Automate Linux Configuration with cfengine

By Carla Schroder | Sep 6, 2005 | Print this Page
http://www.enterprisenetworkingplanet.com/netsysm/article.php/3532391/Automate-Linux-Configuration-with-cfengine.htm

As your Linux/Unix network grows, you're probably going to get tired of running around to individual machines to do updates and fixes, unless it's part of your fitness program. My ideal sysadmin scenario is rather like Dr. Evil's submarine lair: lounge about with a cat on my lap, occasionally pushing a button. Only I have no grand ambitions to conquer the world; I just don't like doing my modest chores the hard way. Cfengine (Configuration engine) is just the tool for streamlining hardworking system and network administrator's lives.

Cfengine is great for all Linux/Unix systems -- no more do you have to choose between scripting for portability or writing mounds of specialized scripts, because cfengine automates administration chores across a mixed *nix environment. The larger your network grows, the more you'll like cfengine. Cfengine has two primary uses:

  • Pushing out changes to all hosts on a network, regardless of operating system or hardware configuration.
  • Automatically keeping all systems in a correct, stable state.

Those of you who are daring and bold can even use cfengine to edit the Windows Registry, and maintain Windows hosts just like your *nix hosts. I am not quite so bold, and will talk about *nix systems only.

Some of the things that cfengine does are keep junk files cleaned off systems, maintain correct file ownership and permissions, create and maintain symbolic links (quite handy for creating uniform file locations across diverse systems), and keep network interfaces configured correctly. It uses a class structure, which means you're not faced with creating individual configurations for every host on your network, but for clumps of machines, categorized in whatever way makes sense for you -- operating system, server type, any kind of characteristic that cfengine can be configured to recognize. (This will be covered in more detail in part 2.)

The cfengine documentation is voluminous and detailed; it installs locally under /usr/share/doc/cfengine/. We'll walk through a simple setup and configuration step-by-step on just the server; next week we'll add clients. Be sure to install cfengine 2.x, as it is greatly improved over 1.x. You'll find it in RPM packages, Debian repositories, and the usual source tarballs. On Debian the documentation is in a separate cfengine2-doc package. Eventually cfengine needs to be installed on all hosts, but for now we'll just play with the server.

Make sure none of the cfengine daemons are running; for now we'll stick to manual testing. We'll create the necessary cfengine server configuration files, then test our configurations locally.

Central Server
Any host running cfengine can be a cfengine server, which offers all kinds of flexibility, and all kinds of confusion. It is best to stick with a single central master cfengine server until your cfengine skillz are well-honed.

Cfengine Files
The three most important executables are:

  • cfservd, the cfengine daemon. Must be running on all hosts, uses port 5308
  • cfagent, performs the actual changes on hosts
  • cfexecd, the cfengine scheduler

Also important are

  • cfrun, pushes updates to clients
  • cfkey, the encryption key generator
Understanding the cfengine file structure is a common point of confusion. There were changes between cfengine upgrades, which messes up older howtos. And various Linux distributions have their own ideas about where to put them. Red Hat EL4 uses /var/cfengine. Debian uses /var/lib/cfengine2. I'm sure there are good reasons for the differences. (Yeah. Sure.) And they may be symlinked to /etc/cfengine or other interesting locations, so be prepared for anything. This is the cfengine directory structure as described in the cfengine documentation:

/var/cfengine
  /bin, contains executables
  /inputs, configuration files live here
    cfagent.conf, performs the actual changes on each host
    cfservd.conf, controls the cfservd daemon
    cfrun.hosts, list of participating hosts
    update.conf, used by cfagent on the master server to copy configuration files and binaries into the correct locations on servers and clients
  /outputs, home of logfiles
  /ppkeys, encryption keys

Configuring the Server
You can copy and use these files, making sure to use your own filepaths and domain name. I don't have space to describe all the options; anything that doesn't make sense is explained in the Tutorial or Reference Manual. Let's start with cfservd.conf. This controls the main server daemon, cfservd. The example is from a Debian Sarge installation:

#################################
# /var/lib/cfengine2/cfservd.conf
#################################

control:
  domain = ( carla.com )
    # use the full path
    cfrunCommand = ( "/usr/sbin/cfagent" )

any::
  IfElapsed = ( 1 )
  ExpireAfter = ( 15 )
  MaxConnections = ( 50 )
  MultipleConnections = ( true )

#################################

grant:

  # Grant access to all hosts at carla.com
  # Files should be world readable
   /var/lib/cfengine2/masterfiles/inputs *.carla.com
  # Allow remote systems to execute the cfagent command using cfrun
  /var/lib/cfengine2/bin/cfagent    *.carla.com

#################################

Continued on page 2Continued From Page 1

First, a couple of syntax notes. Whitespace is mostly irrelevant, except that parentheses must be surrounded by spaces, except when they enclose variables like in update.conf. Comments are indicated by the customary hash marks.

The control section defines global variables and default values. A control section is required, or else cfengine won't run. All hosts on carla.com are allowed to download the master cfengine configuration files using cfagent.

any:: is our introduction to cfengine's classes. The double colon indicates that whatever follows applies only to the named class. "Any", of course, means all hosts. Cfengine has a number of built-in classes, such as linux, solaris, and redhat (see the Reference manual), and users can define their own classes.

IfElapsed limits the maximum number of times a command can be run; in this example, no more than once per minute. cfengine is very polite and has many safeguards against overloading its own network. (See the "Spamming and Security" section of the cfengine tutorial.) ExpireAfter limits how long a particular cfengine action can last. MaxConnections is the maximum number of threads allowed.

Next up is update.conf. This makes no changes to anything; it specifies which files cfengine is to push out to clients and prepares the working environment:

#################################
# /var/lib/cfengine2/update.conf
#################################
control:
  actionsequence = ( copy tidy )
  domain = ( carla.com )

  # name the master server
  policyhost = ( windbag.carla.com )

  master_cfinput = ( /var/lib/cfengine2/masterfiles/inputs )
  workdir = ( /var/lib/cfengine2 )
  cf_install_dir = ( /usr/sbin )

# Avoid server contention
SplayTime = ( 5 )

copy:

  $(master_cfinput)    dest=$(workdir)/inputs
    r=inf
    mode=700
    type=binary
    exclude=*.lst
    exclude=*~
    exclude=#*
    server=$(policyhost)

  $(cf_install_dir)/cfagent dest=$(workdir)/bin/cfagent
    mode=755
    backup=false
    type=checksum

  $(cf_install_dir)/cfservd    dest=$(workdir)/bin/cfservd
    mode=755
    backup=false
    type=checksum

  $(cf_install_dir)/cfexecd    dest=$(workdir)/bin/cfexecd
    mode=755
    backup=false
    type=checksum

tidy:

  # keep this directory from overflowing
  $(workdir)/outputs pattern=* age=7
#################################

And finally, the workhorse of cfengine, the cfagent.conf file. This is a very simple example, we'll get into this in detail next week. For testing purposes I created a file called testfile.txt, pasted some random text in it, owned by nobody, and made it mode 777. cfagent.conf will correct the ownership and mode:

#################################
# /var/lib/cfengine2/cfagent.conf
#################################
control:

  actionsequence = ( files )
files:
   /home/carla/testfile.txt owner=carla group=carla mode=0700 action=fixall
#################################

Ready to make a test drive? The following command turns on verbosity and does a dry-run only:

# cfagent -vn

When you want to run it for real, leave off the n switch. If it worked, you'll see it reported in the output, and testfile.txt will now have the correct ownership and permissions:

# ls -al testfile.txt
-rwx------ 1 carla carla 37 Sep 1 11:00 testfile.txt

That's all the cfengine fun I can take for this week. Come back next week to learn how to use encryption keys, connect clients, and to how to make cfagent rules for every occasion.

Resources