tl;dr: Implementing CFEngine policy server, storing policy in a local git repo.
If you maintain one or more Unix boxes, you can benefit from a configuration management system. Want to make sure the root password is changed, on all your systems, to the same new password, securely and automatically? Piece of cake! Want to change an option in all of your sshd config files? No problem! Want to update OpenSSL so that it's not vulnerable to HeartBleed? Totally doable!
I've made several attempts over the past few years to implement a configuration management (CM) system on my home network. I know it's a long- (and even medium-) term win once implemented, but I always seem to run up against one issue or another which derails my progress. I think the underlying problem for me is that I want my network to be "perfect" as soon as I begin implementing CM; instead, what I should focus on is converging on a well-managed network. After all, today's best practice might very well become tomorrow's flawed implementation, so "perfection" is a moving target.
When I first started looking at Open-source CM systems (10 years ago?), I chose CFEngine for the following reasons:
It's mature -- CFEngine has been around for decades(!). It's not quite as old as Unix itself, but it's definitely in the tried-and-true range.
Few dependencies -- You don't need to install a bunch of other software in order to get CFEngine up and running.
Good theoretical underpinning -- Promise Theory underlies everything in CFEngine. All the systems taking part in a configuration are cooperating (rather than coerced) to achieve a desired state, or at least move toward the desired state.
Here's the (short) list of prerequisites I have before installing CFEngine on my network.
I'll be using an old desktop for my policy server, (Pentium 4 @ 2.8 GHz with 2 GiB RAM). I've set up my DHCP server to give this box a static IP address. There is (was?) a bug in CFEngine that would cause the policy server's IP address to be effectively hard-coded into the network configuration upon the first connection. (My Google-fu is not strong, not finding a reference to it right now.) So I want to give my policy server a well-known, "permanent" IP address.
I installed CentOS version 6 on this system, because it doesn't have a 64-bit processor. (CentOS 7 doesn't seem to play nice with an old 32-bit CPU.) Probably any Linux, BSD, or other Unix variant would work for this. I chose CentOS to gain some more experience with it, and add some heterogeniety to my network.
During installation, I created a user account and added it to sudoers.
After this, just make sure that wget is available:
You should see output like this:
Okay, ready to rock! Here's the 1-line command to install CFEngine:
$ wget -O- http://cfengine.package-repos.s3.amazonaws.com/quickinstall/quick-install-cfengine-community.sh | sudo bash
That should get everything installed. You'll probably see a message: Complete! Ready to bootstrap... DON'T DO IT YET!
(Here is a more detailed CFEngine installation tutorial, if needed).
I want to have my policy files under revision control, so that I can keep track of changes, undo things that break my network, and hopefully test changes before they cause breakage! I'm using git just to get more experience with it. I'll sort of follow the CFEngine VCS guide. But they use github as a repository server--I don't have a paid github account, and I don't want my policy files to be world-readable, so I'll set up a private git repository on my network.
Git isn't installed yet, and I don't have CFEngine running to do that for me, so I'll install it manually:
I set up git-daemon (git repository server) on a separate box, without SELinux enabled (currently). The git server offers read-only access -- I'll use ssh to control write access to the server/repo. The git server is running under my non-privileged account on that box, which means I can manipulate the repository and edit the policy files therein, without having to su/sudo constantly.
ssh [email protected] $ mkdir -p $HOME/git_depot/cfe-home-master.git $ cd $HOME/git_depot/cfe-home-master.git $ git init --bare
The trailing '.git' in the directory name is conventionally used to indicate a "bare" repository, i.e. it doesn't contain a working copy. Shared repositories are normally bare, regardless of how they're served/shared: nfs, git-daemon, file server, http, etc. Note that the filename doesn't turn this into a bare repo, it's merely a naming convention.
Now let's turn the freshly-installed out-of-the-box policy files into a git repo, then push that up to the new repository:
(on the new policy server) $ sudo bash # cd /var/cfengine/masterfiles/ # git init # echo cf_promises_release_id >>.gitignore # echo cf_promises_validated >>.gitignore # git remote add origin ssh://[email protected]/home/me/git_depot/cfe-home-master.git/ # git push -ff origin master
Okay, at this point there are two repositories: The one on the policy server (which has a working directory, but no origin), and the remote/bare repo (which I want to become the "authoritative" one). See Version Control with Git, 2009, pp. 187-8, "Make Your Own origin Remote", for background.
(back on the git server...) $ pwd /home/me/git_depot/cfe-home-master.git $ touch git-daemon-export-ok $ git daemon --reuseaddr --verbose --base-path=$HOME/git_depot -- $HOME/git_depot/cfe-home-master.git
Yes, I am running git-daemon interactively. No, this is not perfect -- see the Background section. But it'll do for now, and I can fix it (with CFEngine!) later. First, let's test the git-daemon. On the policy server, do an "ls-remote":
# git ls-remote git://my.git.server/cfe-home-master.git/ b0b723fa8c254f5a923c101a271a38383e4c5cf4 HEAD b0b723fa8c254f5a923c101a271a38383e4c5cf4 refs/heads/master
Works! You should also see some output on the interactive git-daemon server.
Now let's point the masterfiles/ directory on the policy server to the new git-daemon. We just need to update the policy server's remote:
# edit .git/config ### (remove the '[remote "origin"]' section, including 'url=...' and 'fetch=...' lines) # git remote add origin git://my.git.server/cfe-home-master.git/ ### test! # git remote update # git branch -a * master remotes/origin/master
Bootstrapping the policy server
Remember the Complete! Ready to bootstrap... message from earlier? Time to get that done! We're still root on the policy server:
# /var/cfengine/bin/cf-agent --bootstrap my.policy.server
You'll see a bit of output, ending with:
Bootstrap to '(ip.address)' completed successfully!
Congratulations! Your policy server is up and running, and you're now well on your way to a more perfect network.
This post is getting pretty long, but I've still got plenty to do. Take a quick glance at this post and you'll notice that the bulk of it has to do with setting up the git server. If a Version Control System (VCS) server was already available (as my dhcp server was), this would have been considerably shorter! Getting CFEngine installed and bootstrapped is really only 2 commands. So if you're willing to hold off on version control for your policy files, you can get this going pretty quickly and easily.
Next step will be adding another system to my configuration. Once you have a real network, (more than just one box), adding more systems is just a matter of "more of the same".
After that second system is on my network, I'll probably write about how I handle my git repo, e.g. branch naming, testing, and merging.