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

docs: Add example playbook and "readme" for confined users #184

Merged
merged 2 commits into from
Nov 14, 2023
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
61 changes: 61 additions & 0 deletions README-confined_users.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Confined users
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
# Confined users
# Confined users

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed, thank you.


By default linux users are mapped to SELinux user `unconfined_u`, which is subject to minimal restrictions. You can greatly improve security of your systems by confining users, that is by mapping them to SELinux users with less privilege.
`confined_users-playbook.yml` contains an example configuration for confining existing users and creating new ones with varying levels of access.

## Expected functionality

* Set default user mapping
* Confine existing users accounts
* Set booleans to customize access

## Variables

### selinux_booleans
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
### selinux_booleans
### selinux_booleans

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed, thank you.


SELinux policy provides several booleans for customizing access of confined users.

`selinux_booleans` is expected to hold a list of booleans together with their intended value and persistence setting.
Formally it is a `list` of `dict`, where each `dict` is in the same format as used by the
[seboolean](https://docs.ansible.com/ansible/latest/collections/ansible/posix/seboolean_module.html#ansible-collections-ansible-posix-seboolean-module)
module.

```yaml
selinux_booleans:
- {name: 'ssh_sysadm_login', state: 'on', persistent: 'yes'}
- {name: 'user_exec_content', state: 'off', persistent: 'yes'}
```

See
[confined users documentation](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html-single/using_selinux/index#managing-confined-and-unconfined-users_using-selinux)
for a list of relevant booleans.

### existing_privileged_users

Specify a list of existing users to be mapped to `staff_u` and allowed to use `sudo` to perform administrative tasks.

```yaml
existing_privileged_users:
- "Mark"
- "Roger"
```

### selinux_logins

Manage the linux user to SELinux user mapping. This is a `list` of `dict`,
where each `dict` is in the same format as used by the
[selogin](https://docs.ansible.com/ansible/latest/collections/community/general/selogin_module.html)
module.

```yaml
selinux_logins:
- {login: 'plautrba', seuser: 'staff_u', state: 'absent'}
- {login: '__default__', seuser: 'staff_u', serange: 's0-s0:c0.c1023', state: 'present'}
```

`__default__` is the value assigned to a new user when no login mapping is specified for them. All other lines must correspond to existing user accounts. Note that changing a login mapping changes the file context definitions of the user's home directory. This change is applied using `restorecon` at the end of the playbook.

## Examples

Confining users is demonstrated in
[confined_users-playbook.yml](examples/confined_users-playbook.yml) playbook.
126 changes: 126 additions & 0 deletions examples/confined_users-playbook.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
---
- name: Manage SELinux policy example
hosts: all
become: true
vars:
# Use "targeted" SELinux policy type
selinux_policy: targeted
# Set "enforcing" mode
selinux_state: enforcing
# Set SELinux booleans
selinux_booleans:
# Allow ssh logins as sysadm_r:sysadm_t
# - {name: 'ssh_sysadm_login', state: 'on', persistent: 'yes'}
# Allow sysadm_u/staff_u to execute applications in their
# home directories and /tmp
- {name: 'sysadm_exec_content', state: 'on', persistent: 'yes'}
- {name: 'staff_exec_content', state: 'on', persistent: 'yes'}
# But block normal users from the same
- {name: 'user_exec_content', state: 'off', persistent: 'yes'}
# Allow staff user to create and transition to svirt domains
# - {name: 'staff_use_svirt', state: 'on', persistent: 'yes'}
# Allow confined users the ability to execute the ping and traceroute
# - {name: 'selinuxuser_ping', state: 'on', persistent: 'yes'}
# Allow users to connect to the local mysql server
# - {name: 'selinuxuser_mysql_connect_enabled', state: 'on',
# persistent: 'yes'}
# Allow samba and winbind-rpcd to share users home directories
# - {name: 'samba_enable_home_dirs', state: 'on', persistent: 'yes'}
# Disallow programs, such as newrole, from transitioning to administrative
# user domains
# - {name: 'secure_mode', state: 'on', persistent: 'yes'}

# List of existing users to be mapped to staff_u and allowed to use sudo
existing_privileged_users:
- "Lizzy"
- "Tarja"

# The following section specifies mapping of EXISTING system users
# to SELinux users
selinux_logins:
# Map all new users to SElinux user "user_u" (instead of "unconfined_u")
- {login: '__default__', seuser: 'user_u', serange: 's0',
state: 'present'}
# Alternatively map all new users to SElinux user "staff_u" (instead of

Check failure on line 44 in examples/confined_users-playbook.yml

View workflow job for this annotation

GitHub Actions / ansible_lint

yaml[comments-indentation]

Comment not indented like content
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
# Alternatively map all new users to SElinux user "staff_u" (instead of
# Alternatively map all new users to SElinux user "staff_u" (instead of

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I skipped this one since it would indent the comment from the surrounding lines.

Copy link
Contributor

Choose a reason for hiding this comment

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

ok - what do you suggest we do to make yamllint happy?

# "unconfined_u")
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
# "unconfined_u")
# "unconfined_u")

# - {login: '__default__', seuser: 'staff_u', serange: 's0-s0:c0.c1023',
# state: 'present'}
# Map admin users to SElinux user "staff_u"
# Map select non-admin privileged users to SELinux user "staff_u"
# - {login: '<existing_user>', seuser: 'staff_u', serange: 's0',
# state: 'present'}
# - {login: 'Lizzy', seuser: 'staff_u', serange: 's0',
# state: 'present'}

# Prepare the prerequisites required for this playbook
tasks:
# Enable kiosk mode -- add extremely limited users "guest" and "xguest"
# - name: Install xguest package
# yum:
# name: xguest
# state: present

# Create login mappings for "existing_privileged_users"
- name: Build list of selinux logins
set_fact:
selinux_logins: "{{ selinux_logins + login_helper | list }}"
with_items: "{{ existing_privileged_users }}"
vars:
login_helper:
- {login: "{{ item }}", seuser: 'staff_u', serange: 's0',
state: 'present'}

# Users that get assigned a new SELinux user need to have their homedirs
# relabeled.
# Gather homedirs of each user with a new login mapping
- name: Gather homedirs of users with new login mapping

Check failure on line 76 in examples/confined_users-playbook.yml

View workflow job for this annotation

GitHub Actions / ansible_lint

risky-shell-pipe

Shells that use pipes should set the pipefail option.
shell: >-
# exit in case of errors in the following command ("-o pipefail"
# cannot be used since "getent passwd __default__" is expected to fail)
set -eu;
getent passwd "{{ item.login }}" | awk -F: '{ print $6 }'
register: __login_homedirs
with_items: "{{ selinux_logins }}"
changed_when: false

# Relabel the gathered homedirs using "selinux_restore_dirs" variable
- name: Relabel homedirs of users with new login mapping
set_fact:
selinux_restore_dirs: "{{ selinux_restore_dirs | default([])
+ [item.stdout] }}"
when: item.stdout != ""
with_items: "{{ __login_homedirs.results if __login_homedirs.results is
iterable else [] }}"

# Allow existing_privileged_users to use sudo
- name: Allow privileged users to use sudo
copy:
dest: /etc/sudoers.d/{{ item }}
content: "{{ item }} ALL=(ALL) TYPE=sysadm_t ROLE=sysadm_r ALL"
mode: "0640"
loop: "{{ existing_privileged_users | list }}"

# Run selinux role to apply changes described in "vars" section
- name: Execute the role and catch errors
block:
- name: Include selinux role
include_role:
name: linux-system-roles.selinux
rescue:
# Fail if failed for a different reason than selinux_reboot_required.
- name: Handle errors
fail:
msg: "role failed"
when: not selinux_reboot_required

- name: Restart managed host
reboot:

- name: Wait for managed host to come back
wait_for_connection:
delay: 10
timeout: 300
Copy link
Contributor

Choose a reason for hiding this comment

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

why so long? Is this because selinux has to do some sort of filesystem-wide restorecon?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is just copied from the first example.


- name: Reapply the role
include_role:
name: linux-system-roles.selinux
28 changes: 14 additions & 14 deletions tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,20 +84,6 @@
ignore_selinux_state: "{{ ansible_selinux.status == 'disabled' }}"
with_items: "{{ selinux_fcontexts }}"

- name: Restore SELinux labels on filesystem tree
command: /sbin/restorecon -R -F -v {{ restorecon_threads }} {{ item }}
with_items: "{{ selinux_restore_dirs }}"
register: restorecon_cmd
changed_when: '"Relabeled" in restorecon_cmd.stdout'

- name: Restore SELinux labels on filesystem tree in check mode
command: /sbin/restorecon -R -F -v -n {{ restorecon_threads }} {{ item }}
with_items: "{{ selinux_restore_dirs }}"
register: restorecon_cmd
changed_when: '"Would relabel" in restorecon_cmd.stdout'
check_mode: false
when: ansible_check_mode

- name: Set an SELinux label on a port
local_seport:
ports: "{{ item.ports }}"
Expand Down Expand Up @@ -133,3 +119,17 @@
checksum: "{{ selinux_installed_modules[mod_name][priority]['checksum'] | default('sha256:') }}"
when: selinux_modules is defined
loop: "{{ selinux_modules | flatten(levels=1) }}"

- name: Restore SELinux labels on filesystem tree
command: /sbin/restorecon -R -F -v {{ restorecon_threads }} {{ item }}
with_items: "{{ selinux_restore_dirs }}"
register: restorecon_cmd
changed_when: '"Relabeled" in restorecon_cmd.stdout'

- name: Restore SELinux labels on filesystem tree in check mode
command: /sbin/restorecon -R -F -v -n {{ restorecon_threads }} {{ item }}
with_items: "{{ selinux_restore_dirs }}"
register: restorecon_cmd
changed_when: '"Would relabel" in restorecon_cmd.stdout'
check_mode: false
when: ansible_check_mode
Loading