In order to automate Active Directory instance joins and unjoins, we need a keytab file corresponding to an AD user that has the proper rights in AD and in the Centrify zone.

Because a keytab is pretty much a credential, we are going to adhere to the following principles:

  • The credential for the keytab shall have least minimum access
  • The password for the credential shall be unknown
  • The keytab file shall always be deleted once it's used.


What you'll need:

  • You may need assistance from your Active Directory lead
    • Why? First and foremost separation of duties.  Also, in practicality, the UNIX/Linux/Mac teams in enterprises are different from the AD teams.
    • What do they need to do for me?  They need to create an AD account, provide delegation (see below) and they may have to type their credential when running the adkeytab command.
    • How many times do we need to do this?  Only once. 

Create an AD User

When you create an AD service account, you have to align with the security policy governing these accounts.  The overhead can come depending on the frequency of password changes.  Since adkeytab scrambles the password and it's effectively unknown, the account can be set with a Password Never Expires/User cannot change password flag, however for due-diligence you may rotate it once a year.  Each time the password is rotated, the key table file has to be generated again.


  1. Open Active Directory Users and Computers
  2. Navigate to the container or OU for this service account
  3. Select New > User
  4. In the New Object form, set the information based on your naming convention
    Note:  the "common name" of the user is typically the same as the display name.  If this contain spaces, you have to make note of this for when you use the adkeytab command (samaccountname vs cn).
  5. In the New Object - User form, type a password and set the options according to your service account policy
    Remember, if you do the right thing, adkeytab will randomize the password and this can be a compensating control.  If you are required to change this password, you must re-generate the keytab and redistribute, otherwise your scripts or recipes will fail.

If you prefer PowerShell instead, you can use the New-ADUser commandlet.

Now you should have a service account.  Make note of the username (e.g. ad-joiner) vs. the cn (AD Joiner Service Account).


Delegate Permissions

There are 2 delegations needed to make sure the automation of joins/removals works.  The service account should be able to create/remove  computer objects in your designated AD container for UNIX/Linux or Mac systems, plus if you're using Centrify zones, the system has to have the ability to join, remove and modify computer profiles.

Optionally, there's a third delegation related to Computer Roles (contained in AD groups); for this you need to provide the "manage group membership" delegation to the target groups (or OU that contains the groups).


Let's illustrate the steps using this OU structure


 In this scenario, I plan to add the UNIX/Linux computers to the Servers SubOU under Centrify; this means that I have to delegate at that level to preserve the least privilege principle.  In a real-world deployment, you may have a different layout (perhaps based on sites), in that case you have to delegate in multiple places.


To delegate the computer object in the target OU 

  1. In ADUC (as a privileged AD user), right click the Servers SubOU and select "Delegate Control"
  2. Welcome Page > Next
  3. Users or Groups > press Add, find the service account, select and press OK, then Next
  4. Task to Delegate > Select "Create custom task to delegate" and press Next
  5. Object Type > Select "Only the following objects in the folder"; check the Computer Objects box and check  Create and Delete.
  6. Permissions tab > Check "Full Control" under permissions and press Next.
    You can dial this down, however we have this scoped down to the OU and type of object.
  7. Completing page > Finish

 Now the service account can create/remove computer objects in the Servers container.


To delegate at the Centrify Zone level

You must know all the Centrify zones that the service account will be leveraged for automation.  In my example I have one zone (AWS). Centrify provides PowerShell to perform bulk delegations (see Set-CdmDelegation, in this link)

  1. Open Centrify DirectManage Access Manager
  2. If needed, open your target zone(s)
  3. Right-click the zone and select "Delegate Zone Control"
  4. Selected Objects > Press Add and find and select  your service account, press OK and Next
  5. Tasks to Delegate > check join and modify computer operations to the zone (3 check boxes)
    Access Manager - delegation of computer ops.jpg
  6. Completing Page > Press Finish.

At this point, if you're not using DirectAuthorize Computer Roles you are done.

Note:  You can always verify delegations by running the "Zone Delegation Report"


Optional:  To delegate for Computer Roles 

Computer Roles allow the grouping of systems as "teams of servers" this gives administrators the flexibility granting access/privileges to systems to  multiple user populations, the only operation required is the the system is a "Member" of the Computer role, and this can be accomplished any time or during system setup by automating add/removal of the computer account into the AD security groups that make-up the computer role.


In my example, I'm leveraging the Centrify recommended OU structure and all my AD Security groups for the purposes of Computer Roles are stored in the Computer Roles SubOU under the Centrify OU.  This means that I only need to make one delegation.  Based on your design, this may vary and you may have to perform multiple delegations.


  1. In ADUC (as a privileged AD user), right click the Computer Roles" SubOU and select "Delegate Control"
  2. Welcome Page > Next
  3. Users or Groups > press Add, find the service account, select and press OK, then Next
  4. Task to Delegate > Select "Modify Membership of a Group" and press Next
    ADUC - delegation membership group.jpg
  5. Completing > Press Finish

From this point on, the service account will be able perform add/removals of objects into any existing or new AD group in that container.


Create the Keytab File

Creating the keytab may require two individuals.  One individual can run privileged commands on UNIX/Linux/Windows, the other is an authorized AD user that can perform certain operations on the AD user (like changing it's password).

You need to know the account's samaccounname vs the common name.  You can quickly see this using the Attribute Editor in ADUC or PowerShell

This is important because the last parameter of the adkeytab command is the common name.  If you assume they are the same, you may hit this error:


AD Object found: CN=AD Joiner,OU=Service Accounts,OU=Centrify,DC=awsrealm,DC=centrifying,DC=net
Error: The account name does not match the SAM account name. You must supply both on the command line.
Adkeytab return code: 23
Failed: Adopt Account: ad-joiner


Here's a simple way of constructing an adkeytab command

  • Elevation required:  root or credential for sudo or dzdo required:  sudo adkeytab
  • Operation:  adopt  (needs the sammacount name, an authorized account and the common name):  --adopt
  • Authorized user (e.g. AD administrator): --user admin
  • AD user: --samname ad-joiner
  • Keytab File name (e.g. login.keytab):  --keytab login.keytab  (the file will be owned by root)
  • Common Name (if the CN is different from samaccount name):  "AD Joiner"  (since there are spaces, it has to be double-quoted)
  • Verbose output recommended (-V)

Here's the command

dzdo adkeytab --samname ad-joiner --adopt --user admin --keytab login.keytab -V "AD Joiner"

Here's a sample output:

dzdo adkeytab --samname ad-joiner --adopt --user admin --keytab login.keytab -V "AD Joiner"
[dzdo] password for lisa:
ADKeyTab version: CentrifyDC 5.4.0-286
use machine ccache: no
server: null
user: admin
container: null
account: AD Joiner
trust: no
des: no
Attempting bind to site:Default-First-Site-Name ccache:MEMORY:0x644640
Bind successful to server
Searching for AD Object: filter = (samAccountName=ad-joiner), root = DC=awsrealm,DC=centrifying,DC=net
AD Object found: CN=AD Joiner,OU=Service Accounts,OU=Centrify,DC=awsrealm,DC=centrifying,DC=net
Key Version = 4
Activating AD account: CN=AD Joiner,OU=Service Accounts,OU=Centrify,DC=awsrealm,DC=centrifying,DC=net. Clearing existing SPNs: No
Account 'CN=AD Joiner,OU=Service Accounts,OU=Centrify,DC=awsrealm,DC=centrifying,DC=net' All SPNs already present
Adding managed account keys to configuration file: AD Joiner
Changing account 'AD Joiner' password with user 'rpimentel@AWSREALM.CENTRIFYING.NET' credentials.
Searching for AD Object: filter = (samAccountName=ad-joiner), root = DC=awsrealm,DC=centrifying,DC=net
AD Object found: CN=AD Joiner,OU=Service Accounts,OU=Centrify,DC=awsrealm,DC=centrifying,DC=net
Key Version = 5
Updated properties to config file /etc/centrifydc/centrifydc.conf.
Success: Adopt Account: AD Joiner

Verify the keytab is correct.  List the principals

 dzdo /usr/share/centrifydc/kerberos/bin/klist -kt login.keytab
Keytab name: FILE:login.keytab
KVNO Timestamp           Principal
---- ------------------- ------------------------------------------------------
   5 04/20/2017 17:49:43 ad-joiner@AWSREALM.CENTRIFYING.NET
   5 04/20/2017 17:49:43 ad-joiner@AWSREALM.CENTRIFYING.NET
   5 04/20/2017 17:49:43 ad-joiner@AWSREALM.CENTRIFYING.NET
   5 04/20/2017 17:49:43 ad-joiner@AWSREALM.CENTRIFYING.NET
   5 04/20/2017 17:49:43 ad-joiner@AWSREALM.CENTRIFYING.NET

 Testing your Keytab for Join/Removal Operations

 You can test the keytab by removing and rejoining Active Directory.  You'll need to use kinit to authenticate with the key table file, then leverage adjoin or adleave to check the results.  Optionally, you can use the --computerrole switch of adjoin to check for those operations.


Authenticating using the key table file

  1. Sign-in to your system with a privileged user (remember, the key table file is owned by root)
  2. Change directories to the location of the key table file.
  3. Run the kdestroy command
  4. Run kinit with the kt option to get a TGT for the service account and klist to verify the TGT
    sudo /usr/share/centrifydc/kerberos/bin/kinit -kt login.keytab ad-joiner
    [dzdo] password for lisa:
    $ /usr/share/centrifydc/kerberos/bin/klist
    $ dzdo /usr/share/centrifydc/kerberos/bin/klist
    Ticket cache: FILE:/tmp/krb5cc_cdc1702888528_Hw29E6
    Default principal: ad-joiner@AWSREALM.CENTRIFYING.NET
    Valid starting       Expires              Service principal
    04/20/2017 17:59:19  04/21/2017 03:59:19  krbtgt/AWSREALM.CENTRIFYING.NET@AWSREALM.CENTRIFYING.NET
            renew until 04/21/2017 17:59:20


Testing adjoin and adleave operations

Depending on the state of your system, you may test removal or joining first.  Since my system is already joined, I'm testing removal first (note that I switched to ec2-user since I was logged in as an AD user).  Note that I'm copying the centrify-populated krb5.conf file, since this file will be rolled-back once the system left the domain.

$ dzdo su ec2-user
$ sudo cp /etc/krb5.conf .
$ sudo adleave --remove Using domain controller: writable=true Left domain. Centrify DirectControl stopped.

Attempting adjoin to the Zone an the "Utility-Servers" computer role.

$ sudo env KRB5_CONFIG=krb5.conf  /usr/share/centrifydc/kerberos/bin/kinit -kt login.keytab ad-joiner
$  sudo adjoin --zone AWS --container ou=servers,ou=centrify --computerrole Utility-Servers
Using domain controller: writable=true
Join to, zone:AWS successful

Centrify DirectControl started.
Initializing cache
You have successfully joined the Active Directory domain:
in the Centrify DirectControl zone: CN=AWS,CN=Zones,OU=Centrify,DC=awsrealm,DC=centrifying,DC=net

You may need to restart other services that rely upon PAM and NSS or simply
reboot the computer for proper operation.  Failure to do so may result in
login problems for AD users.


What next?

At this point you have to distribute your keytable file to your distribution points web server, repository, file share, etc. Note that this file needs to be deleted after it's used for added security.  For example, you can upload this file to an AWS S3 bucket to use it with your AWS OpsWorks or CloudFormation scripts.

Related Articles



Note:  this is a companion article to the blog post titled: "[HOWTO] Orchestration Basics - Using a Chef recipe to deploy Centrify and join Active Directory";  these posts are relatively identical, the only difference is the tool.


In the field, we often get inquiries on deployment, governance or orchestration frameworks.  Common questions range from: how do I deploy the Centrify client?  or How do I establish an approval flow for the Access Control model that you facilitate? 

Sometimes we also hear these questions:  We use Ansible | Bladelogic | Chef | Puppet in on premise or with our IaaS (cloud) deployment, how would I go about deploying your product using those tools?

These are important questions, especially in the age of private/public clouds and elastic environments.  Some of you are adopting frameworks like OpenStack, Amazon AWS or Microsoft Azure that underneath use these toolsets.


At Centrify we have invested heavily through the years to make sure that the products "just work".  From a deployment perspective, we our messaging is consistent:

  • We always provide the native platform package
  • Our tools are all Kerberized  (ready for automation)
  • We also provide other tools like and Deployment manager that abstract the underlying OS package manager
  • The Centrify agent automatically maintains its configuration and the Kerberos configuration based on Active Directory, and it uses AD specs for Sites and Services, DC location, offline cache.
  • The configuration parameters can be managed by any tool, plus native Active Directory Group Policy.

In other words, Centrify software is easier to use in these scenarios than what the typical IT Infrastructure lead may think.


Disclaimers and Acknowledgements

  • This article provides a "quick basic configuration";  in a true deployment you have to account for high-availability, replication, security, package integrity, supported platforms, supported versions, change control, etc. 
  • All names, logos and trademarks used in this articles correspond to their existing owners.
  • We are not Puppet, Chef or Bladelogic subject-matter experts, hence the use of a stand-alone script or recipe. 
  • Puppet Master server/slaves/node architecture is outside the scope of this post
  • This would not be possible without my customers/prospects asking and the tutorials available online.  Some great resources:
    - Introduction to Puppet:
    - Willams' blog post "How to install Puppet in Stand-Alone mode on CentOS7"
    - Kudos to MaestroDev for the wget Puppet extension:

What is required?

  • An Active Directory domain
  • A Centrify zone (optional - if using Centrify in licensed mode/privilege management)
  • A Centrify zone and a Computer Role  (optional)
  • An Active Directory service account for joins and removals, plus a keytab for the account and a usable krb5.conf file.  Read this article if you want to know how to create the service account and obtain the keytab.
  • A RHEL-based system with enough storage for the Centrify RPM packages for each platform (or just for the subset you need to support).  This system has to be set up as a YUM repository, as described in the the original orchestration article.
  • A second RHEL-derivative system to install Puppet (see below), this system must have DNS settings configured correctly.

Note:  Although it's possible for you to follow this and put together a working prototype, I strongly-encourage that you really explore the concepts  of DevOps/infrastructure as code.  The whole philosophy promotes constant improvement, this means that if you expect this to be a "set it and forget it" solution, I advise that you realign your expectations.


Finally, By no means what's outlined here is ready for production.  Check out the reading list below. 


Example Diagram

Chef Blog - Diagram.png


Implementation Steps



The goal of this lab is to be able to deploy the Centrify bits in a RedHat, CentOS, Scientific or Oracle system in a consistent way.  Also, if you know what you're doing, you can extend this to other OSs, and platforms as well.


The 'core' process without checking for major dependencies or issues is to:

  1. Install Centrify DirectControl
  2. Authenticate against Active Directory with an account with minimal rights
  3. Join Active Directory

Building Blocks

  • YUM Repository with Centrify RPMs (detailed instructions here)
  • AD account + keytab (steps outlined in a previous post)
  • Usable krb5.conf:  You can copy this file from any Centrified system; however, depending on where you're onboarding the system, you want to edit the file only with the DCs that are reachable to the new system.


Make the krb5.conf and service account keytab available to your infrastructure

In the original article, we piggy-backed on the Apache webserver as the transport for our repository.  Now we're going to create another folder for utilities (utils for short) and copy the keytab and krb5.conf file.

If you prepared this for the Chef article, you can skip to Puppet installation.


  1. Create a folder under /var/www/html
    $ sudo mkdir /var/www/html/centrify/utils
  2. Copy the RPMs to the folder.
    $ cd /path/to/files
    $ sudo mv krb5.conf  /var/www/html/centrify/utils
    $ sudo mv ad-joiner.keytab  /var/www/html/centrify/utils
  3. Set the proper permissions in the folder
    chmod -R ugo+rX /var/www/html/centrify/utils
  4. Verify that the files are accessible via the web server (you may have to check the firewall settings)

Install Puppet and the wget Extension

  1. Add the Puppet repository (you must find the proper repository for your RHEL version, version 7 shown)
    $ sudo rpm -ivh
  2. Install the bits
    $ yum install puppet
  3. Make sure your system's DNS settings are up to date (yes, no "localsystem.localdomain")
    Can you ping your own system by name and FQDN?
    What is the output of the hostname command?
    Run this:
    facter | grep hostname
    facter | grep fqdn
    if the output isincorrect, you must edit the /etc/hosts and /etc/resolv.conf and speak to your DNS admin to set things straight
  4. Logout and log back in to verify the ruby path
    $  sudo puppet module install maestrodev-wget
    You should be ready to get going.

Create and test your stand-alone Puppet Script

To recap, the sequence to automate Installation and joins is as follows:

  1. Retrieve a usable krb5.conf file
  2. Retrieve the keytab of a valid service account with minimum rights to join systems to the target AD OU, to the target zone (if using in zone mode) and if adding to a Computer role, with rights to add to the target AD groups.
  3. Install the Centrify Package and use the kinit tool to obtain a TGT
  4. Run adjoin with the proper options.
  5. Perform cleanup


Here is the Non-idenpotent Puppet Script:


# This stand-alone recipe will install the Centrify Agent on RHEL derivatives, 
# joins Active Directory and places the system in a Computer Role
# Notes: This recipe is not idempotent (achieving this is up to you!)

include wget

# Variables for my environment (see blog post)
# domain is the most basic parameter to join Active Directory

$adname = "centrify.vms"  
# Notice that I could not use "domain" like in the Chef example.  
# That word seems to be reserved in Puppet # In Zone Mode (licensed with UNIX identity and Access Control) the zone # parameter corresponds is where the system will be placed. Not needed # if working in workstation or express mode. $zone = "Global" # OU is where your computer object will be placed in Active Directory # your ad-joiner account should be able to join systems to this container $ou = " ou=servers,ou=unix" # A Computer role is one of the ways to group systems and define access # control. A system may be a member of multiple computer roles. # E.g. a LAMP system may be accessible by Web Admins, Developers and # DBAs with different access rights and privileges. $crole = "App Servers" # nodes are the managed system in Puppet; in a true deployment you can # apply to individual systems or collections of systems. Since this is not # idempotent, you must specify the fqdn. node "your-system-fqdn" { # Centrify's utilities are Kerberized, this means that they will use the current # user's Kerberos TGT to attempt the transaction against AD. However, in a # virgin system, there are no working krb5.conf files, therefore kinit won't know # how to find a KDC to authenticate against. This is why we need a krb5.conf # file from a working system (or that points to a reachable Domain Controller), # in the previous blog entry, we piggy-backed on an Apache Web server to # serve those files (engcen6). wget::fetch {"download a working krb5.conf": source => 'http://engcen6.centrify.vms/centrify/utils/krb5.conf', destination => '/temp/krb5.conf', timeout => 0, verbose => true, nocheckcertificate => true, before => Exec["kinit"] } # The keytab corresponds to a service account that has the minimal rights, in # this case, the rights to write a computer object in the designated container # (ou), centrify zone and the AD group that contains the "App Servers"computer # role needless to say, you need to treat this file with care and if possible, # remove when complete. wget::fetch {"download the ad-joiner keytab file": source => 'http://engcen6.centrify.vms/centrify/utils/ad-joiner.keytab', destination => '/temp/ad-joiner.keytab', timeout => 0, verbose => true, nocheckcertificate => true, before => Exec["kinit"] } # We leverage Puppet to ensure the files are present. This will be used later # to guarantee proper sequencing. file {"ad-joiner.keytab": ensure => present, path => '/temp/ad-joiner.keytab' } file {"krb5.conf": ensure => present, path => '/temp/krb5.conf' } # In this command, we authenticate against AD with the keytab of our service # account. Note that we are using the usable krb5.conf file so kinit can reach # a KDC (domain controller). The end-result is that root (or sudo) user will # have a TGT and you don't need to put keys, hashes or passwords in your # script. The before/subscribe and require Puppet directives guarantee proper # sequencing. exec {"kinit": command => "/bin/env KRB5_CONFIG=/temp/krb5.conf /usr/share/centrifydc/kerberos/bin/kinit -kt /temp/ad-joiner.keytab ad-joiner", before => Exec["adjoin"], subscribe => [ File["/temp/ad-joiner.keytab"], File["/temp/krb5.conf"], ], require => Package["CentrifyDC"], } # In a pre-requiste blog entry, I outlined how to create a YUM repository for # RHEL and derivatives. This means that you need a yum or apt repo with # the Centrify packages. Puppet will simply make sure the package is present # notice the differences, I declared this after the previous directives, when # the package is a pre-requisite. package {"CentrifyDC": ensure => 'installed', } # Finally we run adjoin. At this point we are using the variables from my # environment. Although in doing so, we broke the 'idempotent principles, I'm # certain that Puppet experts can find ways to improve on this. exec { "adjoin": command => "/usr/sbin/adjoin -z $zone -c $ou -R \"$crole\" -V $adname", require => Package["CentrifyDC"] } # In the cleanup phase, we clear the TGT and delete the utility files # Although the keytab provides very specific limited AD rights, always make # a habit of cleaning-up. exec {'kdestroy': command => '/bin/env KRB5_CONFIG=/tmp/krb5.conf /usr/share/centrifydc/kerberos/bin/kdestroy', require => Exec['adjoin'], } exec {"/bin/rm -f /temp/*": require => Exec['kdestroy'], } } # End of Script



Verify the recipe

$ sudo puppet apply centrify-build.pp
Notice: Compiled catalog for engcen7.centrify.vms in environment production in 1.77 seconds
Info: Applying configuration version '1458157258'
Notice: /Stage[main]/Main/Node[engcen7.centrify.vms]/Package[CentrifyDC]/ensure: created
Notice: /Stage[main]/Main/Node[engcen7.centrify.vms]/File[krb5.conf]/ensure: created
Info: /Stage[main]/Main/Node[engcen7.centrify.vms]/File[krb5.conf]: Scheduling refresh of Exec[kinit]
Notice: /Stage[main]/Main/Node[engcen7.centrify.vms]/Wget::Fetch[download a working krb5.conf]/Exec[wget-download a working krb5.conf]/returns: executed successfully
Notice: /Stage[main]/Main/Node[engcen7.centrify.vms]/File[ad-joiner.keytab]/ensure: created
Info: /Stage[main]/Main/Node[engcen7.centrify.vms]/File[ad-joiner.keytab]: Scheduling refresh of Exec[kinit]
Notice: /Stage[main]/Main/Node[engcen7.centrify.vms]/Wget::Fetch[download the ad-joiner keytab file]/Exec[wget-download the ad-joiner keytab file]/returns: executed successfully
Notice: /Stage[main]/Main/Node[engcen7.centrify.vms]/Exec[kinit]/returns: executed successfully
Notice: /Stage[main]/Main/Node[engcen7.centrify.vms]/Exec[kinit]: Triggered 'refresh' from 2 events
Notice: /Stage[main]/Main/Node[engcen7.centrify.vms]/Exec[adjoin]/returns: executed successfully
Notice: /Stage[main]/Main/Node[engcen7.centrify.vms]/Exec[kdestroy]/returns: executed successfully
Notice: /Stage[main]/Main/Node[engcen7.centrify.vms]/Exec[/bin/rm -f /temp/*]/returns: executed successfully
Notice: Finished catalog run in 38.32 seconds


Verification Video




There are absolutely many improvements that can be made.   Here are a few that come to mind (in no specific order):


  • Check for Perl:  CentrifyDC requires Perl 5.8 and up.
  • Chek for DC connectivity:  You can potentially check for connectivity to KDCs prior to attempting to authenticate.
  • Inspect the name of the system:  In keeping with AD Naming conventions, we should check for length and uniqueness in the forest prior to join.
  • Check if the system is already joined or in the desired zone/forest.
  • Inspect the IP/DNS configuration:  Maybe the TCP/IP and DNS config is not right.
  • Perform a Dynamic DNS update using addns:  After join, you can use addns to get the system registered with Microsoft DNS
  • Obtain Certificates with ADCert:  If the system is used for SSL communications, you can get the cert manually using adcert.
  • Manage centrifydc.conf:  There are some basic parameters that may not be manageable via GPO (e.g. DMZ) that can be managed from there.
  • New Information:  Centrify DirectControl can provide information to Puppetregarding the AD topology.
  • Add dependent packages:  LDAP Proxy or Centrify DirectAudit/DirectSecure come to mind.
  • Most importantly:  This requires a Puppet infrastructure.  Make it as idempotent as possible!


Showing results for 
Search instead for 
Do you mean 

Community Control Panel