published on 4 August 2016

Editor's Note: This post is a taste of what you'll get in our ebook about about automating routine IT tasks with Puppet, The Top 5 Things to Automate with Puppet Right Now. Download it for free to read the rest.

Puppet makes managing your infrastructure quick and easy. But where do you start? In this series we’ll show you five common processes you can automate right away to start streamlining infrastructure management.

Common tasks

You’ll be tempted to tackle the most painful tasks first, but hang on. It would be great to automate that incredibly painful deployment process on the AS/400 that’s somehow still running critical infrastructure. But the project will take tons of time and won’t really pay off in the long run. Instead, start with tasks you do all the time. The new time gained will free you up to focus your attention on improving your existing processes.

Task 1: Standardize service accounts

Many IT organizations manage local service accounts on servers. Not only do you likely have a handful of service accounts distributed across your various OSes, they probably don’t have consistent user identifications (UIDs), group memberships, SSH keys, etc.

Luckily, Puppet built a module to solve the problem — the accounts module. The accounts module provides a simple way to standardize service accounts across all of your *nix operating systems.

Add the following to your puppetfile:

mod 'puppetlabs/stdlib',   '4.12.0'
mod 'puppetlabs/accounts', '1.0.0'

Create site/profile/manifests/base.pp if it does not already exist. This will be a profile that we apply to all servers as part of their base configuration. You can think of this as the standard operating environment (SOE). This profile will be included as part of our roles, which we will discuss later on.

A profile is a reusable block that you can use to build different types of servers. The place we pull those blocks together is called a role. Each server gets one role, and that role consists of many profiles (i.e., building blocks) to create that server.

Create the base shell of your profile:

class profile::base {
  #the base profile should include component modules that will be on all nodes
}

Let's now create a role for our Puppet master. Create site/role/manifests/master.pp if it does not already exist and include our first class:

class role::master {
  # Here we include all of the profiles that make up a Puppet master
  # for now it's just the base (the SOE) but we will probably add more later
  include profile::base
}

Now deploy your code to the Puppet master.

The last thing we need to do with our role is assign it to the Puppet master. We will do this by going into the Puppet Enterprise console, clicking Nodes > Classification > Add Group... This will allow us to add a group for our master and assign our new role to it.

Create a group called Puppet masters. Click the newly created group from the list and, under Pin specific nodes to the group, open it up, add your Puppet master and click Pin. Now go to the Classes tab and add your new role. If it is not available yet, you may need to click the refresh button in the middle right portion of the screen. Once you have added the master role, click Commit Changes.

Now that we have done this, we are almost ready to test it out. Let's create a test account called monitoring in our base profile:

class profile::base {
  accounts::user { 'monitoring':
    managehome => false,
  }
}

This will create a monitoring user (but not a home directory) on all the machines with the base profile. Add, commit and push your code, then deploy it to the master.

Run puppet agent -t.

We should see something like this in our logs:

Notice: /Stage[main]/Profile::Base/Accounts::User[monitoring]/Group[monitoring]/ensure: created
Notice: /Stage[main]/Profile::Base/Accounts::User[monitoring]/User[monitoring]/ensure: created

We can also view the status of this run in the console by clicking view graph on the Puppet master. This will show us everything that Puppet is managing; the resources relating to our new monitoring user will come up as blue dots since they were changed in the last run.

We have now created a user as part of our SOE, and any machines with roles that include the profile::base class will also have this user (currently only the Puppet master).

However, this is not a very good service account. We are not managing the UID (user identifier) or GID (group identifier), meaning that they will most likely be different across machines. Plus, the user is allowed to log in, which is probably not what we want. Let's go ahead and fix that:

class profile::base {
  accounts::user { 'monitoring':
    ensure     => present,
    uid        => '450',
    gid        => '450',
    managehome => false,
    locked     => true,
  }
}

Now deploy your code and run Puppet using puppet agent -t.

You should see output that looks like this:

Notice: /Stage[main]/Profile::Base/Accounts::User[monitoring]/Group[monitoring]/gid: gid changed '1003' to '450'
Notice: /Stage[main]/Profile::Base/Accounts::User[monitoring]/User[monitoring]/uid: uid changed '1003' to '450'
Notice: /Stage[main]/Profile::Base/Accounts::User[monitoring]/User[monitoring]/shell: shell changed '/bin/bash' to '/sbin/nologin'

We can see that Puppet has now amended the GID and UID for our monitoring user and disallowed the user from logging in by changing the shell from /bin/bash to /sbin/nologin.

All we need to do now is apply this to all our servers, and we will have a standardized monitoring service account with exactly the same GID and UID across all servers.

One neat benefit of the accounts module is the ability to get rid of passwords. Since the module provides a central point of management for SSH keys, passwords can be disabled on the accounts and SSH keys used instead. This makes it trivial (and auditable) to revoke access on a per-key basis, instead of having to globally change a password every time an employee who knows the password leaves the company.

A good use of this is to create a backup account that can be used to log into servers if LDAP (lightweight directory access protocol) is unavailable. Here we will add one such user to our base profile:

class profile::base {
  accounts::user { 'monitoring':
    ensure     => present,
    uid        => '450',
    gid        => '450',
    managehome => false,
    locked     => true,
  }

  accounts::user { 'emergency':
    ensure     => present,
    uid        => '460',
    gid        => '460',
    shell      => '/bin/bash',
    password   => '!!', # No password
    sshkeys    => [
      "ssh-rsa AAAA...",
      "ssh-rsa BBBB...",
      "ssh-rsa CCCC...",
      ],
  }
}

Under the sshkeys parameter, we have added the SSH keys of all sysadmins who should be able to log into that emergency account. If one of these sysadmins were to leave, all we would have to do is remove that key from the list, and their access would be revoked without having to log into each machine.

And that’s it, you’ve successfully automated service accounts with Puppet. Watch this space for the rest of our series to learn about other common processes you can automate with Puppet.

Dylan Ratcliffe is a professional services engineer at Puppet.

Learn more

Share via:
Posted in:

Add new comment

The content of this field is kept private and will not be shown publicly.

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.