Imagine this scenario: you have twenty servers under your care, some running Red Hat Linux, some running Solaris, and a few machines running Debian. You want to make sure that all of the systems have the same network configuration, but you don't want to log in to each machine and make the changes by hand. Unfortunately, you also know that it won't be easy to write a simple shell script to automate the task because each system's layout is a little bit different. Making simple changes to all machines on your network, without automation, can be quite a hassle. Happily, that's what Cfengine is for.
Imagine this scenario: you have twenty servers under your care, some running Red Hat Linux, some running Solaris, and a few machines running Debian. You want to make sure that all of the systems have the same network configuration, but you don’t want to log in to each machine and make the changes by hand. Unfortunately, you also know that it won’t be easy to write a simple shell script to automate the task because each system’s layout is a little bit different. Making simple changes to all machines on your network, without automation, can be quite a hassle. Happily, that’s what Cfengine is for.
Cfengine is a system that automates a number of system administration tasks across different versions of Linux, Unix, and even Windows if you’re using cygwin. In fact, you can even use Cfengine for tasks on a single machine or only on selected machines.
Cfengine isn’t an all-purpose programming language like Perl or Python and isn’t quite as flexible as shell scripting, but it handles a good number of common system administration tasks like editing text files, deleting unnecessary files, and mounting and unmounting filesystems. Using Cfengine, you can greatly reduce the amount of time you spend doing simple, repetitive tasks.
What is Cfengine?
Cfengine consists of several programs. Oddly enough, none of them are actually called “cfengine.” cfagent is the program that actually performs Cfengine functions — creating files, editing files, mounting disks, and so on. cfrun is used to run Cfengine on other machines. The Cfengine tools also include cfservd, the Cfengine daemon that listens for instructions from another machine, and cfexecd, a daemon scheduler that runs Cfengine at regular intervals.
cfagent has an entire control language that’s fairly robust. We’ll delve into it a bit in this column, but it’s far too complex to cover in a few pages. In fact, the Cfengine reference is more than 100 pages, so you’ll definitely want to set aside some time to familiarize yourself with all of its features once you finish this article. We’ll cover the basic syntax so you can pick up the rest on your own.
To install Cfengine from source, first install the Berkeley Database and OpenSSL (if your system doesn’t already have those packages). Next, you can download the source and documentation for Cfengine from its home page at http://www.cfengine.org. The most recent version of Cfengine (as we go to press) is 2.0.4, although 2.0.5 may be available by the time you read this.
Most Linux distributions have packages for Cfengine, though it usually isn’t installed by default. However, be careful! Several Linux distributions have packages for older versions of Cfengine. For example, Mandrake 9.0 comes with version 1.6.3, as does the stable release of Debian. There are significant improvements in the 2.0.x series of Cfengine, so make sure to download and install the latest code.
If you’re installing from source, follow the normal ./configure, make, make install routine. If you receive the error, “This release of cfengine requires BerkeleyDB 3.2 or later,” try ./configure –with-berkeleydb=/usr and Cfengine should compile fine.
After compiling the program, generate a key. To do this, run cfkey as root. cfkey creates and installs a public/private key pair.
Once you’ve compiled Cfengine, it’s time to get everything set up. When you run cfagent (or run it via cron), it expects a configuration/action file. If you installed Cfengine from source, cfagent should automatically look for its configuration file in /var/cfengine/inputs/cfagent.conf. (On Debian, it looks for /var/lib/cfengine2/inputs/cfagent.conf.) cfagent.conf is a list of commands for cfagent to carry out. Listing One shows the cfagent.conf syntax.
Listing One: The cfagent syntax
domain = ( mydomain.com )
timezone = ( MST )
access = ( root bob ginny )
actionsequence = ( checktimezone tidy)
# get rid of files more than 14 days old.
/tmp/ pattern=* r=inf age=14
The control: section contains general information like your domain name, time zone, and which users are allowed to run cfagent. actionsequence tells cfagent what to do and the order to do it in.
As you might imagine, the checktimezone function simply confirms that the system time zone is set correctly. The next function, tidy, removes files that are no longer necessary. However, cfagent needs some guidance to determine which files to remove. That’s what the tidy: section is for. You specify an absolute path, a pattern to match filenames, and some filters.
Here, the path is /tmp/ (again, the path must be absolute, so you’ll want to use /tmp/ instead of tmp/). pattern specifies “any file” (the wildcard, * means “any”) and age=14 filters “any” to only those files that are older than fourteen days.
You can add a comment to the file by preceding the comment with a hash (#).
There are about twenty actions that can be carried out by cfagent, including mounting and unmounting file systems, editing files, checking or sending a signal to a process, running shell scripts, or executing a user-defined Cfengine module. Unfortunately, we can’t cover them all here, but they are covered in the Cfengine documentation.
If you want to be notified via email whenever Cfengine completes its tasks, you can add the following to the control section of your cfagent.conf file:
Once you’ve finished your configuration, run cfagent -v from the command line to check that everything is OK.
Editing Files Using Cfengine
Another task that can be done quite easily with Cfengine is editing system files. Since Linux and Unix systems use plain-text files almost exclusively, there’s quite a bit you can do with Cfengine when it comes to system configuration.
To edit a file, use the editfiles directive. Here’s a small example, using the append function:
actionsequence = ( editfiles )
AppendIfNoSuchLine “It’s sys admin appreciation day!”
This editfiles configuration tacks on the line It’s sys admin appreciation day! to the end of /etc/motd, providing the line doesn’t exist.
There are many file editing directives in addition to AppendIfNoSuchLine. See the Cfengine reference for a complete list.
Setting Permissions Using Cfengine
Let’s say you manage an FTP server. From time to time, you probably verify the permissions on the server to ensure that what’s private is still private and what’s public is indeed available for all to access. With Cfengine, you can do that automatically.
To verify files, use the files directive. Here’s a brief example of changing a directory’s permissions:
actionsequence = ( files )
/var/www/cgi-bin mode=0755 r=0 o=root g=root act=fixall
In the example, the directory is /var/www/cgi-bin. We want to make sure that the permissions are set correctly to (octal) mode 0755. The next bit, r=0 is a tad more cryptic. r= is the recursion option, which is set to 0 in this example. Only the mode of /var/www/cgi-bin is checked (and possibly altered) and nothing more. If you wanted to work with /var/www/ cgi-bin and its immediate child directories, you could set the value to 1. If you want to work with all subdirectories, then set the value to inf which tells the program to work with any depth of subdirectories. If you look back at Listing One, you can see r=inf was specified for the tidy command.
The next two options, o= and g=, specify the owner and group for the file in question. Finally, the act option tells the program to fix the permissions if they do not match the specified permissions, group, and owner.
The files directive can also be used for several other tasks. Essentially, you can perform almost any action that requires manipulating a file or verifying its existence and permissions. If you need to touch a file to change its timestamp, create a new file, or just issue a warning if a file doesn’t exist or match certain parameters, the files directive can help automate the task.
Running Cfengine on Remote Hosts
So far, we’ve only covered running Cfengine on the local machine. While that might be useful for some tasks, it’s hardly exciting. Remember, the power of Cfengine is its ability to perform tasks on a number of different systems from one machine.
Instead of running the cfagent command, use cfrun. Before you can use cfrun, however, you need to have a configuration file called cfrun.hosts, which should be located in the same directory as cfagent.conf. Alternatively, you can specify a cfrun.hosts file on the command line using cfrun -f cfrun. hosts, though the file can actually be called anything you want.
The cfrun.hosts file is pretty minimal: just specify your domain and the hosts that you want to invoke Cfengine on. So, you’ll have something like this:
domain = mydomain.com
Other options can be used in the cfrun configuration file, but the only elements that are absolutely necessary are your domain and the hosts. Notice that you don’t need to provide fully-qualified domain names; the host name alone is sufficient.
You’ll also need to have cfservd running on hosts that are to take commands from the main server running Cfengine. Without cfservd, you have to run cfagent by hand, which kind of defeats the point of installing it. The cfservd daemon has its own configuration file, cfservd.conf, which also lives in your inputs directory.
The syntax for cfservd.conf is similar to cfagent.conf, but contains different information. Here is an example cfservd.conf file:
domain = ( myhost.mydomain.com )
AllowConnectionsFrom = ( 10.0.0.4-15 )
AllowUsers = ( root bob )
LogAllConnections = ( true )
MaxConnections = ( 5 )
domain is the domain of the host machine that cfservd is running on. The next directive, AllowConnectionsFrom, specifies a single IP address or a range of addresses that are allowed to connect. If you want to log connections to your machine (a good idea), set LogAllConnections to true. Again, there are many more directives that you might wish to use in this configuration file — check the Cfengine reference documentation for the full list.
Also, don’t forget that you’ll need to have an entry in /etc/services to register a port for Cfengine. The default is cfengine 5308/tcp. This entry should be added during installation, but check to make sure.
But beware! There is the possibility that a malicious user could “spam” a machine by running cfrun against a machine with a listening cfservd running. While it will only run the configuration that you’ve set up, it’s possible that someone could try to slow a system down by running cfagent continually. By default, cfagent has a minimum amount of time that it will wait before running again. However, the default is one minute, so that could be abused. To set a longer period of time, you can set a global time limit or a time limit on each action. To set a global limit, put this in your control section:
IfElapsed = ( 30 )
ExpireAfter = ( 240 )
The first value is the minimum amount of time that cfagent should wait before starting again in minutes. The second value is the amount of time to wait before cfagent kills an old instance of cfagent and starts fresh. If you’d prefer, you can set specific times for each action rather than a global time limit, like this:
Using this configuration, cfagent will wait the default amount of time before performing actions associated with files, but will use the specified times for tidy and copy.
If you want to set up Cfengine to perform tasks at regular intervals, set up a cron job using cfexecd. To do this, just add the following line (or something similar) to the root crontab on your system:
* 1 * * * /usr/local/sbin/cfexecd -F
Make sure that /usr/local/sbin is the actual location of cfexecd on your system. The -F option prevents cfexecd from forking.
As you can see, Cfengine is a useful program to have at your disposal. The Cfengine website has some useful documentation, including a 114-page PDF tutorial and a 168-page PDF Cfengine language reference. Download those, review the papers on the Web site, and start automating those menial chores today.
Joe “Zonker” Brockmeier is a freelance author who writes about Linux and related technologies and regularly contributes to Linux Magazine. He can be reached at email@example.com.
Joe 'Zonker' Brockmeier
is a freelance writer and editor with more than 10 years covering IT. Formerly the openSUSE Community Manager for Novell, Brockmeier has written for Linux Magazine, Sys Admin, Linux Pro Magazine, IBM developerWorks, Linux.com, CIO.com, Linux Weekly News, ZDNet, and many other publications. You can reach Zonker at
firstname.lastname@example.org and follow him on Twitter