Hands-On Labs Of the System Admin and Developer Community of OTN
In this lab we we take quick tour of some of Oracle Solaris security features that can help you to protect your applications and your system. We will look at the following technologies:
For lab exercises 3 and 4, apache 2.2 is required.
To install apache 2.2 on Solaris 11;
apache-22
.Expected duration: 20 minutes
The goal of this exercise is to gain a basic understanding of the RBAC/privileges framework in Solaris.
Thanks Joerg Moellenkamp and his post on Less known Solaris features: RBAC and Privileges - Part 1: Introduction for the following introduction.
And then there was root
. And root
was almighty. And that wasn't a good thing. root
was able to control the world without any control. And root
needed control. It was only a short chant between the mere mortals and root
. Everybody with the knowledge of the magic chant was able to speak through root
.
But root
wasn't alone. root
had servants called daemons. Some of one them needed divine powers to do their daily job. But root
was an undividable being. So the servants had to work with the powers of root
. But the servants were not as perfect as root: Some of the servants started to do everything mere mortals said to them if they only said more than a certain amount of prayers at once.
The old model of rights in a Unix systems is based on a duality. There is the superuser and the normal user. The normal users have a restricted set of rights in the system, the superuser has an unrestricted set of rights. To modify the system, a normal user has to login as root
directly or assume the rights of root (by su -
). But such a user has unrestricted access to the system. Often this isn't desirable. Why should you enable an operator to modify a system, when all he or she has do to on the system is create some users from time to time. You've trained them to do useradd
or passwd
. What do you do when they get too curious? They need root
privileges to create a user or change a password. You need some mechanisms to limit this operator.
But it gets more problematic. Programs have to modify the system to work. A web server is a good example. You expect it to use port 80, ports beneath port number 1024 are privileged ports. You need special rights to modify the structures of the system to listen to port 80. A normal user doesn't have these rights. So the web server has to be started as root. The children of this process drop the rights of root by running with a normal user. But there is this single instance of the program with all the rights of the user. This process has much more rights than needed, a possible attack vector for malicious users.
There is a concept in security known as least privilege. You give someone only least amount of privileges, only enough to do the tasks they are assigned. An example of the real world - you won't give the janitor the master key for all the rooms on the campus, when all he has to do is work in Building C. The other way around - there are some trusted people who have access to all rooms in case of an emergency.
You have the same concept in computer security. Everyone should have only the least amount of privileges in the system to do their job. The concept of the superuser doesn't match to this, it's an all or nothing model. You are an ordinary user with basic privileges or you are a user with unrestricted rights. There is nothing in between. This doesn't follow the least privileges model.
Role Based Access Control (RBAC)
The example with the key for the janitors is a good example. Let's imagine a large campus. You have janitors responsible for the plumbing (let's call them Lenny and Carl), for the park (let's call him Homer), for the security system (let's call her Marge and Lenny helps from time to time).
These roles have different sets of privileges: For example the plumbing janitors have access to all the rooms of the heating system. The janitor for the park has only access to the garage with the lawnmower.
When they start to work in their job, they assume a role. From the privilege perspective it's not important who is the person, but what role the person has assumed. Lenny punches the clock and assumes the role of the plumbing janitor for the next 8 hours. And while he is doing its job he uses the privileges inherent to the role. But he also has to do tasks in his office or in his workshop. It's his own room, so he doesn't need the special privileges.
Role Based Access Control is quite similar. You login to the system, and then you start to work. You read your emails (no special privileges needed), you find an email "Create user xy45345. Your Boss". Okay, now you need special privileges. You assume the role of a User Administrator and create the user. Job done, you don´t need the privileges anymore. You leave the role and write the "Job done" mail to your boss with your normal user's privileges.
Role Based Access Control is all about this: Defining roles, giving them privileges and assigning users to this roles.
I've used the word quite often in this introduction so far. What is a privilege? A privilege is the right to do something. For example, having the keys for the control panel of the heating system.
Unix users are nothing different. Every user has privileges in a Unix system. A normal user has the privilege to open, close, read, write and delete files when he is allowed to do this (Because he created it, because he belongs to the same group as the creater of the file or the creator gave everybody the right to do it). This looks normal to you, but it's privilege based on the login credentials you gave to system. You don't have the privilege to read all files on the system or to use a port number 1024.
Every thing done in the system is based on these privileges. Solaris has separated the tasks into many privilege sets. At the moment, there are 70 different privileges in the system. The difference between the normal user is that the users have only a basic set, while root
has all.
In Solaris the model has changed, privileges and users aren't connected with each other. You can give any user the power of the traditional “root userâ€, and restrict the privileges of the root user. Solaris is configured to look as a traditional super user model due to our binary compatibility guarantee that mandates that the standard configuration of the system resembles the superuser model. There are application out there, which assume that only the root
user or the UID 0 as unrestricted rights and exit when they are started with a different user.
The only thing that is special with UID 0 in Solaris is that it's the owner of the system configuration files, and thus has the capability to change system configurations.
RBAC and Privileges in Solaris
Both features have their root in the Trusted Solaris product. Trusted Solaris was a version of Solaris to ensure the highest security standards. Today, these mechanisms are part of the normal Solaris in conjunction with the Trusted Extensions. So RBAC is a really old feature - it has been in Solaris since Solaris 8 (published in 2000). Privileges found their way into the generic Solaris with the first availability of Solaris 10 in February 2005.
Lets start with some basic concepts for RBAC:
reboot
as root
.solaris.device.cdrw authorization
. This authorization enables users to read and write to a CD-ROM device.Lets take a closer look at RBAC and roles:
Open a terminal window by right clicking any point in the background of the desktop, and select Open +T+erminal in the pop-up menu.
Lets look at what roles are assigned to our Oracle
user. In a terminal, do as follows:
oracle@solaris:~$ roles
root
As you can see here you should be assigned the role root
, it allows us to assume the root
role. In Solaris 11 root is not a user but rather a role. So you have to login to the system as a normal user and then assume the root
role with the su
command.
In a terminal window type as follows:
oracle@solaris:~$ userattr type root
role
oracle@solaris:~$ auths root
solaris.*
As you can see here root
is defined as a role with all solaris authorizations, the effect of this is similar to the old almighty root user. This is put in place for backwards compatibility.
And as your user is assigned the root
role, you can try this by assuming the root
role:
oracle@solaris:~$ whoami
oracle
oracle@solaris:~$ su
Password: <root password>
oracle@solaris:~# whoami
root
oracle@solaris:~# who am I
oracle pts/1 Apr 21 07:32 (:0.0)
oracle@solaris:~# exit
exit
oracle@solaris:~$
Lets add a new user, Joe Doe to our system:
oracle@solaris:~$ useradd -d /export/home/jdoe -m -s /bin/ksh -c "Joe Doe" jdoe
UX: useradd: ERROR: Permission denied.
As you can see here we are not allowed to use the useradd
command. We will have to use su
to execute useradd
with "root" privileges, and assign missing rights to our account. The su
command will prompt you for the root password.
oracle@solaris:~$ su root -c "usermod -K profiles='User Management' oracle"
Password: <your root password>
oracle@solaris:~$ userattr profiles oracle
User Management
As you can see, we now have the right to manage users. To take advantage of this right, we will invoke a profile shell, e.g. pfbash
, and create the new user, jdoe.
oracle@solaris:~$ pfbash
oracle@solaris:~$ useradd -d /export/home/jdoe -g oinstall -m -s /bin/ksh -c "Joe Doe" jdoe
To change the user's password we have to have User Security profile assigned, but it is not advised to assign it to a regular user because it allows the user to change passwords of other users, including more powerful ones. User Management profile is safe, because you can only delegate what you already have. Therefore, let's change the password of the new user using root role:
oracle@solaris:~$ su root -c passwd jdoe
Password: <root password>
New Password: abc123
Re-enter new Password: abc123
passwd: password successfully changed for jdoe
oracle@solaris:~$ su - jdoe
Password: abc123
Oracle Corporation SunOS 5.11 11.0 November 2011
jdoe@solaris:/export/home/jdoe$ roles
No roles
jdoe@solaris:/export/home/jdoe$ su root
Password: <root password>
Roles can only be assumed by authorized users
su: Sorry
jdoe@solaris:/export/home/jdoe$ exit
oracle@solaris:~$
Note: -g oinstall option is submitted to the useradd command. It is necessary to add it because oracle user is in oinstall group by default in this lab setup. Default group in Oracle Solaris 11 is staff. Therefore, if you do not explicitly require to add the user to oinstall group with -g oinstall, useradd will try to add the new user to staff group. You are not allowed to do it as user oracle, because a user with "User Management" profile is allowed to add a new user just to a group which he/she already belongs to.
NEW in Role Authentication in Solaris 11
Role Authentication procedure has changed in Solaris 11. Running earlier Solaris version, including Oracle Solaris 11 Express, user had to know role password in order to assume the role. Oracle Solaris 11 includes the ability to specify whether to use the role password or user password when a user wants to assume a given role. Administrators can specify either 'user' or 'role' for the 'roleauth' keyword. If roleauth is not specified, 'role' is implied. Any newly created roles will be 'user' by default.
As you can see here jdoe
doesn't have any roles assigned to him and he can't use su
to assume the root
role. We'll get back to him later. Now let's move on to a closer look at privileges in Exercise 2.
Expected duration: 20 minutes
The goal of this exercise is to understand Solaris privileges and how to use them
What are Privileges? Privileges are rights to do an operation in the kernel. These rights are enforced by the kernel. Whenever you do something within the kernel the access is controlled by privileges.
contract_event, contract_identity, contract_observer, cpc_cpu, dtrace_kernel, dtrace_proc, dtrace_user, file_chown, file_chown_self, file_dac_execute, file_dac_read, file_dac_search, file_dac_write, file_downgrade_sl, file_flag_set, file_link_any, file_owner, file_setid, file_upgrade_sl, graphics_access, graphics_map, ipc_dac_read, ipc_dac_write, ipc_owner, net_access, net_bindmlp, net_icmpaccess, net_mac_aware, net_mac_implicit, net_observability, net_privaddr, net_rawaccess, proc_audit, proc_chroot, proc_clock_highres, proc_exec, proc_fork, proc_info, proc_lock_memory, proc_owner, proc_priocntl, proc_session, proc_setid, proc_taskid, proc_zone, sys_acct, sys_admin, sys_audit, sys_config, sys_devices, sys_ipc_config, sys_linkdir, sys_mount, sys_iptun_config, sys_dl_config, sys_ip_config, sys_net_config, sys_nfs, sys_ppp_config, sys_res_config, sys_resource, sys_smb, sys_suser_compat, sys_time, sys_trans_label, virt_manage, win_colormap, win_config, win_dac_read, win_dac_write, win_devices, win_dga, win_downgrade_sl, win_fontpath, win_mac_read, win_mac_write, win_selection, win_upgrade_sl, xvm_control
Legend: blue - basic privilege
On conventional Unix systems you have a root
user and they have all privileges. And you have a normal user, who has only a limited set of privileges. Sometimes you need the rights of an admin to do some tasks. You don´t even need to administer the system.
oracle@solaris:~$ ls -l /usr/sbin/traceroute
-r-sr-xr-x 1 root bin 46868 2010-11-05 08:02 /usr/sbin/traceroute
oracle@solaris:~$ ls -l /usr/sbin/ping
-r-sr-xr-x 1 root bin 55940 2010-11-05 08:01 /usr/sbin/ping
You can use traceroute
and ping
because both tools are setuid
tools. setuid
allows a process to run with a specific userid and all the privileges that comes with that user. In the case of setuid
to root the process would have root's privileges. A setuid
program in Solaris can be privilege-aware and hence only retain the privileges needed for the operation.
You need a special privilege to ping
- the privilege to use access ICMP. On conventional systems this right is reserved for the root
user. Thus the ping
program has to be executed with the rights of root
. The problem: At the time of the execution of the program, the program has all the rights of the user. Not only to access ICMP, but the program is capable of doing everything on the system, such as deleting files in /etc
. This may not a problem with ping
or traceroute
but think about larger programs. An exploit in a setuid
program can lead to the escalation of the user's privileges.
Let's have a look at the privileges of an ordinary user. There is a tool to get the privileges of any given process in the system, it's called ppriv
. $$
is a shortcut for the actual process id (in this case the process id of the shell):
oracle@solaris:~$ ppriv $$
1684: -bash
flags = <none>
E: basic
I: basic
P: basic
L: all
What does "basic" mean, we can add -v
to the ppriv
flag to expand the aliases:
oracle@solaris:~$ ppriv -v $$
1684: -bash
flags = <none>
E: file_link_any,file_read,file_write,net_access,proc_exec,proc_fork,proc_info,proc_session
I: file_link_any,file_read,file_write,net_access,proc_exec,proc_fork,proc_info,proc_session
P: file_link_any,file_read,file_write,net_access,proc_exec,proc_fork,proc_info,proc_session
L: contract_event,contract_identity,contract_observer,cpc_cpu,dtrace_kernel,dtrace_proc,dtrace_user,file_chown,
file_chown_self,file_dac_execute,file_dac_read,file_dac_search,file_dac_write,file_downgrade_sl,file_flag_set,
file_link_any,file_owner,file_read,file_setid,file_upgrade_sl,file_write,graphics_access,graphics_map,ipc_dac_read,
ipc_dac_write,ipc_owner,net_access,net_bindmlp,net_icmpaccess,net_mac_aware,net_mac_implicit,net_observability,
net_privaddr,net_rawaccess,proc_audit,proc_chroot,proc_clock_highres,proc_exec,proc_fork,proc_info,proc_lock_memory,
proc_owner,proc_priocntl,proc_session,proc_setid,proc_taskid,proc_zone,sys_acct,sys_admin,sys_audit,sys_config,
sys_devices,sys_dl_config,sys_ip_config,sys_ipc_config,sys_iptun_config,sys_linkdir,sys_mount,sys_net_config,sys_nfs,
sys_ppp_config,sys_res_bind,sys_res_config,sys_resource,sys_smb,sys_suser_compat,sys_time,sys_trans_label,
virt_manage,win_colormap,win_config,win_dac_read,win_dac_write,win_devices,win_dga,win_downgrade_sl,win_fontpath,
win_mac_read,win_mac_write,win_selection,win_upgrade_sl,xvm_control
Every process in the system has four sets of privileges that determine if a process is enabled to use a privilege or not. The theory of privileges is quite complex. I would suggest to read the chapter How Privileges Are Implemented" in the Developers Guide to Oracle Solaris Security to learn how each set controls or is controlled other privilege sets.
At this time, I want only to explain the meaning of the first letter:
You can think about the privilege sets as keyrings. The effective privilege set are the keys the janitor has on its keyring. The permitted privilege set are the keys the janitor is allowed to put on its keyring. The janitor can decide to remove some of the keys. Perhaps he thinks: I work only in room 232 today, I don´t need all the other keys. I'll leave them in my office. When he looses his keyring he lost only the control of this single room, not about the complete campus.
The inheritable privilege set is not a really a keyring. The janitor thinks about his new assistant: "Good worker, but I will not give him my key for the room with the expensive tools." The limited privilege set is the overarching order from the boss of janitor to his team leaders: "You are allowed to give your assistant the keys for normal rooms, but not for the rooms with all this blinking boxes from Oracle".
At the moment the most interesting set is the E:. This is the effective set of privileges. This is the set of privilege effectively available to process. Compared to the full list of privileges mentioned above the set is much smaller. But this matches your experience when you use a Unix system.
Lets see how it looks when we assume the root role:
oracle@solaris:~$ su -
Password: <root password>
Oracle Corporation SunOS 5.11 11.0 November 2011
You have new mail.
root@solaris:~# ppriv $$
1779: -bash
flags = <none>
E: all
I: basic
P: all
L: all
This role has much more privileges. The effective set is much broader. When we assume the root role we assume all privileges in the system. NOTE: This is strictly to provide backwards compatibility and is not the recommended usage going forward.
Lets add some privileges to our jdoe
user, let's assume that he is a software developer that needs access to DTrace to debug some applications.
First lets try to use DTrace as jdoe:
# su - jdoe
Password: abc123
Oracle Corporation SunOS 5.11 11.0 November 2011
jdoe@solaris:/export/home/jdoe$ ppriv $$
1790: -ksh
flags = <none>
E: basic
I: basic
P: basic
L: all
jdoe@solaris:/export/home/jdoe$ dtrace -l
dtrace: failed to initialize dtrace: DTrace requires additional privileges
As we can see here jdoe
is missing some privileges to be allowed to use DTrace. There are have 3 privileges needed for DTrace: dtrace_kernel, dtrace_proc, dtrace_user
, depending on what the user needs to use DTrace for. We can add these privileges to the user in three different ways
dtrace
command and the needed privileges, and assign the profile to the user. This would allow him or her to use a profile shell (f.e., pfbash
) to execute the dtrace
command.Lets see how how to add dtrace privileges directly to the user (run first command as root, then exit root shell and continue as oracle user):
# usermod -K defaultpriv=basic,dtrace_kernel,dtrace_proc,dtrace_user jdoe
oracle@solaris:~$ userattr defaultpriv
basic,dtrace_kernel,dtrace_proc,dtrace_user
Note
You will need to add basic to the set of privileges you assign to the user, without that he would not be able to do the most basic things such as create files, spawn new processes etc.
As you can see, jdoe
now has the three needed privileges to use the dtrace
command, lets give it a try:
oracle@solaris:~$ su - jdoe
Password: abc123
Oracle Corporation SunOS 5.11 11.0 November 2011
jdoe@solaris:/export/home/jdoe$ ppriv $$
1814: -ksh
flags = <none>
E: basic,dtrace_kernel,dtrace_proc,dtrace_user
I: basic,dtrace_kernel,dtrace_proc,dtrace_user
P: basic,dtrace_kernel,dtrace_proc,dtrace_user
L: all
jdoe@solaris:/export/home/jdoe$ dtrace -l | more
ID PROVIDER MODULE FUNCTION NAME
1 dtrace BEGIN
2 dtrace END
3 dtrace ERROR
530 fbt smbsrv smb_match_private entry
...
555 fbt smbsrv smb_gmttoken_xdr return
--More--
OK, so that worked, just for the fun of it lets try to create a role that does the same.
First lets remove the dtrace privileges from jdoe:
oracle@solaris:~$ usermod -K defaultpriv=basic jdoe
oracle@solaris:~$ userattr defaultpriv jdoe
basic
Then lets create our role (using root shell, i.e. as a root user), lets call the role "bugger", and assign it to jdoe
# roleadd -u 201 -d /export/home/bugger -P "Process Management" bugger
oracle@solaris:~$ passwd bugger
New Password: abc123
Re-enter new Password: abc123
passwd: password successfully changed for bugger
oracle@solaris:~$ rolemod -K defaultpriv=basic,dtrace_kernel,dtrace_proc,dtrace_user bugger
oracle@solaris:~$ userattr defaultpriv bugger
basic,dtrace_kernel,dtrace_proc,dtrace_user
oracle@solaris:~$ usermod -R bugger jdoe
oracle@solaris:~$ roles jdoe
bugger
OK, lets try and see if jdoe
now can use DTrace
oracle@solaris:~$ su - jdoe
Password:
Oracle Corporation SunOS 5.11 11.0 November 2011
jdoe@solaris:/export/home/jdoe$ roles
bugger
jdoe@solaris:/export/home/jdoe$ su bugger
Password:
jdoe@solaris:~$ ppriv $$
1885: sh
flags = PRIV_PFEXEC
E: basic,dtrace_kernel,dtrace_proc,dtrace_user
I: basic,dtrace_kernel,dtrace_proc,dtrace_user
P: basic,dtrace_kernel,dtrace_proc,dtrace_user
L: all
jdoe@solaris:~$ dtrace -l | more
ID PROVIDER MODULE FUNCTION NAME
1 dtrace BEGIN
2 dtrace END
3 dtrace ERROR
530 fbt smbsrv smb_match_private entry
...
555 fbt smbsrv smb_gmttoken_xdr return
--More--
Now you should have a basic understanding about privileges and how you can assign them to users, however wouldn't it be nice if we could do the same to processes? We will look at that in exercise 3.
Expected duration: 10 minutes
We have looked at how you can add privileges to a user, now we'll look at how privileges interact with processes, we will look at both processes that are privilege aware and processes that are non-privilege aware.
The idea of managing the privileges is not limited to users and their shells. In any given system you find dozens of programs running as daemons.
These daemons interact in several ways with the privileges. The best way is "privilege-aware programming". Let's assume you code a daemon for your system. For example: You know that your daemon will never do an exec()
call. So you can safely drop this privilege. The process modifies the permitted privilege set. The process can remove a privilege but not add it. Even when someone is able to access your process, the attacker can't make an exec()
call. The process doesn't even have the privilege to do such a call. And the attacker can't add the privilege again. Several processes and programs in Solaris are already privilege aware. For example the kernel-level cryptographic framework daemon. Let's look at the privileges of the daemon.
In order to observe or manage privileges, a process must itself already have those privileges. Therefore we will assume the root role for the following exercise.
oracle@solaris:~$ su - root
Password: <root password>
oracle@solaris:~# ps -ef | grep "kcfd"
daemon 129 1 0 Apr 04 ? 0:00 /lib/crypto/kcfd
oracle 1902 1684 0 08:19:19 pts/1 0:00 grep kcfd
oracle@solaris:~# ppriv -v 129
129: /lib/crypto/kcfd
flags = PRIV_AWARE
E: file_owner,file_read,file_write,net_access,proc_priocntl,sys_devices
I: none
P: file_owner,file_read,file_write,net_access,proc_priocntl,sys_devices
L: none
This daemon doesn't have even the basic privileges of a regular user. It has the only the bare minimum of privileges to do it's job.
But the world isn't perfect. Not every process is privilege aware. Thus you have to limit the privileges by other mechanisms. The Service Management Facility comes to help.
Let's take the Apache Webserver as an example. The apache web server is not privilege aware. We start the daemon via the Service Management Framework (SMF).
oracle@solaris:~# svcadm -v enable -s apache22
svc:/network/http:apache22 enabled.
OK, now we look at the processes of the Apache daemons.
oracle@solaris:~# ps -ef | grep "apache" | grep -v grep
webservd 1931 1928 0 08:22:59 ? 0:00 /usr/apache2/2.2/bin/httpd -k start
webservd 1934 1928 0 08:22:59 ? 0:00 /usr/apache2/2.2/bin/httpd -k start
webservd 1932 1928 0 08:22:59 ? 0:00 /usr/apache2/2.2/bin/httpd -k start
webservd 1935 1928 0 08:22:59 ? 0:00 /usr/apache2/2.2/bin/httpd -k start
webservd 1933 1928 0 08:22:59 ? 0:00 /usr/apache2/2.2/bin/httpd -k start
root 1928 1 1 08:22:58 ? 0:00 /usr/apache2/2.2/bin/httpd -k start
Six daemons running as webservd, and one running as root.
oracle@solaris:~# ppriv 1928
1928: /usr/apache2/2.2/bin/httpd -k start
flags = <none>
E: all
I: basic
P: all
L: all
As expected for a root process, this process has the complete set of privileges of a root user. Now lets look at one of its children:
oracle@solaris:~# ppriv 1931
1931: /usr/apache2/2.2/bin/httpd -k start
flags = <none>
E: basic
I: basic
P: basic
L: all
Much better ... only basic privileges.
OK, There is a reason for this configuration. On Unix systems, you have two groups of ports. Privileged ones from 1-1023 and unprivileged ones from 1024 up. You can only bind to a privileged port with the privilege to do it. A normal user doesn´t have this privilege, but root has it. And thus there has to be one process running as root. Do you remember the list of privileges for the apache process running at root. The process has all privileges but needs only one of them, that isn't part of the basic privilege set.
Expected duration: 10 minutes
We have now looked at both privilege aware and non-privilege aware processes, now lets look at how we can use SMF to let a user with a limited set of privileges manage a non-privilege aware process and give it the required privileges without using setuid to root.
In order to observe or manage privileges, a process must itself already have those privileges. Therefore we will assume the root role for the following exercise.
How to get rid of the root
apache process
It doesn't to be this way. With Solaris you can give any user or process the privilege to use a privileged port. You don't need the root process anymore.
Let's configure it this way. At first we have to deactivate the running apache from exercise 3:
oracle@solaris:~$ su - root
Password: <root password>
oracle@solaris:~# svcadm -v disable -s apache22
svc:/network/http:apache22 disabled.
We will not be explaining the Service Management Facility here, but you can set certain properties in SMF to control the startup of a service:
1 oracle@solaris:~# svccfg -s apache22
2 svc:/network/http:apache22> setprop start/user = astring: webservd
3 svc:/network/http:apache22> setprop start/group = astring: webservd
4 svc:/network/http:apache22> setprop start/privileges = astring:
5 basic,!proc_session,!proc_info,!file_link_any,net_privaddr
6 svc:/network/http:apache22> setprop start/limit_privileges = astring: :default
7 svc:/network/http:apache22> setprop start/use_profile = boolean: false
8 svc:/network/http:apache22> setprop start/supp_groups = astring: :default
9 svc:/network/http:apache22> setprop start/working_directory = astring: :default
10 svc:/network/http:apache22> setprop start/project = astring: :default
11 svc:/network/http:apache22> setprop start/resource_pool = astring: :default
12 svc:/network/http:apache22> end
Line 2 to 4 are the most interesting ones. Without any changes, the Apache daemon starts as root and forks away processes with the webservd user. But we want to get rid of the root user for this configuration. Thus we start the daemon directly with the webservd user, the same goes for the group id.
Now it gets interesting. Without this line (line 4), the kernel would deny Apache to bind to port 80. webservd is a regular user without the privilege to use a privileged port. The property start/privileges
sets the privileges to start the service. At first, we give the service basic privileges. Then we add the privilege to use a privileged port. The service would start up now.
But wait, we can do more. A webserver shouldn't do any hardlinks. And it doesn't send signals outside it's session. And it doesn't look at processes other than those to which it can send signals. We don´t need these privileges. proc_session, proc_info and file_link_any are part of the basic privilege set. We remove them, by adding a ! in front of the privilege:
oracle@solaris:~# svcadm -v refresh apache22
Password:
Action refresh set for svc:/network/http:apache22.
OK, we have notified SMF of the configuration changes.
Until now, the apache daemon used the root
privileges. Thus the ownership of files and directories were unproblematic. The daemon was able to read and write in any directory or file in the system. As we drop its privilege set by using a regular user, we have to modify the ownership of some files and move some files:
oracle@solaris:~# mkdir -p -m 755 /var/apache2/2.2/run
oracle@solaris:~# chown webservd:webservd /var/apache2/2.2/run
oracle@solaris:~# chown webservd:webservd /var/apache2/2.2/logs/access_log
oracle@solaris:~# chown webservd:webservd /var/apache2/2.2/logs/error_log
Note
While the service no longer runs as root
, there is a trade-off. In the "root
" configuration, logs were owned by root
and could not be modified by "webservd
". In the new model, the web server has fewer privileges but the logs are now owned and writable by "webservd
". This is not good or bad, just a tradeoff.
We need some configuration changes, too. We have to move the LockFile and the PidFile. There wasn't one of the two configuration directives specified earlier, thus we're simply appending them to the end of the configuration file:
oracle@solaris:~# bash -c 'echo LockFile /var/apache2/2.2/logs/accept.lock >> /etc/apache2/2.2/httpd.conf'
oracle@solaris:~# bash -c 'echo PidFile /var/apache2/2.2/run/httpd.pid >> /etc/apache2/2.2/httpd.conf'
OK, everything is in place. Let´s give it a try.
oracle@solaris:~# svcadm -v enable -s apache22
svc:/network/http:apache22 enabled.
Now we check for the running httpd processes:
oracle@solaris:~# ps -ef | grep "httpd" | grep -v "grep"
webservd 2064 2057 0 08:43:24 ? 0:00 /usr/apache2/2.2/bin/httpd -k start
webservd 2061 2057 0 08:43:24 ? 0:00 /usr/apache2/2.2/bin/httpd -k start
webservd 2062 2057 0 08:43:24 ? 0:00 /usr/apache2/2.2/bin/httpd -k start
webservd 2060 2057 0 08:43:24 ? 0:00 /usr/apache2/2.2/bin/httpd -k start
webservd 2063 2057 0 08:43:24 ? 0:00 /usr/apache2/2.2/bin/httpd -k start
webservd 2057 1 1 08:43:23 ? 0:00 /usr/apache2/2.2/bin/httpd -k start
You notice the difference ? There is no httpd running as root. All processes run with the userid webservd. Mission accomplished.
Let´s check the privileges of the processes. At first the one, who ran as root
before:
oracle@solaris:~# ppriv 2057
2057: /usr/apache2/2.2/bin/httpd -k start
flags = <none>
E: basic,!file_link_any,net_privaddr,!proc_info,!proc_session
I: basic,!file_link_any,net_privaddr,!proc_info,!proc_session
P: basic,!file_link_any,net_privaddr,!proc_info,!proc_session
L: all
Only the least privileges to do the job, no root privileges. And even the other processes are more secure now. Before we changed the configuration of the webserver, it had the basic privileges of a regular user. Now we limited even this set.
But we still need to be a privileged user to start apache. Wouldn't it be nice if I could delegate management of “services†to unprivileged users. I can use authorizations to do that, and authorizations is integrated with SMF. There are two authorizations we will need to add to our user to give hi the right to manage the apach22 service. We need a authorization to manage our service as well as a authorization to change the state of our service:
solaris.smf.value.http/apache22
- Gives a user the right to modify the value of a property in the Apache service.solaris.smf.manage.http/apache22
- Gives a user the right to change the state of a the Apache service with svcadm
.Both are needed to change the state of a service, as the state of the service is kept as a property for the service.
oracle@solaris:~# svcprop http:apache22 | grep auth
httpd/value_authorization astring solaris.smf.value.http/apache22
general/action_authorization astring solaris.smf.manage.http/apache22
general/value_authorization astring solaris.smf.value.http/apache22
First we need to add our authorizations to /etc/security/auth_attr
oracle@solaris:~# echo solaris.smf.manage.http:::Mange Apache 2.2:: >> /etc/security/auth_attr
Password: oracle
oracle@solaris:~# echo solaris.smf.value.http:::Mange Apache 2.2:: >> /etc/security/auth_attr
Note
In most SMF manifests one authorization is used for both action_authorization and value_authorization, as they are commonly used together.
Now we can exit the root
role since we are finished manipulating privileges. Lets add those authorizations to our old friend jdoe
.
oracle@solaris:~# exit
oracle@solaris:~$ usermod -A solaris.smf.manage.http/apache22,solaris.smf.value.http/apache22 jdoe
oracle@solaris:~$ userattr auths jdoe
solaris.smf.manage.http/apache22,solaris.smf.value.http/apache22
Lets see if jdoe
can start and stop apache now
oracle@solaris:~$ su - jdoe
Password: abc123
Oracle Corporation SunOS 5.11 11.0 November 2011
jdoe@solaris:/export/home/jdoe$ /usr/sbin/svcadm enable apache22
jdoe@solaris:/export/home/jdoe$ svcs apache22
STATE STIME FMRI
online 8:43:23 svc:/network/http:apache22
jdoe@solaris:/export/home/jdoe$ /usr/sbin/svcadm disable apache22
jdoe@solaris:/export/home/jdoe$ svcs apache22
STATE STIME FMRI
disabled 8:53:37 svc:/network/http:apache22
See that worked fine, so by using SMF we've been able to take a service such as apache, removed it's need to start as root by giving it the privileges it needed and nothing more. We also removed some privileges that apache doesn't need, but a hacker would need to take control of your system.
Add to that we added the right to manage the apache service via SMF to an unprivileged user by giving him the correct authorizations that allows a user to manage that particular service and nothing else, as you can see here.
jdoe@solaris:/export/home/jdoe$ svcs sendmail
STATE STIME FMRI
online 6:48:12 svc:/network/smtp:sendmail
jdoe@solaris:/export/home/jdoe$ svcadm disable sendmail
svcadm: svc:/network/smtp:sendmail: Permission denied.