These pages cover using CFEngine version 2 to control Unix system configuration. Consult the reference and tutorial documentation included with CFEngine frequently when building out a CFEngine infrastructure.
Articles
- Setup and usage of CFEngine Classes.
- Storing CFEngine configuration in a Concurrent Versions System (CVS) repository. Never hand edit files as root: all system configuration information must be stored under version control, database, or directory service.
- CFEngine Modules for cross-platform and cross-application User Account, Unix Groups, OpenSSH public keys, and Print Queue management.
- Example configurations using CFEngine.
- Running CFEngine on Microsoft Windows.
- Standalone CFEngine configurations.
Other Resources
-
CFEngine Support and Professional Services
-
cfwiki.org
- Automating Linux and Unix System Administration
See also the #cfengine channel on the Freenode IRC network.
Alternatives
Consult Infrastructures.Org and The Practice of System and Network Administration for big picture considerations of system configuration. Alternatives to CFEngine include: Bcfg2, isconf, puppet, and radmind. See also the comparison of open source configuration management software article on Wikipedia.
I strongly recommend against the use of graphical interface tools such as webmin. They have in my experience scaled poorly: many thousands of Domain Name System (DNS) records lead to laughable page load times, never mind the difficulty of editing, auditing, and testing entries trapped within the limitations of the captive web interface. Also, these tools create a dangerous layer of simplification between the actual files and processes being managed, thereby increasing the odds that the admin will remain ignorant of what is actually going on, and that the admin will therefore be unable to handle any software failures or complicated configuration needs that fall outside the limited scope of the interface. These tools may also complicate debugging efforts, unless the user of the tool knows how to translate any advice for directly interacting with the software or operating system into the whatever (or possibly unavailable) methods presented by the configuration tool.
Encryption & Verification
CFEngine uses a custom scheme for encryption and verification of connections. Alternatives include running CFEngine over Secure Shell (SSH) (via OpenSSH) or Transport Layer Security (TLS) (via a wrapper like stunnel). SSH or TLS will be eaiser to setup and debug for most administrators, and does not require learning the different CFEngine way to perform the same thing. Ideally, CFEngine should be fixed and use the standard TLS protocol internally.
CFEngine clients pull data from servers. The pull model has various advantages over pushing out updates. Using SSH or TLS, the CFEngine client would connect to a port on the localhost interface, which would then be forwarded encrypted to the CFEngine server.
Another approach: host the policy files on a regular web server, and require that clients verify a Pretty Good Privacy (PGP) signature before trusting the files.
Useful Tips
- Show Classes
- Disconnect from remote cfservd
- editfiles regular expressions must match full lines
- Default umask very strict.
- Classes and FileExists()
- Use a Makefile.
- Use variables for portability.
- Configuring MaxCfengines
- Symbolic Links
To show the classes defined on a system, run:
$ cfagent -p -v | grep -i classes
Defined Classes = ( … )
Negated Classes = ( )
Installable classes = ( no_default_route )
Ordinary users may not be able to see all classes, especially those from cfenvd. Run cfagent as the super user in this case.
Debugging CFEngine may require frequent cfagent runs on a test system. Disconnect the test system by pointing the update.conf on the test host to the local /var/cfengine/inputs directory. This way, CFEngine will always see the local inputs directory as up-to-date:
control:
any::
policyhost = ( localhost )
copy:
any::
/var/cfengine/inputs/ dest=/var/cfengine/inputs server=${policyhost}
…
When done testing, change update.conf back, and the configuration files will revert to those available on the remote cfservd host.
Regular expressions for editfiles in CFEngine behave differently than under other languages: full line matches are required. With Perl, one could use ^Subject: foo. CFEngine requires a trailing .*$ to match the entire line:
editfiles:
any::
{
/tmp/foo
AutoCreate
Backup "false"
BeginGroupIfNoLineMatching "^Subject: foo.*$"
InsertLine "Subject: foo"
EndGroup
}
By contrast, regular expressions in the processes section do not require a full match on the command name:
processes:
# restart OpenSSH if not running
openbsd::
"sshd$" restart "/usr/sbin/sshd"
redhat::
"sshd$" restart "/sbin/service sshd restart"
The default umask of 77 under shellcommands may cause problems if the command expects a looser 022 umask. Examples of this problem would be directories installed with drwx------ permissions instead of drwxr-xr-x, which disallow access from any user besides the owner. Ensure shellcommands that need the looser umask set the umask=022 option:
shellcommands:
redhat::
"/bin/echo umask" umask=022
Examples of problematic commands include rpm and yum, which will install directories with drwx------ permissions as root, and thus break various software packages.
The FileExists() option can define a class should a file exist on the system. However, to set a class when a file does not exist, other tricks must be used:
classes:
any::
have_file = ( FileExists(/etc/passwd) )
# first way: invert the positive definition
have_file_not = ( any -have_file )
alerts:
have_file_not::
"do not have file"
# another way: negate the class in the action block
!have_file::
"do not have file"
A Makefile under the CFEngine inputs directory can help test changes, creating a make test command to check for syntax errors:
ASROOT?=sudo
run:
@$(ASROOT) cfagent --no-splay --verbose
test:
@env CFINPUTS=`pwd` cfagent --no-splay --verbose --parse-only $(CF_ARGS)
Custom classes can be enabled via the CF_ARGS environment variable. This allows classes to be defined on a host that would otherwise not be set, excepting so-called “hard classes”:
$ env CF_ARGS='-D app_postgresql' make test
…
In cf.site or leading control blocks, set variables for different classes to account for system differences.
control:
any::
tmpdir = ( /tmp )
darwin|openbsd::
crondir = ( /var/cron/tabs )
linux::
crondir = ( /var/spool/cron )
solaris::
crondir = ( /var/spool/cron/crontabs )
Do not set MaxCfengines too low; all CFEngine commands, including cfenvd, are counted towards the total allowed MaxCfengines value. On the other hand, without a limit, CFEngine processes might remain open and eventually run a system out of resources.
MaxCfengines = ( 11 )
Symbolic links are an easy way to ensure commands share the same path. For example, Berkeley Software Distribution (BSD) systems such as Mac OS X and OpenBSD locate test under /bin, while SystemV systems appear to use /usr/bin. The following ensures test exists under /usr/bin.
links:
darwin|openbsd::
/usr/bin/test ->! /bin/test
Another option: do not touch the vendor space, and reference test under a software depot that has the correct test command for all supported platforms.
Mac OS X
OpenBSD
The ports system on OpenBSD 3.5 includes an old version of CFEngine, though version 2 can be built from source against the Berkeley DB package.
- Run cfengine at startup from /etc/rc.local.
editfiles:
{
/etc/rc.local
BeginGroupIfNoLineContaining "cfagent"
GotoLastLine
InsertLine "$(workdir)/bin/cfagent --no-splay --define sys_startup &"
InsertLine "echo -n ' cfagent'"
EndGroup
}