Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions docs/manual/developer_guide.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1600,11 +1600,14 @@ audit_rules_usergroup_modification::
** *path* - path that should be part of the audit rule as a value of `-w` argument, eg. `/etc/group`.
* Languages: Ansible, Bash, OVAL

bls_bootloader_option::
* Checks kernel command line arguments in BLS-compatible (Boot Loader Specification) boot loader configuration.
argument_value_in_line::
* Checks that `argument=value` pair is present in (optionally) the line started with line_prefix (and, optionally, ending with line_suffix) in the file(s) defined by filepath.
* Parameters:
** *arg_name* - argument name, eg. `audit`
** *arg_value* - argument value, eg. `'1'`
** *filepath* - File(s) to be checked. The value would be treated as a regular expression pattern.
** *arg_name* - Argument name, eg. `audit`
** *arg_value* - Argument value, eg. `'1'`
** *line_prefix* - The prefix of the line in which argument-value pair should be present, optional.
** *line_suffix* - The suffix of the line in which argument-value pair should be present, optional.
* Languages: OVAL

file_groupowner::
Expand Down Expand Up @@ -1812,8 +1815,6 @@ an OVAL template file called _template_OVAL_package_installed_:
</def-group>
----

Notice that you can use Jinja macros and Jinja filters in the template code.

And here is the Ansible template file called _template_ANSIBLE_package_installed_:

----
Expand Down Expand Up @@ -1887,6 +1888,18 @@ def mount_option(data, lang):
return data
----

==== Filters

You can use Jinja macros and Jinja filters in the template code. ComplianceAsCode support all built-in Jinja link:https://jinja.palletsprojects.com/en/2.11.x/templates/#builtin-filters[filters].

There are also some custom filters useful for content authoring defined in the project:

escape_id::
* Replaces all non-word (regex *\W*) characters with underscore. Useful for sanitizing ID strings as it is compatible with OVAL IDs `oval:[A-Za-z0-9_\-\.]+:ste:[1-9][0-9]*`.

escape_regex::
* Escapes characters in the string for it to be usable as a part of some regular expression, behaves similar to the Python 3's link:https://docs.python.org/3/library/re.html#re.escape[*re.escape*].


=== Tests (ctest)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
{{{ oval_metadata("The grub2 boot loader superuser should have a username that is hard to guess.") }}}

<criteria operator="OR">
{{{ oval_file_absent_criterion("/boot/grub2/grub.cfg", rule_id + "_grub_cfg") }}}
{{{ oval_file_absent_criterion("/boot/grub2/grub.cfg") }}}
<criterion comment="Superuser is defined in /boot/grub2/grub.cfg and it isn't root, admin, or administrator." test_ref="test_bootloader_unique_superuser"/>
</criteria>
</definition>

{{{ oval_file_absent("/boot/grub2/grub.cfg", rule_id + "_grub_cfg") }}}
{{{ oval_file_absent("/boot/grub2/grub.cfg") }}}

<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="superuser is defined in /boot/grub2/grub.cfg files. Superuser is not root, admin, or administrator" id="test_bootloader_unique_superuser" version="1">
<ind:object object_ref="object_bootloader_unique_superuser" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
{{{ oval_metadata("The grub2 boot loader should have password protection enabled.") }}}

<criteria operator="OR">
{{{ oval_file_absent_criterion(grub_cfg_prefix + "/grub.cfg", rule_id + "_grub_cfg") }}}
{{{ oval_file_absent_criterion(grub_cfg_prefix + "/grub.cfg") }}}
<criteria operator="AND">
<criteria comment="check both files to account for procedure change in documenation" operator="OR">
<criterion comment="make sure a password is defined in /boot/grub2/user.cfg" test_ref="test_grub2_password_usercfg" />
Expand All @@ -15,7 +15,7 @@
</criteria>
</definition>

{{{ oval_file_absent(grub_cfg_prefix + "/grub.cfg", rule_id + "_grub_cfg") }}}
{{{ oval_file_absent(grub_cfg_prefix + "/grub.cfg") }}}

<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="superuser is defined in /boot/grub2/grub.cfg files." id="test_bootloader_superuser" version="2">
<ind:object object_ref="object_bootloader_superuser" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
{{{ oval_metadata("The grub2 boot loader superuser should have a username that is hard to guess.") }}}

<criteria operator="OR">
{{{ oval_file_absent_criterion("/boot/efi/EFI/redhat/grub.cfg", rule_id + "_grub_cfg") }}}
{{{ oval_file_absent_criterion("/boot/efi/EFI/redhat/grub.cfg") }}}
<criterion comment="make sure a superuser is defined in /boot/efi/EFI/redhat/grub.cfg" test_ref="test_bootloader_uefi_unique_superuser"/>
</criteria>
</definition>

{{{ oval_file_absent("/boot/efi/EFI/redhat/grub.cfg", rule_id + "_grub_cfg") }}}
{{{ oval_file_absent("/boot/efi/EFI/redhat/grub.cfg") }}}

<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="superuser is defined in /boot/efi/EFI/redhat/grub.cfg. Superuser is not root, admin, or administrator" id="test_bootloader_uefi_unique_superuser" version="1">
<ind:object object_ref="object_bootloader_uefi_unique_superuser" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
{{{ oval_metadata("The UEFI grub2 boot loader should have password protection enabled.") }}}

<criteria operator="OR">
{{{ oval_file_absent_criterion(grub_cfg_prefix + "/grub.cfg", rule_id + "_grub_cfg") }}}
{{{ oval_file_absent_criterion(grub_cfg_prefix + "/grub.cfg") }}}
<criteria operator="AND">
<criteria comment="check both files to account for procedure change in documenation" operator="OR">
<criterion comment="make sure a password is defined in {{{ grub_cfg_prefix }}}/user.cfg" test_ref="test_grub2_uefi_password_usercfg" />
Expand All @@ -20,7 +20,7 @@
</criteria>
</definition>

{{{ oval_file_absent(grub_cfg_prefix + "/grub.cfg", rule_id + "_grub_cfg") }}}
{{{ oval_file_absent(grub_cfg_prefix + "/grub.cfg") }}}

<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="superuser is defined in /boot/efi/EFI/redhat/grub.cfg." id="test_bootloader_uefi_superuser" version="2">
<ind:object object_ref="object_bootloader_uefi_superuser" />
Expand Down
25 changes: 25 additions & 0 deletions shared/macros-bash.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -614,3 +614,28 @@ for f in $( ls /etc/sudoers /etc/sudoers.d/* 2> /dev/null ) ; do
fi
done
{{%- endmacro -%}}

{{% macro bash_sssd_ldap_config(parameter, value) -%}}
SSSD_CONF="/etc/sssd/sssd.conf"
LDAP_REGEX='[[:space:]]*\[domain\/[^]]*]([^(\n)]*(\n)+)+?[[:space:]]*{{{ parameter }}}'
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 {{{ parameter }}} in sssd.conf, if it exists, set to '{{{ value }}}'
# if {{{ parameter }}} 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#{{{ parameter }}}[^(\n)]*#{{{ parameter }}} = {{{ value }}}#" $SSSD_CONF
elif grep -qs $DOMAIN_REGEX $SSSD_CONF; then
sed -i "/$DOMAIN_REGEX/a {{{ parameter }}} = {{{ value }}}" $SSSD_CONF
else
if test -f "$SSSD_CONF"; then
echo -e "[domain/default]\n{{{ parameter }}} = {{{ value }}}" >> $SSSD_CONF
else
echo "Config file '$SSSD_CONF' doesnt exist, not remediating, assuming non-applicability." >&2
fi
fi
fi
{{%- endmacro %}}
104 changes: 71 additions & 33 deletions shared/macros-oval.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,8 @@
- filepath (String): Path to the file to be checked.
- id of the test name - the test will be named test_<id>
#}}
{{%- macro oval_file_absent_criterion(filepath, id) -%}}
<criterion comment="Pass if {{{ filepath }}} does not exist" test_ref="test_{{{ id }}}" />
{{%- macro oval_file_absent_criterion(filepath) -%}}
<criterion comment="Pass if there are no files matching pattern '{{{ filepath }}}' exist in the system" test_ref="test_{{{ rule_id }}}_file_{{{ filepath|escape_id }}}_absent" />
{{%- endmacro %}}

{{#
Expand All @@ -230,12 +230,13 @@
- filepath (String): Path to the configuration file to be checked.
- id of the test name - the test will be named test_<id>, the respective object object_<id> etc.
#}}
{{%- macro oval_file_absent(filepath, id) -%}}
<unix:file_test check="all" check_existence="none_exist" comment="{{{ filepath }}} does not exist" id="test_{{{ id }}}" version="1">
<unix:object object_ref="object_{{{ id }}}" />
{{%- macro oval_file_absent(filepath) -%}}
<unix:file_test check="all" check_existence="none_exist" id="test_{{{ rule_id }}}_file_{{{ filepath|escape_id }}}_absent"
comment="Check if {{{ filepath }}} does not exist" version="1">
<unix:object object_ref="object_{{{ rule_id }}}_file_{{{ filepath|escape_id }}}_absent" />
</unix:file_test>
<unix:file_object id="object_{{{ id }}}" version="1">
<unix:filepath>{{{ filepath }}}</unix:filepath>
<unix:file_object id="object_{{{ rule_id }}}_file_{{{ filepath|escape_id }}}_absent" version="1">
<unix:filepath operation="pattern match">^{{{ filepath }}}</unix:filepath>
</unix:file_object>
{{%- endmacro %}}

Expand All @@ -250,6 +251,69 @@
</unix:file_object>
{{%- endmacro %}}

{{#
Macro to define the OVAL test to check if there is a line in file with a pair of argument=value (Criterion definition).
Parameters:
- filepath (String): Path to the file to be checked.
- name (String): Argument name
- value (String): Argument value
- application (String): The application which the configuration file is being checked. Can be any value and does not affect the actual OVAL check.
#}}
{{%- macro oval_argument_value_in_line_criterion(filepath, name, value, application='') -%}}
{{%- set name_value = name+"="+value -%}}
<criterion comment="Check if argument {{{ name_value }}}{{% if application %}} for {{{ application }}}{{% endif %}} is present in {{{ filepath }}}"
test_ref="test_{{{ rule_id }}}_{{{ name_value|escape_id }}}_argument_in_{{{ filepath|escape_id }}}"/>
{{%- endmacro -%}}

{{#
Macro to define the OVAL test to check if there is a line in file with a pair of argument=value (Test definition).
Parameters:
- filepath (String): Path to the configuration file to be checked. The operation is "pattern match"
- name (String): Argument name
- value (String): Argument value
- line_prefix (String): The starting part of the line with the list of arguments, default is empty
- line_suffix (String): The ending part of the line with the list of arguments, default is empty
#}}
{{%- macro oval_argument_value_in_line_test(filepath, name, value, line_prefix='', line_suffix='') -%}}
{{%- set name_value = name+"="+value -%}}
<ind:textfilecontent54_test id="test_{{{ rule_id }}}_{{{ name_value|escape_id }}}_argument_in_{{{ filepath|escape_id }}}"
comment="Check if argument {{{ name_value }}} is present{{% if line_prefix %}} in the line starting with '{{{ line_prefix }}}'{{% endif %}} in {{{ filepath }}}"
check="all" check_existence="all_exist" version="1">
<ind:object object_ref="object_{{{ rule_id }}}_{{{ name_value|escape_id }}}_argument_in_{{{ filepath|escape_id }}}" />
<ind:state state_ref="state_{{{ rule_id }}}_{{{ name_value|escape_id }}}_argument_in_{{{ filepath|escape_id }}}" />
</ind:textfilecontent54_test>
<ind:textfilecontent54_object id="object_{{{ rule_id }}}_{{{ name_value|escape_id }}}_argument_in_{{{ filepath|escape_id }}}" version="1">
<ind:filepath operation="pattern match">^{{{ filepath }}}</ind:filepath>
<ind:pattern operation="pattern match">^{{{ line_prefix|escape_regex }}}(.*){{{ line_suffix|escape_regex }}}$</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_state id="state_{{{ rule_id }}}_{{{ name_value|escape_id }}}_argument_in_{{{ filepath|escape_id }}}" version="1">
<ind:subexpression datatype="string" operation="pattern match">^(?:.*\s)?{{{ name_value|escape_regex }}}(?:\s.*)?$</ind:subexpression>
</ind:textfilecontent54_state>
{{%- endmacro -%}}

{{#
Hight level macro to define the OVAL test to check if there is a line in file with a pair of argument=value.
Parameters:
- filepath (String): Path to the configuration file to be checked.
- name (String): Argument name
- value (String): Argument value
- line_prefix (String): The starting part of the line with the list of arguments, default is empty
- line_suffix (String): The ending part of the line with the list of arguments, default is empty
- application (String): The application which the configuration file is being checked. Can be any value and does not affect the actual OVAL check.
#}}
{{%- macro oval_argument_value_in_line(filepath, name, value, line_prefix='', line_suffix='') -%}}
<def-group>
<definition class="compliance" id="{{{ rule_id }}}" version="2">
{{{ oval_metadata("Ensure argument " + name + "=" + value + " is present"+ (" in the line starting with '" + line_prefix + "'" if line_prefix else "") + " in file(s) '" + filepath + "'") }}}
<criteria operator="AND">
{{{- oval_argument_value_in_line_criterion(filepath, name, value, application) }}}
</criteria>
</definition>
{{{- oval_argument_value_in_line_test(filepath, name, value, line_prefix, line_suffix) }}}
</def-group>
{{%- endmacro -%}}

{{#
High level macro to check if a particular combination of parameter and value in the ssh daemon configuration file is set.
This macro can take five parameters:
Expand Down Expand Up @@ -534,29 +598,3 @@
<description>{{{ description }}}</description>
</metadata>
{{%- endmacro %}}


{{% macro bash_sssd_ldap_config(parameter, value) -%}}
SSSD_CONF="/etc/sssd/sssd.conf"
LDAP_REGEX='[[:space:]]*\[domain\/[^]]*]([^(\n)]*(\n)+)+?[[:space:]]*{{{ parameter }}}'
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 {{{ parameter }}} in sssd.conf, if it exists, set to '{{{ value }}}'
# if {{{ parameter }}} 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#{{{ parameter }}}[^(\n)]*#{{{ parameter }}} = {{{ value }}}#" $SSSD_CONF
elif grep -qs $DOMAIN_REGEX $SSSD_CONF; then
sed -i "/$DOMAIN_REGEX/a {{{ parameter }}} = {{{ value }}}" $SSSD_CONF
else
if test -f "$SSSD_CONF"; then
echo -e "[domain/default]\n{{{ parameter }}} = {{{ value }}}" >> $SSSD_CONF
else
echo "Config file '$SSSD_CONF' doesnt exist, not remediating, assuming non-applicability." >&2
fi
fi
fi
{{%- endmacro %}}
20 changes: 10 additions & 10 deletions shared/templates/template_ANSIBLE_zipl_bls_entries_option
Original file line number Diff line number Diff line change
Expand Up @@ -4,49 +4,49 @@
# complexity = medium
# disruption = low

- name: "Ensure BLS boot entries options contain {{{ ARG_NAME_VALUE }}}"
- name: "Ensure BLS boot entries options contain {{{ ARG_NAME }}}={{{ ARG_VALUE }}}"
block:
- name: "Check how many boot entries exist "
find:
paths: "/boot/loader/entries/"
patterns: "*.conf"
register: n_entries

- name: "Check how many boot entries set {{{ ARG_NAME_VALUE }}}"
- name: "Check how many boot entries set {{{ ARG_NAME }}}={{{ ARG_VALUE }}}"
find:
paths: "/boot/loader/entries/"
contains: "^options .*{{{ ARG_NAME_VALUE }}}.*$"
contains: "^options .*{{{ ARG_NAME }}}={{{ ARG_VALUE }}}.*$"
patterns: "*.conf"
register: n_entries_options

- name: "Update boot entries options"
command: grubby --update-kernel=ALL --args="{{{ ARG_NAME_VALUE }}}"
command: grubby --update-kernel=ALL --args="{{{ ARG_NAME }}}={{{ ARG_VALUE }}}"
when: n_entries is defined and n_entries_options is defined and n_entries.matched != n_entries_options.matched

- name: "Check if /etc/kernel/cmdline exists"
stat:
path: /etc/kernel/cmdline
register: cmdline_stat

- name: "Check if /etc/kernel/cmdline contains {{{ ARG_NAME_VALUE }}}"
- name: "Check if /etc/kernel/cmdline contains {{{ ARG_NAME }}}={{{ ARG_VALUE }}}"
find:
paths: "/etc/kernel/"
patterns: "cmdline"
contains: "^.*{{{ ARG_NAME_VALUE }}}.*$"
contains: "^.*{{{ ARG_NAME }}}={{{ ARG_VALUE }}}.*$"
register: cmdline_find

- name: "Add /etc/kernel/cmdline contains {{{ ARG_NAME_VALUE }}}"
- name: "Add /etc/kernel/cmdline contains {{{ ARG_NAME }}}={{{ ARG_VALUE }}}"
lineinfile:
create: yes
path: "/etc/kernel/cmdline"
line: '{{{ ARG_NAME_VALUE }}}'
line: '{{{ ARG_NAME }}}={{{ ARG_VALUE }}}'
when: cmdline_stat is defined and not cmdline_stat.stat.exists

- name: "Append /etc/kernel/cmdline contains {{{ ARG_NAME_VALUE }}}"
- name: "Append /etc/kernel/cmdline contains {{{ ARG_NAME }}}={{{ ARG_VALUE }}}"
lineinfile:
path: "/etc/kernel/cmdline"
backrefs: yes
regexp: "^(.*)$"
line: '\1 {{{ ARG_NAME_VALUE }}}'
line: '\1 {{{ ARG_NAME }}}={{{ ARG_VALUE }}}'
when: cmdline_stat is defined and cmdline_stat.stat.exists and cmdline_find is defined and cmdline_find.matched == 0

8 changes: 4 additions & 4 deletions shared/templates/template_BASH_zipl_bls_entries_option
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# platform = Red Hat Enterprise Linux 8

# Correct BLS option using grubby, which is a thin wrapper around BLS operations
grubby --update-kernel=ALL --args="{{{ ARG_NAME_VALUE }}}"
grubby --update-kernel=ALL --args="{{{ ARG_NAME }}}={{{ ARG_VALUE }}}"

# Ensure new kernels and boot entries retain the boot option
if [ ! -f /etc/kernel/cmdline ]; then
echo "{{{ ARG_NAME_VALUE }}}" >> /etc/kernel/cmdline
elif ! grep -q '^(.*\s)?{{{ ARG_NAME_VALUE }}}(\s.*)?$' /etc/kernel/cmdline; then
sed -Ei 's/^(.*)$/\1 {{{ ARG_NAME_VALUE }}}/' /etc/kernel/cmdline
echo "{{{ ARG_NAME }}}={{{ ARG_VALUE }}}" > /etc/kernel/cmdline
elif ! grep -q '^(.*\s)?{{{ ARG_NAME }}}={{{ ARG_VALUE }}}(\s.*)?$' /etc/kernel/cmdline; then
sed -Ei 's/^(.*)$/\1 {{{ ARG_NAME }}}={{{ ARG_VALUE }}}/' /etc/kernel/cmdline
fi
9 changes: 9 additions & 0 deletions shared/templates/template_OVAL_argument_in_file
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{{{
oval_argument_value_in_line(
filepath=FILEPATH,
name=ARG_NAME,
value=ARG_VALUE,
line_prefix=LINE_PREFIX,
line_suffix=LINE_SUFFIX
)
}}}
Loading