Mon, 14 Mar 2011
Find Unpuppeted SSH Keys
It all started with one of those annoying little items on the todo list
- find all the unpuppeted ssh authorized_keys files on a machine and
alert on them. On first impressions it was going to be quite manual
(always a bad sign), involve digging in to legacy installs and would be
something we'd need to re-verify occasionally. It couldn't be that bad
though could it? After all how many places can an unmanaged-by-
puppet sshkey live?
Essentially the task can be broken in to three main parts. The first, quite easy part, is to grab a list of all the users (hello /etc/passwd) and look for known key file names in their home directories. The second part, which was a little harder, is to build a list of all the authorized_keys files that puppet knows it's managing for this host. Lastly once you have the two collections find the differences. Instead of doing static analysis on the puppetmasters classes and modules we're going to focus on how to do it using the compiled desired state of what the local machine should look like, according to the puppet catalog.
The catalog (which lives at /var/lib/puppet/client_yaml/catalog/$fqdn.yaml in modern puppet) is a yaml-based representation of what puppet knows about how the local system should be configured. It contains details of all the resources to be managed on the local machine and their desired end state; which makes it perfect for our needs. I'm not going to go into the catalog in depth in this post but hopefully this little example will whet your appetite and spark some ideas.
Our example, the audit-sshkey-files nagios check, was actually quite easy to write (after some digging in to puppet and borrowing some code from Puppet Catalog Diff by R.I.Pienaar) and should hopefully show how much you can gain from using the meta-data puppet provides.
While most of the audit-sshkey-files script is boilerplate the most important snippet is below:
if target.type == "File" and target.title.include? "/authorized_keys"
@puppet_keys.push target.title
return target.title
end
All we're doing is building a list of any resources that are of type file and include the string "/authorized_keys" in their name (resource title in puppet terms). While this may not seem like much it's potentially game changing, any resources or relationships that you've modelled in puppet can be later mined to add context to your other tools. You can (as we have here) audit security related files or find user ids puppet doesn't know about and so might be inconsistent over systems. By using the catalog and the relationships and meta-data it provides you can make much more of your investment in deploying systems with puppet, and hopefully this little example presents an easy way to get started.
Now I've gushed about what the puppet catalog can do for you there are two caveats, firstly about my example. It isn't a complete solution, for example it doesn't look for other allowed "authorized_keys" filenames that are defined in the sshd_config file. But it does the 80% of what I needed in our environment and by managing the sshd_config file in puppet (as you should be) it's easy for me to double check I'm looking for the correct files. Secondly about the Puppet catalog itself. Harnessing its contents doesn't exactly have a shallow learning curve and documentation is a little thin on the ground. The original author of puppet Luke Kanies is working on some alternative ways of accessing this kind of information (such as via his Puppet Interfaces project) and as more people build their puppet deployments you can expect so see more and more harnessing of this additional structure.
Like this post? - Digg Me! | Add to del.icio.us! | reddit this!
Posted: 2011/03/14 23:30 | /tools/puppet | Permanent link to this entry | This entry and same date
Reusing Puppets Package providers
One of puppets more under-appreciated features is its ability to abstract
and smooth the edges of certain operating system tasks and behaviours.
Even something as trivial as installing a package can actually become a
portability nightmare once you consider the number of different systems
in the wild - rpm, yum, dpkg, pkgsrc etc. - and the varied commands
needed to use them. You end up either hard coding commands, and sacrificing
portability, or writing your own detection, lookup and invocation
logic.
That sounds like, dull, scut work so how does puppet deal with this? And how can we reuse this work to simplify our own code? In slightly simplified terms, Puppet has a package type, which is backed by a number of providers. Each of these providers actually implement the required functionality for a given package manager and contains all the code we need. So how do we harness this existing work? Quite easily. Luckily for us, puppets providers are written in ruby code and are simple to call in our own scripts:
# show package version
$ irb
irb(main):001:0> require 'puppet'
=> true
irb(main):002:0> Puppet::Type.type(:package).new(:name => "bash").provider.properties
=> { :provider=>:yum, :ensure=>"4.1.7-3.fc14", :release=>"3.fc14",
=> :arch=>"i686", :epoch=>"0", :name=>"bash", :version=>"4.1.7" }
# do the same thing with an explicitly specified provider.
irb(main):003:0> Puppet::Type.type(:package).new(:name => "bash", :provider => "rpm").provider.properties
=> { :provider=>:rpm, :ensure=>"4.1.7-3.fc14", :release=>"3.fc14",
:arch=>"i686", :epoch=>"0", :name=>"bash", :version=>"4.1.7" }
While that snippet will hopefully whet your appetite if you need a more worked example I've put a small Puppet Package Provider wrapper up on github. The script will enable you to do the basic install, update and delete without knowing or caring what the underlying package manager is. Hopefully these little code snippets will help you stop thinking of puppet as "just" a tool and show how parts of its code base can be used as a framework to improve other parts of your tool chain.
As an aside it's also worth mentioning that you can globally Change the Package provider in puppet if you're not happy with its auto-detection.
Like this post? - Digg Me! | Add to del.icio.us! | reddit this!
Posted: 2011/03/14 00:18 | /tools/puppet | Permanent link to this entry | This entry and same date

