Centrally manage SELinux user mapping with (Free)IPA

SELinux LogoSELinux allows to confine users with SELinux user mappings. This article covers some basics about the confinement of users and shows how to manage them in central way with the help of (Free)IPA. It will greatly enhance your systems security.

SELinux is available and enabled on all Red Hat based distributions such as RHEL, CentOS and Fedora. for the basics please have a look at article. Before proceeding with the examples in this article:

  • ensure your system is running in enforcing mode otherwise you will experience strange results with the sysadm_r role when logging in.
  • temporary enable root login via SSH or have access to the systems console, used for debugging

Helpful packages

It is recommended to install a few packages to manage SELinux.

# yum -y install libselinux-python policycoreutils-python policycoreutils-devel policycoreutils-newrole setools-console

The basics

By default, every user is mapped to the SELinux user unconfined_u as you can proof with semanage login -l

rhel7:~# semanage login -l

Login Name           SELinux User         MLS/MCS Range        Service

__default__          unconfined_u         s0-s0:c0.c1023       *
root                 unconfined_u         s0-s0:c0.c1023       *
system_u             system_u             s0-s0:c0.c1023       *

Overview about standard SELinux users and roles

The following SELinux users are predefined with the standard policy:

User Role Domain su/sudo Exec * X11 Networking
sysadm_u sysadm_r sysadm_t sudo, su yes yes yes
staff_u staff_r staff_t sudo yes yes yes
user_u user_r user_t yes yes yes
guest_u guest_r guest_t no no no
xguest_u xguest_r xguest_t no yes yes, http(s) only

* Execution of scripts and binaries in /home and /tmp

Role transition

This is important to understand. Which users or which roles are allowed to switch the role?

seinfo is your friend…

seinfo -xu
[..some output ommited...]
      default level: s0
      range: s0 - s0:c0.c1023
[..some output ommited...]

This means that a Linux user mapped to staff_u can switch the role to sysadm_r, but not to guest_r.

Allowed target types

How do I figure out what is allowed to do for a certain role? Again, seinfo is your friend:

root@server ~]# seinfo -rsysadm_r -x      
      Dominated Roles:
[.. lots of output ommited ..]

Note: There must be no space between r and sysadm_r, the parameter is really rsysadm_r.

There you can see every target type the role sysadm_r is allowed to access, it is a lot. Of course this looks different for each role, have a look at them.

Implementation with IPA

Change the default SELinux usermap order

In this example we will map the sysadmins group to the sysadm_r role. The SELinux user for this role, sysadm_u is not defined in the IPA configuration. Lets change that.

ipa config-mod --ipaselinuxusermaporder='guest_u:s0$xguest_u:s0$user_u:s0$staff_u:s0-s0:c0.c1023$sysadm_u:s0-s0:c0.c1023$unconfined_u:s0-s0:c0.c1023'

To ensure non-mapped users are confined, create a default mapping:

ipa config-mod --ipaselinuxusermapdefault='user_u:s0'

Create users, groups and add members

echo Welcome123|ipa user-add --first=Luc --last="de Louw" --password luc
echo Welcome123|ipa user-add --first=Luc --last="de Louw" --password ldelouw
echo Welcome123|ipa user-add --first=Joe --last=Doe --password jdoe
echo Welcome123|ipa user-add --first=Guest --last=User --password guest

ipa group-add sysadmins
ipa group-add-member sysadmins --users=luc

ipa group-add staff
ipa group-add-member staff --users=ldelouw

ipa group-add users
ipa group-add-member users --users=jdoe

ipa group-add guests
ipa group-add-member guests --users=guest

The password of the users will immediately expire and need to be changed on the first login. Please log in with every user and change the password before proceeding.

Adding some HBAC rules

In this example I’ll make user of a host group testservers. Please create that and add one or more of your hosts to that group first.

ipa hbacrule-add sysadmins-allhosts --hostcat=all --servicecat=all
ipa hbacrule-add-user --groups=sysadmins sysadmins-allhosts

ipa hbacrule-add staff-testservers --servicecat=all
ipa hbacrule-add-user --groups=staff staff-testservers
ipa hbacrule-add-host --hostgroup=testservers staff-testservers

ipa hbacrule-add users-testservers --servicecat=all
ipa hbacrule-add-user --groups=users users-testservers
ipa hbacrule-add-host --hostgroup=testservers users-testservers

ipa hbacrule-add guests-testservers --servicecat=all
ipa hbacrule-add-user --groups=guests guests-testservers
ipa hbacrule-add-host --hostgroup=testservers guests-testservers

This creates four HBAC rules. The first allows everyone in the sysadmins group to log in to all hosts, the others restrict its users to the hostgroup testservers.

Create SELinux maps

ipa selinuxusermap-add --selinuxuser='sysadm_u:s0-s0:c0.c1023' --hbacrule=sysadmins-allhosts sysadmins
ipa selinuxusermap-add --selinuxuser='staff_u:s0-s0:c0.c1023' --hbacrule=staff-testservers staff
ipa selinuxusermap-add --selinuxuser='user_u:s0' --hbacrule=users-testservers users
ipa selinuxusermap-add --selinuxuser='guest_u:s0' --hbacrule=guests-testservers guests

In this example, I use HBAC rules for the mapping. This is recommended practice because the HBAC rules are the central point to manage user access rules.

However, you also can assign users (and groups of them), hosts (and groups of them) to a SELinux map, i.e. with ipa selinuxusermap-add-host –hostgroups=testservers semapname and ipa selinuxusermap-add-user –groups=users semapname. For single user or hosts it is the parameter –hosts or –users.


Note that roles like user_r and lower can not do sudo to other users (incl. root). guest_r does even not allow to use the network. Please have a look at the table above.

Lets create the sudoers rules for the groups staff and sysadmins.

ipa sudocmd-add "/bin/bash"
ipa sudorule-add --hostcat=all --runasusercat=all --runasgroupcat=all sysadmins-can-sudo-i
ipa sudorule-add-user --group=sysadmins sysadmins-can-sudo-i
ipa sudorule-add-allow-command --sudocmds=/bin/bash sysadmins-can-sudo-i
ipa sudorule-add-option --sudooption='!authenticate' sysadmins-can-sudo-i
ipa sudorule-add-option --sudooption='type=sysadm_t' sysadmins-can-sudo-i
ipa sudorule-add-option --sudooption='role=sysadm_r' sysadmins-can-sudo-i

ipa sudorule-add --runasusercat=all --runasgroupcat=all staff-can-sudo-i
ipa sudorule-add-user --group=staff staff-can-sudo-i
ipa sudorule-add-host --hostgroups=testservers staff-can-sudo-i
ipa sudorule-add-allow-command --sudocmds=/bin/bash staff-can-sudo-i
ipa sudorule-add-option --sudooption='!authenticate' staff-can-sudo-i
ipa sudorule-add-option --sudooption='type=sysadm_t' staff-can-sudo-i
ipa sudorule-add-option --sudooption='role=sysadm_r' staff-can-sudo-i

Switching roles

Switching roles can be done in three different ways:

  • Using the newrole command when already logged in with the default role
  • Provide the role when logging in with ssh
  • Using sudo, please see above

If you are already logged in, you can switch the role with the newrole command.

[ldelouw@server ~]$ newrole -r sysadm_r

The output if id -Z shows that you are now mapped to the same SELinux user staff_u but in the role of sysadm_r


Most of the time you will know what you gonna do on a target system. You can provide the role as a parameter to ssh:

[luc@client ~]$ ssh ldelouw/unconfined_r@server.example.com
ldelouw@server.example.com's password:
Last login: Sun Jun 24 11:29:54 2018 from client.example.com
Kickstarted on 2018-01-16
[ldelouw@server ~]$ id -Z
[ldelouw@server ~]$

This example allows you to use the unconfined_r role instead of the default defined in the SELinux user map (staff_r).

Be aware that this is by default not possible with the sysadm_r role, as logging in with that role is turned off.


sysadm_u can not log in

By default a user with the role of sysadm_r is not allowed to log in via ssh, only console logins are allowed.

To change this for testing, set the following boolean:

# setsebool ssh_sysadm_login on

Use the -P parameter to make the change persistent:

# setsebool -P ssh_sysadm_login on

User mapped to sysadm_u can login but is not supposed to do so

If you can log in into a host as a user mapped to sysadm_u, and id shows the following obviously wrong SELinux user role and domain:

[luc@server ~]$ id
uid=594600001(luc) gid=594600001(luc) groups=594600001(luc),594600005(sysadmins)  context=system_u:system_r:unconfined_t:s0-s0:c0.c1023

Then probably the ssh_sysadm_login boolean is set to false and your system runs in permissive mode.

Sudo to root fails with permission denied to .bash_profile

[ldelouw@server ~]$ sudo -i
-bash: /root/.bash_profile: Permission denied

You dont have the role sysadm_r, this is why access to files owned by root are denied. Please have a look at the sudo configuration as described in this article.

Sudo trows errors

[ldelouw@server ~]$ sudo -i
sudo: sudoRole sudo_root_admins: unknown defaults entry "TYPE"
sudo: sudoRole sudo_root_admins: unknown defaults entry "ROLE"
-bash: /root/.bash_profile: Permission denied

There is a difference between using traditional /etc/sudoers files and IPA. The man sudoers reads SELinux_Spec ::= (‘ROLE=role’ | ‘TYPE=type’) which is correct for file based configuration but wrong for IPA.

All sudoers options defined in IPA must be lowercase to get recognized in the correct way.

Changes in IPA are not working on the clients

This is can be a caching problem.

sss_cache -E

This wipes everything in the sssd cache. Sometimes sudoers will still not be working, it is safe to remove the whole SSSD database and restart sssd.

rm -rf /var/lib/sss/db/*
systemctl restart sssd

Read further

There are tons of documentation available. Lets list the most notable.

Getting help

If you run into problems, there are different sources for getting help

Secure your system with SELinux

SELinux Logo

SELinux Logo

Introduction to SELinux

SELinux is well known as the most sophisticated Linux Mandatory Access Control (MAC) System. If you install any Fedora or Redhat operating System it is enabled by default and running in enforcing mode. So far so good.

Its available for many years and its not rocket science to use it. This article is supposed to give you some hints how to make your system even more secure and how to solve some troubles SELinux may have on your system.


Linux and traditional Unix systems are using DAC (Discretionary Access Control). Every user can change access rights to its own files. SELinux is a MAC (Mandatory Access Control) System where access rights are ruled by system wide policies. This can cause confusion when access is denied to a resource. Be aware that DAC will kick in before SELinux policies do. So if access to a resource is denied, please check access rights first. In such a case you will not see any AVC denials in your logs. The return code (EACCES) is the same.


There is plenty of information available in the man pages. Some of the configuration file examples also contains additional information.

server:~# man -k selinux

Gives a good overview

Stick to Standards

Sofware installed from a RHEL or Fedora repository is usually not a problem at all, as long as you are using standards for config files, data, ports etc. Stick to the standards wherever possible. I.e. It does not make any sense to store websites in /opt instead of /var/www/html

Standards do not work for you?

If you can not stick to the standards for whatever reason, you can adjust a lot of settings with semanage.

Adding an allowed TCP Port for Apache

If you want to run your Apache httpd on port 8010, Apache will not start and a SELinux AVC denial is filed. To check which ports are allowed for Apache run:

server:~# semanage port -l|grep http_port_t
http_port_t                    tcp      80, 81, 443, 488, 8008, 8009, 8443, 9000

There is nothing like 8010

You can simply add port 8010 to the allowed ports by running

server:~# semanage port -a -t http_port_t 8010 -p tcp

Check again:

server:~# semanage port -l|grep http_port_t
http_port_t                    tcp      8010, 80, 81, 443, 488, 8008, 8009, 8443, 9000


Using a non-standard location for HTML files

Lets assume you want to store your HTML files in /opt/srv. To do so, you need to change the file context of that path and restore the file context afterwards.

server:~# semanage fcontext -a -t httpd_sys_rw_content_t '/opt/srv(/.*)?'
server:~# restorecon -R -v /opt/srv

Make use of Boolean variables

There are plenty of bool variables which simple allows to turn on or off a particular protection.

To get a list of defined bools, run

server:~# getsebool -a

You may want to pipe it to less or grep for a search pattern.

As an example, the default behavior is that a web application running in the httpd_t context will not be allowed to send emails. That helps greatly to prevent a vulnerable web application to send out SPAM. Well, if you want to operate a web mail service Apache must be able to send emails. No big deal:

server:~# setsebool -P httpd_can_sendmail on


The are some CLI (and GUI) tools available to troubleshoot AVC denials. The most important is sealert. Here is an example of an AVC because of a mislabled file in /var/www/html

sealert -a /var/log/audit/audit.log
SELinux is preventing /usr/sbin/httpd from getattr access on the file /var/www/html/test.html
*****  Plugin restorecon (99.5 confidence) suggests   ************************
If you want to fix the label. 
/var/www/html/test.html default label should be
Then you can run restorecon.
# /sbin/restorecon -v /var/www/html/test.html

As you can see, sealert already provides you a hint how to fix the problem. In more complex cases, audit2why and audit2allow will help you. You simply grep for the misbehaving process:

server:~# grep httpd /var/log/audit/audit.log |audit2allow -m my_local_module

Review the result to check if it makes sense (ensure your grep statement does not catch too much). If you’re confident its okay, run the same command again with a capital M as parameter. It will create you a Local Policy Module which can be inserted:

server:~# grep httpd /var/log/audit/audit.log |audit2allow -M my_local_module
server:~# semodule -i my_local_module.pp

Temporary mitigation of SELinux troubles

If sealert and audit2allow can not immediately solve your problems and you quickly need to get your service up and running again, temporary put your system in permissive mode.

server:~# setenforce permissive

It will stay in pemissive mode until you reboot your system.

Permissive mode does not enforce the SELinux policies, it just logs AVC denials and help you to solve the problems without any service interruption. Be aware: This is a temporary quick fix, not a solution.

Put the affected domain only into permissive mode

If all your investigation did not help, all answers from support did not helped (very unlikely) you can put a particular domain into permissive mode. The rest of the policies are still in enforcing mode, your system still have some protection.

As an example, you can put the Apache module into permissive mode:

server:~# semanage permissive -a http_t

Hardening your System

Most people are not aware of the fact that when a system is in enforcing mode a malicious user with root access can manipulate policies or put SELinux into permissive mode.

There is a method to prevent this: Lock down your system

server:~# setsebool -P secure_mode_policyload on

Be aware: Once active nothing can not be changed during runtime, you need to reboot your system and provide selinux=1 enforcing=0 as grub boot parameter to be able to change any SELinux settings.

Have some fun!

Download “The SELinux Coloring Book” and learn more 🙂

Further reading

Have fun 🙂