This is the first blog in a series of three that reviews best practices in Unix/Linux least privilege policy development using PowerBroker for Unix & Linux. This post will be geared toward PowerBroker customers developing a policy that restricts senior system administrators from certain activities on a system. Be sure to watch for the next two blogs in this series where we will review mid-level and junior administrator policies.
In many IT organizations there are administrators who need broad privileged access to Unix/Linux systems in order to execute their work, but who require some restrictions from performing certain functions that may impact system availability, or over which oversight is desired (for example for compliance purposes). This blog is meant to be an introduction to policy writing, and best practices around developing policies within your environment so you can gain better control over your Unix/Linux environment while still ensuring your administrators are productive.
It is important to understand that these are only examples of how this can be accomplished, and is in no way a recommendation for policies within your environment. Every customer use case is different, and these posts merely demonstrate the flexibility and control available within PowerBroker for Unix & Linux policy language.
Before we jump into policy, let’s quickly review why privileged access management (PAM) is important for Unix/Linux systems.
Understanding why Privileged Access Management (PAM) is Important
Privileged access management is often driven by regulatory requirements that require businesses to know ‘who’ is doing ‘what’, ‘where’, ‘when’, and ‘why’ on systems they own, manage, or control. That is a very simple definition, but as you develop policy, those key words will help you to understand and reason through policies.
Understanding the drivers behind why PAM is so important in your organization is the first step toward writing effective policies. Although it is primarily driven by regulatory, audit, or general compliance requirements, it is important to understand that any or all of those can be behind specific reasons for policy development.
Writing System Administrator Policies
System administrators are responsible for making sure that systems are available and healthy, they monitor processes and ensure that applications are performing as designed, and they maintain systems to keep them patched and up to standards.
It is important that policies be developed based on the experience of system administrators that balances the risk of inappropriate activity against system maintenance. As system administrators become more experienced, they can be progressively granted more privileges on systems. For instance, you may want to restrict a junior system administrator from being able to stop a network interface, or reboot a server without a higher-level administrator confirming that is the correct solution.
This method also opens the door to having oversight on system administrators where a second pair of eyes may be required to execute the most privileged commands.
When building the system administration policies, it is best to begin with a base policy that has the least restriction (Level 3), and use that as a template to add restrictions for the other levels. This may seem counter-intuitive, but having a solid template, and locking it down further for the other levels is the easiest way to proceed.
The code below is meant to be demonstrative, rather than efficient. The purpose is to demonstrate the logical construct of a policy, and to show examples for later use.
Best Practice: Back up files
When writing policy, or modifying existing policies, files should be backed up, and with each change, policy should be confirmed with the built-in ‘pbcheck’ command to test syntax and policy structure. All policies should be thoroughly tested prior to implementation.
System Administrator Policy – Level 3 (highest level)
When writing the first policy we will assume that the most senior system administrators will have access to ‘any’ system, at any time, to perform any command. Session keystroke logging will be started, and a user notification will be displayed and acknowledged by the user.
Best Practice: Comment liberally
When writing policy, it is important that you use liberal comments. This serves several purposes, including:
- In a busy environment, there are often several people involved in writing policies. Adding comments helps anyone else who may follow to understand the intent and logical construct of your policies.
- From time to time, auditors, or a compliance team may request policies for review. Adding comments will help them to understand – even if they are not technical.
- Once established, policies may go unaltered for years. Having comments will assist greatly when you look back and try to figure out what the design considerations were when it was developed.
Best Practice: Use headers, author, date
Policies should have a header that describes their purpose, the author of the policy, the date it was created, a record of any changes made with the date of the change, and who altered it.
Suggested Format:<br /># Level 3 System Administrator Policy<br /># Permits senior system administrators to execute any command<br /># on any server.<br />#<br /># Author: Bob Policywriter<br /># Original Implementation: 01/01/2017<br />#<br /># Changelog:<br /># 01/10/2017 – Fred PolicyWriter – Added something at the<br /># request of the administrators (CHG0010000)<br />#<br />
Best Practice: Improve change management
Proper change management, and keeping records of changes will greatly improve audit results, as well as training. Habitually keeping meticulous records of policy changes may be useful if policies ever come under scrutiny during a legal or compliance investigation as well. It is better to leave a detailed audit trail than to leave questions.
Policy will follow the ‘Who’, ‘Where’, ‘What’ pattern described above. In this first policy, this will be called out. In later policy examples, this will be assumed.<br /># Who<br /># In the development policy, system administrators are all<br /># members of the LDAP group ‘L3ADMINS’<br /># Define the group that this policy will apply to
L3AdminGroup = “L3ADMINS”;
#
# Where
# In the development policy, we’ll pretend that there are four
# *NIX servers in our environment.
# Define Server list where policy will apply
UnixServers = “{abc123, abc124, abc125, abc126}”;
Note the curly braces around the list above. By creating a list of servers, we can refer to elements within the list when validating the request. See the Policy Language Guide for more information on lists and how to use them.
<br /># What<br /># In the development policy, the senior administrators can run<br /># any command on any of the servers listed.<br /># Commands = “{*}”; -- All commands are authorized.<br />
Since the exact command is not necessary in this policy (all commands are authorized), there is no need to define anything here. This will be a placeholder for later policies. In this case, a comment to say that all commands are authorized is all that is necessary.
<br />#<br /># Define the condition where this will apply using built-in<br /># variables that come when a request is processed.<br />if ( (L3AdminGroup in groups) && (runhost in UnixServers) ) {<br />}
# End if group and host are in the list
Best Practice: Comments on conditional statements
Policies can become very large and complex – putting comments on the closing braces on ‘if’, ‘for’, and other conditional statements will make it much easier to keep policies organized.
The following code will go within the ‘if’ statement above. It is broken out here so each line can be explained in detail. Bear in mind that within policy you can control all aspects of a user’s environment when authorizing commands.
Step 1 will be to set up the session log for this task:<br /># Set up I/O (keystroke) log for this session<br /># Identify the root directory where iologs will be stored
iolog_dir="/iologs";
# Set the HHMM for log file naming
logtime=strftime("%H:%M");
# Set the log file name
iolog=iolog_dir
+ "pbul_iolog." # All logs will start with ‘pbul_iolog’
+ "admin-session." # Description for session
+ sprintf("%d-%d-%d",month,day,year) + "." # MM-DD-YYYY
+ logtime + "." # HH:MM
+ split(runhost,".")[0]; # Short name of the host
+ basename(command) + "."; # Command entered
+ ".XXXXXX"; # Unique serial number
The filename will expand out to:
/iologs/pbul_iolog.admin-session.01-01-2017.12:00.abc123.su.999999
Note that how the session logs are named is entirely up to the customer. The example above just demonstrates how variables can be used to construct a logical file name.
Step 2 will be to set some basic user environment variables:<br /># Set user environment for this session
runcwd = "/tmp"; # Directory to run command from
rungroup = "!g!"; # Group for user
rungroups = {"!G!"}; # All groups for user
setenv("SHELL", "!!!"); # Set user shell
setenv("HOME", "!~!"); # Set user home
setenv("USER", RunUserName); # Set username
setenv("USERNAME", RunUserName); # Set Name i.e. ‘bob jones’
setenv("LOGNAME", RunUserName); # Set logname variable
setenv("PWD", runcwd); # Set directory to start in
setenv("PATH", "/bin:/usr/bin:/sbin:/usr/sbin"); Set PATH
Most of the above variables are not necessary for most policies. Setting those variables was a way to demonstrate how the user environment can be controlled within a session. For a complete list of variables available, consult the Policy Language Guide.
Step 3 is to set command execution parameters:
<br /># Set command execution<br />runuser = “root”; # All commands for this policy run as ‘root’
# Notify user that session logging is on
print("WARNING: This session is being centrally recorded.”);
print("Session Recording Filename:",iolog);
Note – In some jurisdictions, displaying a notice to privileged users is sufficient, in some it is not required, and in others, it is necessary that they acknowledge the warning. It is up to the customer to determine what is required for their business, or industry, and to develop policies accordingly.
<br /># Accept the command, and proceed with execution<br />accept;<br />
When an ‘accept’ is received within policy, an event is logged, and in the case of this policy, a session log is started.
The entire policy for the senior system administrators:
<br /># Level 3 System Administrator Policy<br /># Permits senior system administrators to execute any command<br /># on any server.<br />#<br /># Author: Bob Policywriter<br /># Original Implementation: 01/01/2017<br />#<br /># Changelog:<br /># 01/10/2017 – Fred PolicyWriter – Added something at the<br /># request of the administrators (CHG0010000)<br />#<br /># Who<br /># In the development policy, system administrators are all<br /># members of the LDAP group ‘L3ADMINS’<br /># Define the group that this policy will apply to
L3AdminGroup = “L3ADMINS”;
#
# Where
# In the development policy, we’ll pretend that there are four
# *NIX servers in our environment.
# Define Server list where policy will apply
UnixServers = “{abc123, abc124, abc125, abc126}”;
# What
# In the development policy, the senior administrators can run
# any command on any of the servers listed.
# Commands = “{*}”; -- All commands are authorized.
#
# Define the condition where this will apply using built-in
# variables that come when a request is processed.
if ( (L3AdminGroup in groups) && (runhost in UnixServers) ) {
# Set up I/O (keystroke) log for this session
# Identify the root directory where iologs will be stored
iolog_dir="/iologs";
# Set the HHMM for log file naming
logtime=strftime("%H:%M");
# Set the log file name
iolog=iolog_dir
+ "pbul_iolog." # All logs will start with ‘pbul_iolog’
+ "admin-session." # Description for session
+ sprintf("%d-%d-%d",month,day,year) + "." # MM-DD-YYYY
+ logtime + "." # HH:MM
+ split(runhost,".")[0]; # Short name of the host
+ basename(command) + "."; # Command entered
+ ".XXXXXX"; # Unique serial number
# Set user environment for this session
runcwd = "/tmp"; # Directory to run command from
rungroup = "!g!"; # Group for user
rungroups = {"!G!"}; # All groups for user
setenv("SHELL", "!!!"); # Set user shell
setenv("HOME", "!~!"); # Set user home
setenv("USER", RunUserName); # Set username
setenv("USERNAME", RunUserName); # Set Name i.e. ‘bob jones’
setenv("LOGNAME", RunUserName); # Set logname variable
setenv("PWD", runcwd); # Set directory to start in
setenv("PATH", "/bin:/usr/bin:/sbin:/usr/sbin"); Set PATH
# Set command execution
runuser = “root”; # All commands for this policy run as ‘root’
# Notify user that session logging is on
print("WARNING: This session is being centrally recorded.”);
print("Session Recording Filename:",iolog);
# Accept the command, and proceed with execution
accept;
}
# End if group and host are in the list
System Administrator Policy – Summary
As you can tell, the PowerBroker for Unix & Linux policy language is very powerful, and permits control over virtually all aspects of a user’s activity within a session. Building an initial policy and using it as a template for other policies is an easy way to expand policy control across an environment. The Advanced Control and Audit feature is a very powerful tool within the policy language, and permits granular control over user activities even within a privileged session.
It is strongly recommended that the above examples be used as a starting point for developing policies customized to suit your environment. For more information on how BeyondTrust can help you simplify Unix/Linux security and compliance, download our whitepaper or contact us for a demo today.
Watch for more blogs coming in this series!
Chad Erbe, Professional Services Architect, BeyondTrust
Chad Erbe is a Certified Information Systems Security professional (CISSP), with nearly 30 years’ experience in a Unix/Linux administration role. Chad has worked in DoD high-security environments, manufacturing, and with large financial services companies throughout his career. This broad experience has lead him to an architectural role with BeyondTrust where he focuses on Privileged Access Management, particularly in the Unix suite of products. Chad also maintains his PCI ASV certification from the PCI council.