11 April,19 at 11:50 AM
Background
Regulatory frameworks have evolved to require documented evidence of approval for development or infrastructure-related change control. These activities usually require the exercise of elevated privileges. Some examples of these requirements and guidelines can be found on PCI DSS, SANS Critical Security controls, ISO 27001 and others:
Centrify DirectAuthorize and DirectAudit provide end-to-end, role-based access controls for UNIX, Linux and Windows, in addition it provides mechanisms for validation and tracking of changes via ticketing or request systems.
Requirements
We've had customers that have two categories of requirements:
$ dzdo tail /var/log/messages Enter the change control ticket number:1255
syslog:
Nov 7 15:04:39 engcen6 dzcheck.sample[35173]: User "dwirth@centrify.vms" will run "/usr/bin/tail /var/log/messages" as "root" with ticket number "1255"DA Console:
Lab Diagram
What you'll need:
Use Case
Implementation Overview
Install the ServiceNow Perl API
The full instructions and requirements are here: http://wiki.servicenow.com/index.php?title=Perl_API#gsc.tab=0
## create a new folder, download and unzip $ mkdir SN $ cd SN $ wget http://wiki.servicenow.com/images/e/e5/ServiceNow-Perl-API.zip $ unzip ServiceNoW-Perl-API.zip ## compile the files $ perl Makefile.PL $ make $ make test $ make installFollow the prompts, once you have all the ServiceNow Perl API libraries installed to use with your scripts.
Testing Connectivity with your ServiceNow Instance (Sample Script)
# This script retrieves all the requests from your servicenow instance # it is used to test connectivity. #!/usr/bin/perl -w use ServiceNow; use ServiceNow::Configuration; # This example uses Centrify Privilege Service's AAPM capability # by checking-out the password from the vault at runtime, we eliminate # the need to use a cleartext password in this script. # uses cgetaccount to check out the password for your-SN-user for 3 mins. # Alternatively you can enable OAuth and use Tokens (recommended) $SN_PASSWD = `cgetaccount -s -t 3 your-SN-user`; my $CONFIG = ServiceNow::Configuration->new(); $CONFIG->setSoapEndPoint("https://your-instance.service-now.com/"); $CONFIG->setUserName("your-SN-user"); $CONFIG->setUserPassword($SN_PASSWD); my $SN = ServiceNow->new($CONFIG); my @requests = $SN->queryRequestedItem(); my $count = scalar(@requests); print "Number of requests=" . $count . "\n"; foreach my $request (@requests) { print "Request number: $request->{'number'}\n"; print "Requested by: $request->{'sys_created_by'}\n"; print "Date Created: $request->{'sys_created_on'}\n"; print "Approval Status: $request->{'approval'}\n"; print "\n"
2. To test the script, add the execution flag and run it
$ chmod +x checksn.sh $ ./inc2.sh Number of requests=34 Request number: RITM0000002 Requested by: fred.luddy Date Created: 2016-05-02 18:15:39 Approval Status: requested Request number: RITM0000004 Requested by: fred.luddy Date Created: 2016-09-03 17:15:39 Approval Status: requested Request number: RITM0000005 Requested by: fred.luddy Date Created: 2016-05-22 19:15:43 Approval Status: requested [output truncated]
Modify the Sample Script to work with Individual Ticket Numbers
To do this, you need to change the script to require arguments and check for usage. The modified lines would look like this:
#!/usr/bin/perl -w # You're checking for arguments here. If there are no arguments # show the usage and exit. E.g. checksn RTM00005 if (@ARGV) { # The previous program can go here. Make sure you modify this line # to look like this: my @requests = $SN->queryRequestedItem({'number'=> $0}) } else { print "USAGE: checksn [ServiceNow Request ID]\n" }
Note that there's no error logic for requests that are not found. We're going to have to add this later.
Modify the dzdo.validator script to to use the ServiceNow Perl API script
Centrify provides a sample dzdo validator script called dzcheck.sample. This script exists under /usr/share/centrifydc/bin.
With the author's limited scripting knowledge we were able to modify it to work this way:
Note that additional error logic and checks can be added.
#!/bin/sh /usr/share/centrifydc/perl/run # A modified demo for Centrify-enhanced sudo (dzdo) validator # Modified to work with ServiceNow Requests use strict; use lib "../perl"; use lib '/usr/share/centrifydc/perl'; use CentrifyDC::Logger; use ServiceNow; use ServiceNow::Configuration; # Use privilege service to retrieve SN shared account password # Alternatively, you can modify the script to use an OAuth token my $SN_PASSWD = `cgetaccount -s -t 3 your-user`; my $dzdo_user=$ENV{DZDO_USER}; my $dzdo_command=$ENV{DZDO_COMMAND}; my $dzdo_runasuser=$ENV{DZDO_RUNASUSER}; my $CONFIG = ServiceNow::Configuration->new(); $CONFIG->setSoapEndPoint("https://your-instance.service-now.com/"); $CONFIG->setUserName("your-user"); $CONFIG->setUserPassword($SN_PASSWD); my $SN = ServiceNow->new($CONFIG); my $logger = CentrifyDC::Logger->new('dzcheck'); printf STDERR "Enter the change control ticket number: "; my $user_input=queryRequestedItem({'number' => $user_input}); # Check if request(s) exist, if not, exit (1) if (scalar(@requests)==0) { system "adsendaudittrailevent", "-t", "tkt_id", "-i", "$user_input"; $logger->log('INFO', "Change control ticket number: %s", $user_input); $logger->log('INFO', "User \"%s\" will not be allowed to run \"%s\" as \"%s\" with ticket number (REASON:not found) \"%s\"", $dzdo_user, $dzdo_command, $dzdo_runasuser, $user_input); exit 1; } foreach my $request (@requests) { my $req_status = $request->{'approval'}; # Exit if request is not in approved status if ($req_status ne "approved") { system "adsendaudittrailevent", "-t", "tkt_id", "-i", "$user_input"; $logger->log('INFO', "Change control ticket number: %s", $user_input); $logger->log('INFO', "User \"%s\" will not be allowed to run \"%s\" as \"%s\" with ticket number (REASON:not approved) \"%s\"", $dzdo_user, $dzdo_command, $dzdo_runasuser, $user_input,$req_status); exit 2; } } # Run command and log if request is approved system "adsendaudittrailevent", "-t", "tkt_id", "-i", "$user_input"; my $logger = CentrifyDC::Logger->new('dzcheck'); $logger->log('INFO', "Change control ticket number: %s", $user_input); $logger->log('INFO', "User \"%s\" will run \"%s\" as \"%s\" with ticket number \"%s\"", $dzdo_user, $dzdo_command, $dzdo_runasuser, $user_input); exit 0;
I've saved this script as dzcheck.snow in the same location.
Configure Centrify-enhanced sudo (dzdo) to use the ServiceNow Requests validator
dzdo.validator: /usr/share/centrifydc/sbin/dzcheck.snow
Testing
We'll use a modified version of the sample script to check the requests for validity first, then we'll try to flush the cache using dzdo.
Request verification $ ./sncheck ABC123 Request not found.
$ dzdo adflush Enter the change control ticket number: ABC123 Sorry, user dwirth is not allowed to execute '/usr/sbin/adflush' as root on engcen6.centrify.vms. # syslog contents Sep 20 18:00:52 engcen6 dzcheck.snow[35963]: Change control ticket number: ABC123 Sep 20 18:00:52 engcen6 dzcheck.snow[35963]: User "dwirth@centrify.vms" will not be allowed to run "/usr/sbin/adflush" as "root" with ticket number (REASON:not found) "ABC123#012" Sep 20 18:00:52 engcen6 adclient[1526]: INFO AUDIT_TRAIL|Centrify Suite|dzdo|1.0|1|dzdo denied|5|user=dwirth(type:ad,dwirth@CENTRIFY.VMS) pid=35961 utc=1474412452436 centrifyEventID=30001 status=DENIED service=dzdo command=/usr/sbin/adflush runas=root reason=Dzdo Validator checks failed. Do not permit to continue the privileged command.
Request verification: $ ./sncheck RITM0010022 number of requests=1 Request number: RITM0010022 Requested by: robertson.pimentel Date Created: 2016-09-16 16:55:06 Approval Status: requested
$ dzdo adflush Enter the change control ticket number: RITM0010022 Sorry, user dwirth is not allowed to execute '/usr/sbin/adflush' as root on engcen6.centrify.vms. # syslog content Sep 20 18:03:04 engcen6 dzcheck.snow[36011]: Change control ticket number: RITM0010022 Sep 20 18:03:04 engcen6 dzcheck.snow[36011]: User "dwirth@centrify.vms" will not be allowed to run "/usr/sbin/adflush" as "root" with ticket number (REASON:not approved) "RITM0010022#012" Sep 20 18:03:04 engcen6 adclient[1526]: INFO AUDIT_TRAIL|Centrify Suite|dzdo|1.0|1|dzdo denied|5|user=dwirth(type:ad,dwirth@CENTRIFY.VMS) pid=36009 utc=1474412584884 centrifyEventID=30001 status=DENIED service=dzdo command=/usr/sbin/adflush runas=root reason=Dzdo Validator checks failed. Do not permit to continue the privileged command
$ ./sncheck RITM0010003 number of requests=1 Request number: RITM0010003 Requested by: diego.jimenez Date Created: 2016-09-11 14:57:57 Approval Status: approved
$ dzdo adflush Enter the change control ticket number: RITM0010003 Demo Password: DNS cache flushed successfully. Authorization cache store flushed successfully. GC and DC caches expired successfully. The auditing service's name cache has been successfully flushed. The DirectAudit installation information cache has been successfully flushed. # syslog content Sep 20 18:06:22 engcen6 dzcheck.snow[36108]: Change control ticket number: RITM0010003 Sep 20 18:06:22 engcen6 dzcheck.snow[36108]: User "dwirth@centrify.vms" will run "/usr/sbin/adflush" as "root" with ticket number "RITM0010003#012" Sep 20 18:06:22 engcen6 adclient[1526]: INFO AUDIT_TRAIL|Centrify Suite|dzdo|1.0|0|dzdo granted|5|user=dwirth(type:ad,dwirth@CENTRIFY.VMS) pid=36106 utc=1474412782119 centrifyEventID=30000 status=GRANTED service=dzdo command=/usr/sbin/adflush runas=root role=UNIX Sysadmin/Global env=(none)
Benefits if you're using DirectAudit
If you have Enterprise Edition, DirectAudit's events will contain information about the Change Control and you can now search for all activity related to an individual change control number.
Benefits if you're using the Centrify Splunk App
The Splunk App will display reports on the reasons why the privilege elevation failed. You can also add alerts based on this to identify any privileged user trying to fish.
Improvements
This is a lab blog post, therefore this is just a simple concept, but here are the improvements I'd make:
Quick Overview Video
Notes: ServiceNow, PCI DSS, SANS and ISO 27001 logos are registered trademarks of their respective owners.