Showing posts with label puppet. Show all posts
Showing posts with label puppet. Show all posts

Wednesday, March 16, 2016

Deploy Centrify and Join Active Directory automatically using a stand-alone Puppet script

A few months ago I published a post titled "Deploy Centrify and Join Active Directory with a simple Chef Recipe" as customary, after I get asked about something 3 times, it's time to create a post, but now using Puppet by PuppetLabs.  This post is identical to the Chef post, just different tools.

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.
  • I'm 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:  https://docs.puppetlabs.com/guides/introduction.html
    - Willams' blog post "How to install Puppet in Stand-Alone mode on CentOS7"
    - Kudos to MaestroDev for the wget Puppet extension: https://forge.puppetlabs.com/maestrodev/wget
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

Planning
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)
    utils.PNG

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 http://yum.puppetlabs.com/puppetlabs-release-el-7.noarch.rpm
  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


Review the results
$ 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


Friday, October 9, 2015

Utilities: install.sh

Background

Automation and orchestration are key capabilities of the modern IT infrastructure.  Whether organizations are using private or public clouds, tools like Bladelogic, System Center, Satellite, Chef, Casper, Puppet or homegrown scripts - software should be orchestration friendly.

Centrify Server Suite for UNIX, Linux, and Mac offers a facility that should be leveraged by any savvy IT infrastructure team.  The tool is a script called install.sh.

This script is shipped with the gzipped tarball for Centrify software, for example, here are the listings for a RHEL-based system (excluding the release notes):

  • adcheck-rhel4-x86_64
  • centrifyda-3.2.3-rhel4-x86_64.rpm
  • centrifydc-5.2.3-rhel4-x86_64.rpm
  • centrifydc-install.cfg
  • centrifydc-ldapproxy-5.2.3-rhel4-x86_64.rpm
  • centrifydc-nis-5.2.3-rhel4-x86_64.rpm
  • centrifydc-openssh-6.7p1-5.2.3-rhel4-x86_64.rpm
  • centrify-suite.cfg
  • install-express.sh -> install.sh
  • install.sh

Note that all the installation bits are shipped in the native package manager or the platform, this gives the opportunity to the administrator to bypass install.sh and use the native installer.  E.g.  to install only the base agent, you can run

rpm -Ivh centrifydc-5.2.3-rhel4-x86_64.rpm

Many admins just simply add the RPMs to their repositories and can use facilities like yum to install or maintain the package.

Capabilities of install.sh

  • Interactive install/join operations:  walks the user through a series of menus and options
  • Automatic with command options:  can be run manually or by an orchestration facility for installations and joins.
  • Automatic with an answer file:  any of the .CFG answer files can be used with install.sh
  • Kerberized:  install.sh calls adjoin and other utilities that can benefit from Kerberos keytab preauthentication.

What does install.sh do?

install.sh is a script;  it acts as an abstraction layer between the package manager of the native OS and any other tool or manual script.  This is very powerful because eliminates the nuances related to each operating system, architecture or distribution.

For example, some AIX systems use the installp facility, RHEL and derivatives use RPM, Debian derivatives like Ubuntu use dpkg, OS X systems use Install.app and so on;  install.sh allows for the administrator to have a QA tested way to install Centrify software and perform additional tasks.


When preparing for a release, Centrify will QA install.sh against all the supported platforms.


Basic Automation Playbook

What you need:
a) The keytab for an AD user that can join systems (or remove them) to the target OUs
For more info on how to create this, click here.
b) A krb5.conf file for a working system
d) Install.sh (or the native package manager utility)
e) If not using install.sh, you'll need adjoin (or adleave)

Sample Command Sequences

Sample 1:  In this sequence, we use an /temp/ad-joiner keytab with a /temp/krb5.conf and we'll use install.sh to install standard edition and join a zone called  myzone in the acme.test domain in the "My Servers" OU.

env KRB5_CONFIG=/temp/krb5.conf  /usr/share/centrifydc/kerberos/bin/kinit -kt /temp/ad-joiner.keytab ad-joiner

 ./install.sh  --std-suite  --adjoin_opt="acme.test -z myzone -c acme.test/My\ Servers"


Sample 1:  In this sequence, we use an /temp/ad-joiner keytab with a /temp/krb5.conf and we'll use install.sh to install standard edition and join a zone called  myzone in the corp.contoso.com domain in the "My Servers" OU.

env KRB5_CONFIG=/temp/krb5.conf  /usr/share/centrifydc/kerberos/bin/kinit -kt /temp/ad-joiner.keytab ad-joiner

 ./install.sh  --std-suite  --adjoin_opt="corp.contoso.com -z myzone -c corp.contoso.com/My\ Servers"

Sample 2:  In this sequence, we use an /temp/ad-joiner keytab with a /temp/krb5.conf and we'll use rpm to install the standard package and adjoin to join the Global zone in the corp.contoso.com domain and put the computer under the Centrify\Servers OU.

env KRB5_CONFIG=/temp/krb5.conf  /usr/share/centrifydc/kerberos/bin/kinit -kt /temp/ad-joiner.keytab ad-joiner

rpm -Ivh centrifydc-5.2.3-rhel4-x86_64.rpm

adjoin -z Global -c "ou=servers,ou=centrify" corp.contoso.com


install.sh Help file

This script installs (upgrades/uninstalls) Centrify Suite.
Only the superuser can run this script.

Usage:
  install.sh [-n|--ent-suite|--std-suite|--express] [-e] [-h] [-V] [-v ver] [-l log_file]

where:
  -n             Custom install/upgrade/uninstall in non-interactive mode.
  --ent-suite    Install Enterprise Suite in non-interactive mode.
  --std-suite    Install Standard Suite in non-interactive mode.
  --express      Install Centrify Express in non-interactive mode.
  --bundle       Install Centrify Suite using bundle.
  --suite-config <config_file>
                 Override default suite config file with <config_file>.
  -e             Uninstall (erase) CentrifyDC.
  -h, --help     Print out this usage and then exit.
  -V             Print out installer version and then exit.
  -v <ver>       Install CentrifyDC <ver> version.
                 Format: x.x.x or x.x.x-xxx. x is number.
  -l <log_file>  Override default log-file PATH with <log_file>.
  --rev <rev>    Package OS revision to install.
  --custom_rc    Return meaningful exit code.
  --override="<options>"
                 In non-interactive mode, override default options with <options> list.
                 Format: --override="CentrifyDC_openssh=n,CentrifyDA=R"
  --adjoin_opt="<adjoin_options>"
                 Override default adjoin command line options with <adjoin_options>.
  --enable-da    In non-interactive mode, once joined to a domain,
                 enable DA for all shells.
  --disable-da   In non-interactive mode, disable DA NSS mode after install.

Examples:
  ./install.sh        -n  --override="INSTALL=R,CentrifyDC_nis=Y,CentrifyDC_openssh=N,CentrifyDA=N"
  ./install.sh        --std-suite  --adjoin_opt="acme.test -p pass\$ -z t_zone -c acme.test/My\ Servers"
  ./install-bundle.sh --std-suite "--adjoin_opt=\"acme.test -p pass\\$ -z t_zone -c acme.test/My\\ Servers\""