Getting Started with HP-UX Security Compartments
Phil Day
HP-UX 11iv2 introduced three significant new security features, Role-Based Access Control (RBAC), Fine-Grained Privileges (FGP), and Security Compartments, which together bring security features previously available only in specialized OS releases (such as VirtualVault) into the main release stream. This high-level overview aims to give any reader familiar with HP-UX the knowledge needed to start exploring how to use these products and provides an example of how they can be combined to create a secure application hosting environment.
Role-Based Access Control
Role-Based Access Control (RBAC) provides a framework to describe groups of users that can perform certain functions. The classic example of why this is useful is to break the single root administrator role into a more granular structure, although the same paradigm also applies at the application administration level. It provides two distinct capabilities: an authorization mechanism that describes who can do what, and a privileged command execution environment that uses the authorization system to run commands with elevated privileges.
RBAC Authorization
The authorization mechanism has three entities: users, authorizations (which are arbitrary names), and roles (which map users to authorizations). Users are associated to one or more roles, and roles have one or more authorizations. As shipped, the RBAC product contains authorizations for all of the standard HP-UX system administration functions, and these are named in a consistent dot-separated manner (e.g., hpux.fs.mount). This naming convention makes it possible to group authorizations with wildcards (hpux.fs.*), but it is worth noting that it is just a convention, and authorizations can be any string.
The commands for manipulating the RBAC authorization are:
- Roleadm -- Create/delete Roles and associate Users to Roles.
- Authadm -- Create/delete Authorizations and associate Authorizations to Roles.
The documentation describes these as manipulating the authorization database, which is implemented as four files in /etc/rbac:
- /etc/rbac/roles -- Defines Roles.
- /etc/rbac/user_role -- Maps Roles to Users.
- /etc/rbac/auths -- Defines Authorizations.
- /etc/rbac/role_auth -- Maps Authorizations to Roles.
It's important to understand that the authorization database provides only a lookup mechanism to determine what authorizations a user has, in effect answering the question "Does a user have, via any of their assigned roles, an association to this authorization string?"
Interpreting what can be done as a result of having an authorization is the responsibility of RBAC-aware executables. These interrogate the authorization scheme to check whether the user can perform some function. Over time it is expected that increasing numbers of products and executables will become RBAC-aware, but for now this is limited to some of the executables in the security products. In particular, there are some executables that check for a specific authorization string (which is complied into the executable), and a configurable utility, privrun, which can be configured to associate authorizations to commands.
The separation of authorization mechanism from action is important; for example, it enables the authorization mechanism to be supplemented or even completely replaced by an alternative product to provide a centralized system.
RBAC Command Execution (privrun)
Privrun provides a mechanism to run commands in an environment that has specific security attributes (which the invoking user does not normally have) subject to the appropriate authorization. It may help to think of it as a configurable form of the standard su command or setuid type functionality.
The command privilege database (implemented as the file /etc/rbac/cmd_priv) associates a command line with the authorization required to invoke it and the run time attributes (e.g., user id, additional privileges, and compartment to run in). The commands for manipulating the command privilege database are:
- cmdpriv -- Create/delete entries in the database.
- privrun -- Run a privileged command (subject to having the correct authorization.
RBAC Example
To help understand how these features come together, consider the following example. A system has the Apache Web server installed, and we want to run it on the default http port 80. As this is in the privileged port range, it must execute with an effective uid of 0 in order to bind to this port. Without RBAC we would either have to make the Apache executable setuid to 0 or be a root user to start or stop it. However, users Phil and Boris are our Apache administrators, and we don't trust them to be root users. With RBAC, we can set this up as follows:
1. Create a role for running these operations, WebAdmin:
# roleadm add WebAdmin "Web Administrators"
2. Assign the role to the users Phil and Boris:
# roleadm assign phil WebAdmin
# roleadm assign boris WebAdmin
3. Create authorizations defining the operations, hpux.web.start and hpux.web.stop, which can be run on the object apache:
# authadm add hpux.web.start apache
# authadm add hpux.web.stop apache
4. Assign all authorizations in the hpux.web group.* for the object apache to the role WebAdmin:
# authadm assign WebAdmin "hpux.web.*" apache
5. Create a command privilege that invokes the command /etc/init.d/apache with the required privileges and assign it the authorizations:
# cmdprivadm add cmd="/sbin/sh -c /sbin/init.d/apache start" \
ruid=0 euid=0 op=hpux.web.start object=apache
Phil can then run the command with:
# privrun /sbin/sh -c "/sbin/init.d/apache start"
The entities and relationships created, and the configuration files that contain them, are shown in Figure 1.
Fine-Grained Privileges
The Fine-Grained Privileges feature (FGP) is the most complex of the three. The principle is simple enough; all of the checks in the kernel that used to look for euid=0 before allowing a system call to proceed have been replaced with a check for the possession of a particular privilege. What makes this complex is the number of privileges (there are between 40 and 50 of them) and the manner in which they are set and propagated, which is a combination of process behavior and extended file attributes.
To effectively select the appropriate privileges for an application, we need the specific details of the system calls it will be making, thus putting FGP more in the domain of the application developer than the systems administrator. Backward compatibility with the "root is all you need" approach is provided by some aggregate privilege sets that provide the equivalent of an euid=0 process and only clear privileges for executables that have been marked specifically as privilege aware.
Under FGP, each process has three sets of privileges:
- The Potential set defines the maximum privileges a process can have. Processes can choose to drop privileges from their potential set, but they can only add additional privileges via an exec.
- The Effective set is the one used by the kernel when deciding whether a system call should be allowed to proceed. Privilege-aware processes are expected to manipulate this set so that at any point in time they have only the privileges required.
- The Retained set defines the privileges that will be passed on when launching a new executable via exec.
The effective and retained sets are always some subset of the potential set and are manipulated via the procxsec system call.
So, once a process has its privilege set established, it can control what it uses and what it passes on, but how does it get the potential set in the first place? Well, this is where the extended file attributes come in. Each executable file can have another four sets of privileges associated with it. These attributes, which are set via the setfilexsec command and stored in the file in /etc/priv-apps/all-apps, operate in pairs to define the minimum and maximum values of the potential and retained privilege sets of a process. In each case, they can be used to both add (minimum) and remove (maximum) privileges. The minimum privileges are added to those that the process already has, and the resulting combined set is then limited by the maximum set.
An additional file attribute, the privilege-aware flag, indicates whether the process will manipulate its effective set itself (i.e., if it is privilege aware or not). For privilege-aware applications, the Effective set is initially empty, and the process itself is responsible for adding and removing privileges as required (constrained of course by its potential set). For non-privilege-aware applications, the effective set is initialized to the potential set.
Privileges can be specified as part of the RBAC execution environment, but this is only recommended if the command requires different privileges depending on who is executing it -- in most cases privileges are the same for all users and specified via the extended file attributes.
Security Compartments
The third security feature is called Compartments, and these compartments act like firewalls within the operating system. Every process runs in a compartment and can communicate freely with any other process in the same compartment. However, when it needs to connect to the network, the file system, or a process in another compartment via inter-process communications (IPC), then that action is subject to the compartment rules. These rules provide a mandatory access control (MAC) layer, and they are applied regardless of the effective user id or other authorization attributes; for example, it is possible to block access to a directory from all users including root.
The rules that can be specified for a compartment apply to the file system (per directory), network (per interface, protocol, and port), and inter-process communications (fifos, unix sockets, signals, etc.). The compartments rules can also limit the privileges of processes running in it.
By default, all processes are in the init compartment, which has no additional rules, so compartments can be implemented on a system and applied to only a selected subset of the processes. It is this concept of a default init compartment, in which processes behave as if they were on a non-compartmentalized HP-UX system, that makes the compartments much less disruptive than previous MAC systems, such as Virtual Vault.
So, how does a process get into something other than the default init compartment? Well, there are two primary mechanisms that the systems administrator can control. First, the extended file attributes already described for FGP include a compartment value, which will cause an executable to run in the specified compartment. This can be used, for example, to specify a particular compartment for a user's login shell. Second, privrun can specify a compartment as part of the execution environment. Additionally, and in the domain of application developers, a process with the appropriate privileges can change compartment via the procxsec system call.
All of these mechanisms are subject to one important caveat; if the compartment is declared as sealed, then the process can never change its compartment or start a process in another compartment.
Compartments are enabled via the cmpt_tune command, which requires a reboot. The configurations are defined in *.rules files in the /etc/cmpt directory tree and applied or viewed via the setrules and getrules commands.
Integration and Dependencies
RBAC can be used on its own to provide an authorization and privileged execution environment. On its own, the execution environment can specify the user and group settings, but it is also integrated with FGP and Compartments so that these can also be specified.
FGP depends on RBAC; for example, the privilege administration command setfilexsec requires the user to have certain hpux.security.xsec.filexsec authorizations. This requirement is built into the command, not configured via the RBAC database.
Compartments depend on both FGP and RBAC. FGP introduces some specific privileges for working with compartments, such as the ability to change compartment, which are not part of the root replacement set and must be explicitly manipulated. Additionally, the compartment configuration command setrules requires the user to have certain hpux.security.xsec.secrules authorizations.
Using RBAC and Compartments to Implement a Secure Application Hosting Environment
Consolidating applications onto a single operating system has many benefits in terms of increased utilization and reduced license costs. However, customers are naturally concerned about the resource contention and security impacts of having multiple application data sets available in one place.
Resource contention is handled very effectively on HP-UX by products such as Process Resource Manager (PRM) and Work Load Manager (WLM), which can be used to guarantee the resources available to particular applications in accordance with business policy.
Security isolation is a more problematic area, as the administrators of each application need to be given sufficient access to their applications but must not be able to access the data sets of other applications. While allocating each application a separate user account provides some protection, commercial customers also require mitigation against a rogue administrator or application gaining root privileges.
This example shows how RBAC and compartments can be used to provide this level of isolation and containment. In this example, each application is associated with a user account, and all of its processes run in the context of that user.
There are several application administrators, each of whom has his own login account and is responsible for several applications. In the interest of maintaining an audit trail, all administrators must first login to their own account before using su to switch to the application account (appx).
To begin, we define a compartment for the application to run in by creating a new rules file in /etc/cmpt:
# echo > /etc/cmpt/apps/app1.rules <<EOF
sealed compartment app1_cmpt
{
disallowed privileges none
permission all /data/app1
permission none /data/app2
permission none /data/app3
permission none /etc/cmpt/apps
}
EOF
# setrules
In practice, the compartment rules would also include details of the network connections required by the application.
Check the compartment definition:
# getrules
Compartment Name: app1_cmpt : sealed
Disallowed Privileges: none
File System Rules:
------------------
PERMISSION PATHNAME
read, write, create, unlink /
read, write, create, unlink /data/app1
none /data/app2
none /data/app3
none /etc/cmpt/apps
Note that we have given the compartment full access to its own data area (/data/app1) but blocked it from access to the other apps (/data/app2 & /data/app3). Unfortunately, there is no way to specify these with a wildcard, so each must be explicitly included.
We also block access to the directory where the compartment rules are stored (/etc/cmpt/apps) as this prevents users in this compartment from modifying their own rules.
Next, the compartment is defined as sealed, which means that processes running in this compartment cannot, regardless of privilege, change compartments or start a process in another compartment. This ensures that even if a process (for example a user shell) gains root privileges it cannot override the compartment rules.
We must also create an authorization to cover the ability of users to switch to the application account and compartment.
# authadm add app1.su app1
and a role to link this authorization to the Administrators
(Phil and Boris).
# roleadm add App1Admin "Application 1 Administrator"
# authadm assign App1Admin app1.su
# roleadm assign phil App1Admin
# roleadm assign boris App1Admin
Next, we define a privileged command, which will get us the correct user and compartment context and can be run by any user with the app1.su authorization:
# cmdprivadm add cmd="/usr/bin/su - app1" ruid=0 euid=0 \
op="app1.su" object=app1 compartment=app1_cmpt
Using this configuration, an authorized user can get access to the correct application context as follows:
$(phil) id
uid=114(phil) gid=20(users)
$(phil) getprocxsec
effective= BASIC
permitted= BASIC
retained= BASIC
cmpt= init
euid= non-zero
$(phil) privrun su - app1
$(app1) id
uid=200(app1) gid=30(apps)
$(app1) getprocxsec
effective= BASIC
permitted= BASIC
retained= BASIC
cmpt= app1_cmpt
euid= non-zero
Note that not only does this get the correct context, but because the su command is executed in the context of root, no password is required. This means that the application account can be set with a non-usable password (e.g. "*") preventing direct login. It also means that no password is required to be shared between the administrators, as access to the context is controlled by the RBAC authorization.
Within the compartment, we have full access to our own directory structure:
$(app1) ls -l /data/app1
drwx------ 2 app1 apps data
drwx------ 2 app1 apps wls
but we have no access at all to the directory structures of the other applications:
$(app1) ls -l /data/app2
/data/app2 unreadable
even if we gain root privileges:
$(app1) su -
Password:
# ls -l /data/app2
/data/app2 unreadable
Finally, let's try to escape from this compartment by creating a new shell command and explicitly setting it to run in another compartment:
# cp /usr/bin/sh /data/app1/badsh
# setfilexsec -c init /data/app1/badsh
# getfilexsec -c /data/app1/badsh
/data/app1/badsh
Flag: start_full
PermittedMinPrivileges:
PermittedMaxPrivileges:
RetainedMinPrivileges:
RetainedMaxPrivileges:
# /data/app1/badsh
# getprocxsec
effective= BASIC
permitted= BASIC
retained= BASIC
cmpt= app1_cmpt
euid= non-zero
So, even though we are root and have access to an executable that would normally teleport us to another compartment, we are contained within the app1_cmpt because it has been declared as sealed.
Links
HP-UX Security Products -- http://www.docs.hp.com/en/internet.html
Phil Day has a bachelor's degree from Warwick University and has worked on various Unix systems for 25 years. He is currently a Senior Solution Architect with HP Consulting, with a particular focus on IT Simplification, Utility Computing, and Virtualization. He used to have hobbies but now has small children instead. Phil can be contacted at: phil.day@hp.com.
|