Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create OVAL macro to consistently identify Interactive Users #10215

Merged

Conversation

marcusburghardt
Copy link
Member

@marcusburghardt marcusburghardt commented Feb 16, 2023

Description:

Currently, there are 14 rules checking for requirements related to "interactive users":

  1. accounts_umask_interactive_users
  2. accounts_user_dot_user_ownership
  3. accounts_user_dot_group_ownership
  4. accounts_user_dot_no_world_writable_programs
  5. accounts_user_interactive_home_directory_defined
  6. accounts_user_interactive_home_directory_exists
  7. accounts_users_home_files_groupownership
  8. accounts_users_home_files_ownership
  9. accounts_users_home_files_permissions
  10. file_groupownership_home_directories
  11. file_ownership_home_directories
  12. file_permissions_home_directories
  13. file_permissions_home_dirs
  14. no_forward_files

For all these rules, the approach to identify interactive users is exactly the same.
However, each rule had its own OVAL check.

Besides the code duplication, during the review of these rules it was also noticed other minor issues:

  • Some rules consider the nobody user while others not.
  • Some rules ignore users based on a user list while other not.
  • Some rules were filtering interactive users by their gids while the uids should be used instead.
  • Some rules were using hard-coded uids or gids instead of products variables.

These issues prove how difficult is to keep consistency among these rules.
The maintenance is also expensive considering 14 rules.

Recently, after some discussions in CIS Community, after checking related requirements in existing benchmarks, like STIG and CIS, and also after offline conversations with experts, it was agreed that users configured with /sbin/nologin shell should also be ignored in the "Interactive Users" list.

This change inevitably would demand OVAL update in the 14 mentioned rules.
It was a great opportunity to improve the consistency of these rules, reduce maintenance cost and make it easier to introduce new similar rules.

So, in this PR I have created a OVAL macro to properly and consistently identify "Interactive Users" and provide a OVAL object to be used in the rules. Once the macro was created, the OVAL for these all 14 rules was updated to use the new macro and a new test scenario was included to cover the case of non-system accounts that has /sbin/nologin shell.

The minor issues mentioned before were also fixed.

Rationale:

  • Maintenance cost reduced
  • Stronger consistency
  • Simplification

Review Hints:

Although I identified improvement opportunities also in remediation, I decided to limit the scope of this PR to OVAL updates and minor fixes in remediation. It makes the PR easier to review and test since the changes are more controlled.

For review, check commit by commit in the order they are presented.
For test, I would recommend to use a loop for testing these 14 rules using automatus. Here is a simple example that can be used as reference:

for rule in accounts_umask_interactive_users accounts_user_dot_group_ownership accounts_user_dot_user_ownership accounts_user_dot_no_world_writable_programs accounts_user_interactive_home_directory_defined accounts_user_interactive_home_directory_exists accounts_users_home_files_groupownership accounts_users_home_files_ownership accounts_users_home_files_permissions file_groupownership_home_directories file_ownership_home_directories file_permissions_home_directories file_permissions_home_dirs no_forward_files; do
  for os in rhel9 rhel8 rhel7; do
    for flavor in bash ansible; do
      echo "`date` - $os - $rule - $flavor VM"
      ./tests/automatus.py rule --libvirt qemu:///session $os --datastream build/ssg-$os-ds.xml --dontclean --remediate-using $flavor $rule
    done
  done
done

As a follow-up, something similar should be done with the remediation.

@marcusburghardt marcusburghardt added enhancement General enhancements to the project. OVAL OVAL update. Related to the systems assessments. labels Feb 16, 2023
@marcusburghardt marcusburghardt added this to the 0.1.67 milestone Feb 16, 2023
@github-actions
Copy link

Start a new ephemeral environment with changes proposed in this pull request:

rhel8 (from CTF) Environment (using Fedora as testing environment)
Open in Gitpod

Fedora Testing Environment
Open in Gitpod

Oracle Linux 8 Environment
Open in Gitpod

@github-actions
Copy link

This datastream diff is auto generated by the check Compare DS/Generate Diff

Click here to see the full diff
New content has different text for rule 'xccdf_org.ssgproject.content_rule_accounts_user_dot_group_ownership'.
--- xccdf_org.ssgproject.content_rule_accounts_user_dot_group_ownership
+++ xccdf_org.ssgproject.content_rule_accounts_user_dot_group_ownership
@@ -1,6 +1,6 @@
 
 [title]:
-User Initialization Files Must Be Group-Owned By The Primary User
+User Initialization Files Must Be Group-Owned By The Primary Group
 
 [description]:
 Change the group owner of interactive users files to the group found

bash remediation for rule 'xccdf_org.ssgproject.content_rule_accounts_user_dot_group_ownership' differs.
--- xccdf_org.ssgproject.content_rule_accounts_user_dot_group_ownership
+++ xccdf_org.ssgproject.content_rule_accounts_user_dot_group_ownership
@@ -1,2 +1,2 @@
 
-awk -F':' '{ if ($3 >= 1000 && $3 != 65534) system("chgrp -f " $3" "$6"/.[^\.]?*") }' /etc/passwd
+awk -F':' '{ if ($3 >= 1000 && $3 != 65534) system("chgrp -f " $4" "$6"/.[^\.]?*") }' /etc/passwd

ansible remediation for rule 'xccdf_org.ssgproject.content_rule_accounts_user_dot_group_ownership' differs.
--- xccdf_org.ssgproject.content_rule_accounts_user_dot_group_ownership
+++ xccdf_org.ssgproject.content_rule_accounts_user_dot_group_ownership
@@ -1,7 +1,7 @@
 - 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 " $3" "$6"/.[^\.]?*")
+ cmd: awk -F':' '{ if ($3 >= 1000 && $3 != 65534) system("chgrp -f " $4" "$6"/.[^\.]?*")
 }' /etc/passwd
 tags:
 - accounts_user_dot_group_ownership

New content has different text for rule 'xccdf_org.ssgproject.content_rule_accounts_users_home_files_groupownership'.
--- xccdf_org.ssgproject.content_rule_accounts_users_home_files_groupownership
+++ xccdf_org.ssgproject.content_rule_accounts_users_home_files_groupownership
@@ -1,6 +1,6 @@
 
 [title]:
-All User Files and Directories In The Home Directory Must Be Group-Owned By The Primary User
+All User Files and Directories In The Home Directory Must Be Group-Owned By The Primary Group
 
 [description]:
 Change the group of a local interactive users files and directories to a

bash remediation for rule 'xccdf_org.ssgproject.content_rule_accounts_users_home_files_groupownership' differs.
--- xccdf_org.ssgproject.content_rule_accounts_users_home_files_groupownership
+++ xccdf_org.ssgproject.content_rule_accounts_users_home_files_groupownership
@@ -1,5 +1,5 @@
 
-for user in $(awk -F':' '{ if ($4 >= 1000 && $4 != 65534) print $1 }' /etc/passwd); do
+for user in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534) 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

ansible remediation for rule 'xccdf_org.ssgproject.content_rule_accounts_users_home_files_groupownership' differs.
--- xccdf_org.ssgproject.content_rule_accounts_users_home_files_groupownership
+++ xccdf_org.ssgproject.content_rule_accounts_users_home_files_groupownership
@@ -25,15 +25,15 @@
 - no_reboot_needed
 - restrict_strategy
 
-- name: Test for existence home directories to avoid creating them, but only fixing
+- 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[2]|int >= 1000
- - item.value[2]|int != 65534
+ - item.value[1]|int >= 1000
+ - item.value[1]|int != 65534
 tags:
 - CCE-86534-5
 - DISA-STIG-RHEL-08-010741

ansible remediation for rule 'xccdf_org.ssgproject.content_rule_accounts_users_home_files_ownership' differs.
--- xccdf_org.ssgproject.content_rule_accounts_users_home_files_ownership
+++ xccdf_org.ssgproject.content_rule_accounts_users_home_files_ownership
@@ -21,7 +21,7 @@
 - no_reboot_needed
 - restrict_strategy
 
-- name: Test for existence home directories to avoid creating them, but only fixing
+- name: Test for existence of home directories to avoid creating them, but only fixing
 ownership
 ansible.builtin.stat:
 path: '{{ item.value[4] }}'

New content has different text for rule 'xccdf_org.ssgproject.content_rule_file_groupownership_home_directories'.
--- xccdf_org.ssgproject.content_rule_file_groupownership_home_directories
+++ xccdf_org.ssgproject.content_rule_file_groupownership_home_directories
@@ -1,6 +1,6 @@
 
 [title]:
-All Interactive User Home Directories Must Be Group-Owned By The Primary User
+All Interactive User Home Directories Must Be Group-Owned By The Primary Group
 
 [description]:
 Change the group owner of interactive users home directory to the

bash remediation for rule 'xccdf_org.ssgproject.content_rule_file_groupownership_home_directories' differs.
--- xccdf_org.ssgproject.content_rule_file_groupownership_home_directories
+++ xccdf_org.ssgproject.content_rule_file_groupownership_home_directories
@@ -1,2 +1,2 @@
 
-awk -F':' '{ if ($4 >= 1000 && $4 != 65534) system("chgrp -f " $4" "$6) }' /etc/passwd
+awk -F':' '{ if ($3 >= 1000 && $3 != 65534) system("chgrp -f " $4" "$6) }' /etc/passwd

ansible remediation for rule 'xccdf_org.ssgproject.content_rule_file_groupownership_home_directories' differs.
--- xccdf_org.ssgproject.content_rule_file_groupownership_home_directories
+++ xccdf_org.ssgproject.content_rule_file_groupownership_home_directories
@@ -32,8 +32,8 @@
 register: path_exists
 loop: '{{ local_users }}'
 when:
- - item.value[2]|int >= 1000
- - item.value[2]|int != 65534
+ - item.value[1]|int >= 1000
+ - item.value[1]|int != 65534
 tags:
 - CCE-83434-1
 - DISA-STIG-RHEL-08-010740

ansible remediation for rule 'xccdf_org.ssgproject.content_rule_file_ownership_home_directories' differs.
--- xccdf_org.ssgproject.content_rule_file_ownership_home_directories
+++ xccdf_org.ssgproject.content_rule_file_ownership_home_directories
@@ -23,7 +23,7 @@
 - no_reboot_needed
 - restrict_strategy
 
-- name: Test for existence home directories to avoid creating them, but only fixing
+- name: Test for existence of home directories to avoid creating them, but only fixing
 ownership
 ansible.builtin.stat:
 path: '{{ item.value[4] }}'

@marcusburghardt
Copy link
Member Author

Automatus CS8 is failing with this message:
ERROR - Rule 'xccdf_org.ssgproject.content_rule_no_forward_files' isn't present in benchmark 'xccdf_org.ssgproject.content_benchmark_RHEL-8' in '/tmp/ssgts-ds-2ej7kupl'

The no_forward_files doesn't have rhel8 in prodtype. I don't know why it was considered in Automatus CS8 test, but it should be fine to waive. This rule will be included for RHEL products in another PR.

Many rules deal with interactive users in a pretty similar way.
It was created a generic macro to be used in these rules in order to
keep the approach consistent among the rules and the maintainability
easier.
There is a new OVAL macro to filter interactive users in a consistent
way among the relevant rules. It was also included a new test scenario
to test the exclusion of users using /sbin/nologin shell.
As a consequence of this improvement, a minor fix was also included in
this commit. The filter for interactive users was checking the
"unix:user_id" field but using "{{{ gid_min }}}" as pattern. The
intention of the object was to collect interactive users and not
interactive groups.
Also improved the existing test scenarios to ensure the expected
permissions are set in the test environment. Comparing to chmod alone
find command can better manage hidden files.
Like the accounts_users_home_files_groupownership rule, this was also
improved with the macro. Before, the interactive users were filtered by
gids while uids is more appropriated.
This commit also created some minor updates in the test scenarios in
order to improve the readability.
This rule is deprecated in favor of file_permissions_home_directories.
However, its OVAL was also updated to keep the approach of collecting
interactive users aligned in all related rules.
@marcusburghardt
Copy link
Member Author

/retest

Copy link
Collaborator

@jan-cerny jan-cerny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this idea very much

Comment on lines +22 to +23
- item.value[1]|int >= {{{ uid_min }}}
- item.value[1]|int != {{{ nobody_uid }}}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

small nit pick: it might be useful for future readers to add a comment about type of data at index 1 (and at index 4 above) in the array

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great point. I wrote this some time ago and when working on this PR, honestly I had to confirm the position of the fields myself. : )) I also intend to open another PR to improve these remediations. But for now, these comments will already come in handy. I will include.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -2,7 +2,7 @@ documentation_complete: true

prodtype: ol7,ol8,rhel7,rhel8,rhv4,sle12,sle15,ubuntu2004,ubuntu2204

title: 'User Initialization Files Must Be Group-Owned By The Primary User'
title: 'User Initialization Files Must Be Group-Owned By The Primary Group'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

item.value[1]|int is used in some Ansible tasks when looping through a
dictionary created from /etc/passwd file. It could not be intuitive the
index and values of the resulting dictionary. It is basically formed by
the fields in /etc/passwd, where the first field is the key and the next
6 fields are in the list of values. Each file line is a item in the
dictionary.
@codeclimate
Copy link

codeclimate bot commented Feb 17, 2023

Code Climate has analyzed commit 97d023a and detected 0 issues on this pull request.

The test coverage on the diff in this pull request is 100.0% (50% is the threshold).

This pull request will bring the total coverage in the repository to 51.7% (0.0% change).

View more on Code Climate.

@marcusburghardt
Copy link
Member Author

/retest

@jan-cerny jan-cerny self-assigned this Feb 20, 2023
Copy link
Collaborator

@jan-cerny jan-cerny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have reviewed the code and I have executed some of the test scenarios

[jcerny@thinkpad scap-security-guide{pr/10215}]$ python3 tests/automatus.py rule --libvirt qemu:///system ssgts_rhel9 accounts_umask_interactive_users
Setting console output to log level INFO
INFO - The base image option has not been specified, choosing libvirt-based test environment.
INFO - Logging into /home/jcerny/work/git/scap-security-guide/logs/rule-custom-2023-02-20-1817/test_suite.log
INFO - xccdf_org.ssgproject.content_rule_accounts_umask_interactive_users
INFO - Script bash_history_ignored.pass.sh using profile (all) OK
INFO - Script hidden_folder_ignored.pass.sh using profile (all) OK
INFO - Script home_dirs_all_absent.pass.sh using profile (all) OK
INFO - Script home_dirs_one_absent.pass.sh using profile (all) OK
INFO - Script interactive_users_absent.pass.sh using profile (all) OK
INFO - Script no_dot_file_ignored.pass.sh using profile (all) OK
INFO - Script umask_defined.fail.sh using profile (all) OK
INFO - Script interactive_user_nologin_ignored.pass.sh using profile (all) OK
[jcerny@thinkpad scap-security-guide{pr/10215}]$ python3 tests/automatus.py rule --libvirt qemu:///system ssgts_rhel9 --remediate-using ansible accounts_umask_interactive_users
Setting console output to log level INFO
INFO - The base image option has not been specified, choosing libvirt-based test environment.
INFO - Logging into /home/jcerny/work/git/scap-security-guide/logs/rule-custom-2023-02-20-1821/test_suite.log
INFO - xccdf_org.ssgproject.content_rule_accounts_umask_interactive_users
INFO - Script bash_history_ignored.pass.sh using profile (all) OK
INFO - Script hidden_folder_ignored.pass.sh using profile (all) OK
INFO - Script home_dirs_all_absent.pass.sh using profile (all) OK
INFO - Script home_dirs_one_absent.pass.sh using profile (all) OK
INFO - Script interactive_users_absent.pass.sh using profile (all) OK
INFO - Script no_dot_file_ignored.pass.sh using profile (all) OK
INFO - Script umask_defined.fail.sh using profile (all) OK
INFO - Script interactive_user_nologin_ignored.pass.sh using profile (all) OK
[jcerny@thinkpad scap-security-guide{pr/10215}]$ python3 tests/automatus.py rule --libvirt qemu:///system ssgts_rhel9 file_permissions_home_directories
Setting console output to log level INFO
INFO - The base image option has not been specified, choosing libvirt-based test environment.
INFO - Logging into /home/jcerny/work/git/scap-security-guide/logs/rule-custom-2023-02-20-1825/test_suite.log
INFO - xccdf_org.ssgproject.content_rule_file_permissions_home_directories
INFO - Script acceptable_permission.pass.sh using profile (all) OK
INFO - Script expected_permissions.pass.sh using profile (all) OK
INFO - Script home_dirs_absent.pass.sh using profile (all) OK
INFO - Script interactive_users_absent.pass.sh using profile (all) OK
INFO - Script lenient_permission.fail.sh using profile (all) OK
INFO - Script special_permissions.fail.sh using profile (all) OK
INFO - Script interactive_user_nologin_ignored.pass.sh using profile (all) OK
[jcerny@thinkpad scap-security-guide{pr/10215}]$ python3 tests/automatus.py rule --libvirt qemu:///system ssgts_rhel9 --remediate-using ansible file_permissions_home_directories
Setting console output to log level INFO
INFO - The base image option has not been specified, choosing libvirt-based test environment.
INFO - Logging into /home/jcerny/work/git/scap-security-guide/logs/rule-custom-2023-02-20-1828/test_suite.log
INFO - xccdf_org.ssgproject.content_rule_file_permissions_home_directories
INFO - Script acceptable_permission.pass.sh using profile (all) OK
INFO - Script expected_permissions.pass.sh using profile (all) OK
INFO - Script home_dirs_absent.pass.sh using profile (all) OK
INFO - Script interactive_users_absent.pass.sh using profile (all) OK
INFO - Script lenient_permission.fail.sh using profile (all) OK
INFO - Script special_permissions.fail.sh using profile (all) OK
INFO - Script interactive_user_nologin_ignored.pass.sh using profile (all) OK

@jan-cerny
Copy link
Collaborator

The error of automatus is expected because some of the rules aren't present in the RHEL 9 data stream

@jan-cerny jan-cerny merged commit 2657bcb into ComplianceAsCode:master Feb 20, 2023
@marcusburghardt marcusburghardt deleted the interactive_users_nologin branch February 21, 2023 08:02
@marcusburghardt marcusburghardt added the Update Rule Issues or pull requests related to Rules updates. label Mar 3, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement General enhancements to the project. OVAL OVAL update. Related to the systems assessments. Update Rule Issues or pull requests related to Rules updates.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants