I’ve been really excited about the potential of Red Hat Enterprise Linux 6 (RHEL6/CentOS6) and the beta has not let me down.
Most of the more prominent features are laid out at the Redhat website but one of the things it neglects to mention is how much more access control it comes with.
Role Based Access Controls (RBAC) offer a system or security administrator a means to define a role of some sort. In our example below we’ll be using a web admin role.
Since Fedora 9, the SELinux maintainers for Redhat have pulled out all the stops to properly deploy a framework for SELinux that is more flexible than what you see with EL5. The problem with EL5’s SELinux policy is that although it works, it really does not scratch the surface of how powerful SELinux really is. RBAC simply is not implemented. This means that delegation of trust and enforcement of a corporate security policy is difficult.
Normal access controls are fraught with problems of trust. To make somebody a true webadmin in traditional Linux systems requires a lot of effort:
To manage this level of access on a traditional system would be nigh on impossible. You might be able to get a lot of it done through the use of file ACLs and sudo but it would be a nightmare to manage and make sure not to permit too much or too little access.
EL6 dips more than just its toe into the water of SELinux and with it comes a more flexible implementation of role based access control that is worthy of consideration.
Normally one needs to be able to define what the limits of the role are in order to implement it. But the SELinux policy in EL6 already comes with predefined roles, such as web admin which can be implemented without too much trouble.
I am going to demonstrate how to do the above in a secure way which gives a system administrator the confidence to delegate trust.
For starters you’ll need either an Fedora 12 box or EL6 Beta. Once here we can prepare our system to do this in a few relatively simple steps.
Firstly, we’ll add the user onto the system as a web administrator.
[root@krbsrv ~]# useradd webadministrator [root@krbsrv ~]# passwd webadministrator Changing password for user webadministrator. New password: Retype new password: passwd: all authentication tokens updated successfully.
Next, we’ll create an SELinux User and assign our UID to use it.
[root@krbsrv ~]# semanage user -a -R "staff_r system_r webadm_r" -L s0 -r s0 webadm_u [root@krbsrv ~]# semanage login -a -r s0 -L s0 -s webadm_u webadministrator
Line 1 creates the webadm_u SELinux user (this is distinctly different from a UNIX user account) which is mapped to roles it can be part of.
What we have done is assigned it to the staff, system and webadm roles. ‘Staff’ is a restricted account which can su and sudo which is what we’re going to need to permit, the system role is used here because its needed to run init scripts (to start/stop httpd), and finally our webadm role is the actual primary role of this user. It’s not possible to map the webadm role directly and only to this user because webadm_r doesnt actually have enough privileges to get it to login via SSH. So instead we use the loginable staff role and transition to the webadm role when we want to do work. The -l and -r are sensitivities. This isnt used in SELinux but its mandatory to pass something to it.
Line 2 maps the actual UNIX user webadministrator to the SELinux user webadm_u, so when the user logs in this will be their identifiable user.
Now we have done this theres still a few more steps left yet.
We have listed 3 roles the SELinux user webadm_u can transition into. But, how do we know which one to transition into by default? Well – the answer to this is the folder: /etc/selinux/targeted/contexts/users. This folder contains a list of SELinux users you already have. If you open the file staff_u file you’ll see something like this:
system_r:local_login_t:s0 staff_r:staff_t:s0 sysadm_r:sysadm_t:s0 system_r:remote_login_t:s0 staff_r:staff_t:s0 system_r:sshd_t:s0 staff_r:staff_t:s0 sysadm_r:sysadm_t:s0 system_r:crond_t:s0 staff_r:staff_t:s0 system_r:xdm_t:s0 staff_r:staff_t:s0 staff_r:staff_su_t:s0 staff_r:staff_t:s0 staff_r:staff_sudo_t:s0 staff_r:staff_t:s0 system_r:initrc_su_t:s0 staff_r:staff_t:s0 staff_r:staff_t:s0 staff_r:staff_t:s0 sysadm_r:sysadm_su_t:s0 sysadm_r:sysadm_t:s0 sysadm_r:sysadm_sudo_t:s0 sysadm_r:sysadm_t:s0
This file is a two columned list of which role/types to map to users depending on how they enter the system. So for example the type “local_login_t” represents accessing from a console directly whereas the type “sshd_t” represents logging in via SSH. To the right of these entries is a left-to-right priority list of what contexts the staff_u user ends up getting when they login. Its not important to know all about how this works. All we really need to do is copy this file and name it webadm_u in the same directory.
[root@krbsrv ~]# cp /etc/selinux/targeted/contexts/users/staff_u \ /etc/selinux/targeted/contexts/user/webadm_u
OK so now we have initialized our webadm_u user for logging in. But theres one final task..
The UNIX user webadministrator cant do some of the things it needs to to properly function – such as restart the httpd service or change file ownerships/permissions when necessary. To do this webadm must become root. Becoming root means nothing to SELinux. It will enforce its policy all the same, so even as root webadministrator is restricted purely to the role that is needed. Thus we can safely do this without compromizing our system. We use sudo to do this which takes special tags we use to transition to our webadm role automatically so the user doesnt need to worry about the selinux particulars:
[root@krbsrv ~]# echo 'web_admin ALL=(ALL) TYPE=webadm_t ROLE=webadm_r ALL' >> /etc/sudoers
This means that when the webadministrator runs sudo it will automatically transition into the webadm_t type and webadm_r role.
Great, now we’ve fixed up our user lets test him out!
[root@krbsrv ~]# ssh email@example.com firstname.lastname@example.org's password: Last login: Wed Aug 11 22:55:45 2010 from 192.168.122.1 [webadministrator@krbsrv ~]$ id -Z webadm_u:staff_r:staff_t:s0 [webadministrator@krbsrv ~]$ sudo -s [root@krbsrv ~]# id -Z webadm_u:webadm_r:webadm_t:s0
So, we login via SSH as per the norm. When we login we check our ID (getting SELinux context). You can see we have logged in with webadm_u as the user but staff_r as the role and staff_t as the type. We can’t do much to our web content in this role and we’re also not root. When we sudo what happens is sudo auto-transitions the user into the webadm_r role and webadm_t type – just what the doctor ordered.
This role runs a very restricted set of actions it can take. Lets see what we can do…
We should be able to change the apache configuration and restart the service:
[root@krbsrv ~]# echo "# Add a comment to this file" >> /etc/httpd/conf/httpd.conf [root@krbsrv ~]# /etc/init.d/httpd restart Stopping httpd: [ OK ] Starting httpd: [ OK ]
However we can’t restart other services:
[root@krbsrv ~]# /etc/init.d/sshd restart bash: /etc/init.d/sshd: Permission denied
We can read, create and modify files in the document root:
[root@krbsrv ~]# cd /var/www/html [root@krbsrv html]# touch new_file.txt [root@krbsrv html]# rm new_file.txt
However we can’t modified files outside this:
[root@krbsrv ~]# echo "Port 20000" >> /etc/ssh/sshd_config bash: /etc/ssh/sshd_config: Permission denied [root@krbsrv ~]# cat /etc/shadow cat: /etc/shadow: Permission denied
So, here we are. As you can see, in the webadm role we can restart httpd (which webadministrator needs to do), write to our configuration files and alter our webcontent. However we can’t change anything outside of our remit or attempt to perform anything nefarious – all despite the fact we are root!
Practically speaking, the SELinux policy that comes with EL6 is meant to be a framework, not really a turn-key solution to just fit in with your current system. mAs such webadm as a role itself needs tweaking.
For starters, in the webadm role you can’t read your own home directory which is a little impractical. But also you can’t manage the php.ini or any session files created within php.ini. Therefore I’ve tweaked the policy and added the ability for webadm to be able to test websites from within the role, resolve DNS name entries and also allow SSL certificates to be written in the appropriate places. I decided not to permit webadministrator to be able to use FTP to download files directory in the webadm role. If he wants to do this however he can use the non-root login (using the staff role) to download to his home directory and then copy it accross in the webadm role afterwards. I have supplied the policy I wrote as an idea of how you would do this (download here: mywebadm).
It should be worth nothing that nearly every SELinux policy needs fine-tuning to suit your needs. One size definitely does not fit all. SELinux policy however gives you the specific tools you need to build a working, guaranteed access policy meaning you can delegate system administrator work without giving away root privileges and assign the specialists in their fields the power they need to do their work and no more.
I’m a bit of a fan of what SELinux is and does and I thought it was a shame that Redhat failed to mention the amount of effort and progress gone into the policy EL6 ships with. In the real world managing security threats outside and inside your network is a high priority. EL6 finally gives Linux the power to do this.
At least control groups gets a mention. But thats a story for another time…