CFEngine recently released version 3.6, which makes deploying and using cfengine easier than ever before. The greatest improvement in 3.6, in my opinion, is by far the autorun feature. I’m going to demonstrate how to get a policy server set up with autorun properly configured.
Installing CFEngine 3.6.2
The first step is to install the CFEngine package, which I’m not going to cover. But I will say that I recomend using an existing repository. Instructions on how to set this up are here. Or you can get binary packages here. If you’re not using Linux (like myself) you can get binary packages from cfengineers.net.If you’re inclined to build from source I expect that you don’t need my help with that. Having installed the CFEngine package, the first thing to do is to generate keys. The keys may have already been generated for you, but running the command again won’t harm anything.
/var/cfengine/bin/cf-key
Setting up Masterfiles and Enabling Autorun
Next you’ll need a copy of masterfiles
. If you downloaded a binary
community package from
cfengine.com you’ll find a
copy in /var/cfengine/share/CoreBase/masterfiles
. As of 3.6 the policy
files have been decoupled from the core source code distribution so if
you’re getting CFEngine from somewhere else it may not come with
CoreBase
. In this case this you’ll want to get a copy of the
masterfiles repository at the
tip of the branch for your version of CFEngine (in this case, 3.6.2),
not from the master branch where the main development happens. There’s
already development going on for 3.7 in master so for consistency and
repeatability grab an archive of 3.6.2. Going this route you also need a
copy of the CFEngine core
source code (although you do not need to
build it).
curl -LC - -o masterfiles-3.6.2.tar.gz https://github.com/cfengine/masterfiles/archive/3.6.2.tar.gz
curl -LC - -o core-3.6.2.tar.gz https://github.com/cfengine/core/archive/3.6.2.tar.gz
tar zxf masterfiles-3.6.2.tar.gz
tar zxf core-3.6.2.tar.gz
You’ll now have the main masterfiles
distribution unpacked. This isn’t
something that you can just copy into place, you need to run make
to
install it.
cd masterfiles-3.6.2
./autogen.sh --with-core=../core-3.6.2
make install INSTALL=/opt/local/bin/install datadir=/var/cfengine/masterfiles
Note: Here I’ve included the path to install
. This is required for
SmartOS. For other systems you can probably just run make install
. At
this point it’s time to bootstrap the server to itself.
/var/cfengine/bin/cf-agent -B <host_ip_address>
You should get a message here saying that the host has been successfully
bootstrapped and a report stating ‘I’m a policy hub.’ To enable autorun
simplet make the following change in def.cf
.
- "services_autorun" expression => "!any";
+ "services_autorun" expression => "any";
Note: There’s a bug in masterfiles-3.6.0, so make sure to use at least 3.6.2.
Using Autorun
With the default configuration autorun will search for any files in
services/autorun/
with the tag autorun
and execute it. At this point
you can see autorun working for yourself.
/var/cfengine/bin/cf-agent -K -f update.cf
/var/cfengine/bin/cf-agent -Kv
Here I’ve enabled verbose mode. You can in the verbose output that
autorun is working. Now, like Han Solo, I’ve make a couple of special
modifications myself. I also like to leave the default files in pristine
condition, as much as possible. This helps when upgrading. This is why
I’ve only made very few changes to the default polcies. It also means
that instead of using services/autorun.cf
I’ll create a new autorun
entry point. This entry point is the only bundle executed by the default
autorun. I’ve saved this to services/autorun/digitalelf.cf
body file control
{
agent::
inputs => { @(digitalelf_autorun.inputs) };
}
bundle agent digitalelf_autorun
{
meta:
"tags" slist => { "autorun" };
vars:
"inputs" slist => findfiles("$(sys.masterdir)/services/autorun/*.cf");
"bundle" slist => bundlesmatching(".*", "digitalelf");
methods:
"$(bundle)"
usebundle => "$(bundle)",
ifvarclass => "$(bundle)";
reports:
inform_mode::
"digitalelf autorun is executing";
"$(this.bundle): found bundle $(bundle) with tag 'digitalelf'";
}
This works exactly the same as autorun.cf
, except that it looks for
bundles matching digitalelf
and only runs them if the bundle name
matches a defined class. Also note that enabling inform_mode
(i.e.,
cf-agent -I
) will report which bundles have been discovered for
automatic execution. For example I have the following
services/autorun/any.cf
.
bundle agent any {
meta:
# You must uncomment this line to enable autorun.
"tags" slist => { "digitalelf" };
vars:
linux::
"local_bin_dir" string => "/usr/local/bin/";
smartos::
"local_bin_dir" string => "/opt/local/bin/";
files:
"/etc/motd"
edit_line => insert_lines("Note: This host is managed by CFEngine."),
handle => "declare_cfengine_in_motd",
comment => "Make sure people know this host is managed by cfengine";
}
Since the tag is digitalelf
it will be picked up by
services/autorun/digitalelf.cf
and because bundle name is any
, it
will match the class any
in the methods promise, and therefore run.
You can drop in bundles that match any existing hard class and it will
automatically run. Want all linux
or all debian
hosts to have a
particular configuration? There’s a bundle for that.
Extending Autorun
You may already be familiar with my cfengine
layout
for dynamic bundlesequence and bundle layering. My existing dynamic
bundlesequence is largely obsolete with autorun, but I still extensively
use bundle stack layering. I’ve incorporated the classifications from
bundle common classify
directly into the classes:
promises of
services/autorun/digitalelf.cf
. I can trigger bundles by discovered
hard classes or with any user defined class created in bundle agent digitalelf_autorun
. By using autorun bundles based on defined classes
you can define classes from any source. Hostname (like I do), LDAP, DNS,
from the filesystem, network API calls, etc. This article was submitted
by Brian Bennett, a Vertical
Sysadmin consultant and trainer