cfengine [3/3] : Using cfengine in a client/server setup

Posted by Steve on Tue 23 Aug 2005 at 09:44

After the previous coverage of cfengine we'll now look at actually installing it and using it for real on a number of different hosts. The rules will come from one central host and be automatically pushed to a collection of managed servers where they will be executed.

The rules file cfagent.conf which controls the jobs which are actually executed we've previously discussed.

For the purpose of this example we will be using three hosts:

As previously mentioned installing cfengine is as simple as running :

apt-get install cfengine2

(Here cfengine2 is the most recent version of the software; newer and incompatible with the previous package cfengine).

After installing the package upon each host you'll be presented with a debconf dialog asking if you wish to start several processes at boot time, along with an explanation of what each process is used for.

I chose to enable all services at boot time for the moment, although you'll likely not need all services running upon each host.

Now comes the hardest part actually configuring the software to do something useful. I strongly recommend that you also install the cfengine2-doc package upon at least one host and read the information it installs. This will be located beneath the directory:

/usr/share/doc/cfengine2-doc/
|-- examples
`-- html

To do someting useful you'll need two things:

Overview

We are going to setup is a centralised server which will host a file cfagent.conf containing the actions to be conducted upon each of the hosts we manage.

Each managed client will retrieve this rule file and then execute the rules locally.

The server itself will be able to force "pushes" of this file, and thus execute the rules upon any of the managed clients, either individually or en masse.

A Note On Security

If you setup cfengine in anger one of the biggest difficulties you'll encounter is getting the keyfile negotiation to work properly.

As discussed in the introductory piece cfengine uses a two-way trust. This means that the server's public key must be copied to the client, and the client's key must also be known to the server.

The fine documentation will explain the process of generating the keys with the command cfkey, and copying/renaming the keys appropriately. However due partly to misleading error messages and a lack of good discussion this is a common stumbling point.

As the communication is key to getting something working if you don't manage to get the keys setup correctly you'll not get anything working if you have problems.

So instead of using keys I'm going to ignore keyfiles completely - and trust all machines on the LAN.

This simplifies the description of the setup enormously; but it does weaken security.

(With a bit of firewalling it is possible to setup each client such that it only accepts connections from the central host. If you choose to ignore keyfiles, as I do, then this is something you should investigate.)

Setting Up The Server

The role of the server is going to be twofold:

What is less obvious is that the clients have to fetch the most current version of the cfagent.conf file on every run (if it has changed), so to make that explicit I will create a new location for this file to exist in:

mkdir -p /var/lib/cfengine2/masterfiles/inputs

Once you've done that you can install the cfagent.conf file there. A simple example file is:

#
# /var/lib/cfengine2/masterfiles/inputs/cfagent.conf
#
# Master cfagent file on the server, 
#
control:
  domain = ( my.flat )
  access = ( root )
  cfrunCommand = ( "/usr/sbin/cfagent" )
  actionsequence = ( files directories tidy resolve )
  maxage = ( 7 )


#
# Fix some basic file permissions.
#
files:
  /etc/sudoers mode=440 owner=root group=root   action=fixall
  /etc/passwd mode=644  owner=root group=root   action=fixall
  /etc/shadow mode=640  owner=root group=shadow action=fixall

#
# Clean out *ALL* files older than $(maxage) days from /tmp.
#
# Clean out files older than $(maxage) which match the pattern *~
# inside user home directories.
#
tidy:
  /tmp pattern=* age=$(maxage) recurse=inf
  /home pattern=*~ age=$(maxage) recurse=inf

directories:
  /tmp mode=1777 owner=root group=root

resolve:
	"search my.flat"
	192.168.1.1
        "# Edit with cfengine"

(This file is available for download.)

As you can see there is a "domain" setting right at the top, this is important as most of the cfengine files will use a "domain" when testing if accesses are allowed, as we'll see in the server configuration file.

You should change all domain settings to match your local network setup.

The server's configuration file is /etc/cfengine/cfservd.conf and ours will look like this:

#
# /etc/cfengine/cfservd.conf - for the server


control:
  domain = ( my.flat )
  TrustKeysFrom = ( 192.168.1.0/24 )
  AllowUsers = ( root )

any::

  IfElapsed = ( 0 )
  ExpireAfter = ( 15 )
  MaxConnections = ( 50 )
  MultipleConnections = ( true )


grant:

   # Grant access to all hosts in my.flat.
   /var/lib/cfengine2/masterfiles/inputs   *.my.flat

You can download this file if you wish.

For your setup you will need to modify the two mentions of my.flat, along with the local IP address range you're using.

The last job for the server is to build up a list of hosts you're going to manage. Do that by creating the file /etc/cfengine/cfrun.hosts:

domain = my.flat

#
# Clients
#
scratchy.my.flat
lappy.my.flat

(Again this file is available for download.)

Now that you've created the two file cfrun.hosts, and cfservd.conf inside /etc/cfengine you can restart the server:

/etc/init.d/cfengine2 restart
Setting Up The Clients

The client setup really consists of three things:

As we've covered the server we know that the cfagent.conf rule file will be stored on the host in the directory /var/lib/cfagent/masterfiles/input - the update file contains the magic which will copy it from there into /etc/cfengine on our host - where it can actually be used.

This means that our rulefile will always be current.

The /etc/cfengine/update.conf file will look like this:

#
# /etc/cfengine/update.conf - for the clients
#

control:
  actionsequence  = ( copy )
  domain          = ( my.flat )
  policyhost      = ( mystery.my.flat  )

# smtpserver      = ( smtp.domain.com )
# sysadm          = ( address@bogus.example.com )

  master_cfinput  = ( /var/lib/cfengine2/masterfiles/inputs )
  repository      = ( /var/lib/cfengine2/outputs )


#
# Download the most recent 'cfagent.conf' file from the
# server, and install it to /etc/cfengine
#

copy:
     $(master_cfinput)/cfagent.conf    dest=/etc/cfengine/cfagent.conf
                                       mode=600
                                       server=$(policyhost)
                                       force=true
                                       trustkey=true



(This file is available for download.)

You will need to change "my.flat" to your own domain, and "mystery.my.flat" to the name of your server if you wish to use it. No other changes should be required.

Once you've created the update file you're ready to create the cfservd.conf file for this client.

The following is a good sample:

#
# /etc/cfengine/cfservd.conf for the clients
#

control:
  domain = ( my.flat )
  AllowConnectionsFrom = ( 192.168.1.0/24 )
  TrustKeysFrom = ( 192.168.1.0/24 )
  cfrunCommand = ( "/usr/sbin/cfagent" )
  AllowUsers = ( root )
  LogAllConnections = ( true )
  IfElapsed = ( 1 )
  ExpireAfter = ( 15 )
  MaxConnections = ( 50 )
  MultipleConnections = ( true )



grant:
  /usr/sbin/cfagent  *.my.flat

(This file is available for download.)

Again you will need to modify the domain, grant, and the various IP addresses if you wish to use this yourself.

Now that you've copied everything onto the client properly you should be ready to restart the cfengine processes and run the initial agent test.

To restart run:

/etc/init.d/cfengine2 restart

Once this is done become root upon the client and run:

root@scratchy:~# cfagent -q
cfengine:: Trusting server identity and willing to accept key from mystery.my.flat=192.168.1.80

This should give you a message indicating successful trust, as we see, and you should discover the key of the server has now appeared within /var/lib/cfengine2/ppkeys:

root@scratchy:~# ls -l /var/lib/cfengine2/ppkeys/
total 12
-rw-------  1 root root 1743 2005-08-22 06:44 localhost.priv
-rw-------  1 root root  426 2005-08-22 06:44 localhost.pub
-rw-r--r--  1 root root  426 2005-08-22 17:22 root-192.168.1.80.pub
Using the installation

Now that you've setup the basic connection with the server and the clients you're ready to have fun!

To get started you should experiment with adding rules to the master cfagent.conf you've installed in /var/lib/cfengine2/masterfiles/inputs on the server.

To execute these rules against a host run:

cfrun hostname.as.in.cfrun.hosts

(e.g. "cfrun scratchy.my.flat").

Or against all managed hosts with just cfrun.

Note that the rules dont' all get applied in one run, sometimes it will take several executions.

As a sample I've added a rule to make sure the file permissions on /etc/gshadow are correct:

files:
  /etc/gshadow mode=440 owner=root group=root   action=fixall

Running this against a host gives me this :

root@mystery:~# cfrun scratchy.my.flat
cfrun(0):         .......... [ Hailing scratchy.my.flat ] ..........

cfengine::
         Update of image /etc/cfengine/cfagent.conf from master
        /var/lib/cfengine2/masterfiles/inputs/cfagent.conf on mystery.my.flat
cfengine:: Moved /etc/cfengine/cfagent.conf.cfsaved to repository location
        /var/lib/cfengine2/outputs/_etc_cfengine_cfagent.conf.cfsaved
cfengine:scratchy: Object /etc/gshadow had permission 0, changed it to 640
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

(As you can see I ran "chmod 0 /etc/gshadow" on scratchy first to see that the change worked)

What Now?

If you're using this in production you'll want to do three things, most likely:


This article can be found online at the Debian Administration website at the following bookmarkable URL:

This article is copyright 2005 Steve - please ask for permission to republish or translate.