Cfengine 3 Concepts Guide
Cfengine 3 Concepts Guide
Cfengine 3 Concepts Guide
A cfengine AS workbook
Table of Contents
1 System automation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1 Managing diverse and challenging environmens seamlessly and
invisibly . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Managing expectations - a theory of promises. . . . . . . . . . . . . . . . . . . . 1
1.3 Why automation? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.4 Scaling up . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.5 How do you view cfengine? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
6 Network services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
6.1 Cfengine network services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
6.2 How services work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
6.2.1 Remote file distribution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
6.2.2 Remote execution of cf-agent . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
6.3 Remote access explained . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
6.3.1 Server connection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
6.3.2 Remote access troubleshooting . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
6.3.3 Key exchange . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
6.3.4 Time windows (races) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
6.3.5 Other users than root . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
6.3.6 Encryption . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
7 Knowledge Management . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
7.1 Promises and Knowledge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
7.2 The basics of knowledge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
7.3 Annotating promises. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
7.4 What topic maps offer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
7.5 Step by step . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
7.6 Querying the Topic Map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
7.7 The nuts and bolts of topic maps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
7.7.1 Topic map definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
7.7.2 cf-know . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
7.8 Modelling configuration promises as topic maps . . . . . . . . . . . . . . . . . 53
7.9 Annex: Technical pre-requisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
7.9.1 Knowledge base requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
7.9.2 Trouble shooting the knowledge base . . . . . . . . . . . . . . . . . . . . . . 55
8 More... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Chapter 1: System automation 1
1 System automation
1.1 Managing diverse and challenging environmens seamlessly and
invisibly
The future is never far away. Our dream of a future in which smart computing devices are
embedded into the very fabric of our environment has crept slowly into being. Today, smart
operating systems like Linux and Windows are used embedded devices and mobile phones.
Mark Weiser of Xerox PARC once wrote:
”The most profound technologies are those that disappear. They weave them-
selves into the fabric of every day life until they are indistinguisable from it.”
Today many are talking about Cloud Computing as another manifestation of this dream,
in which computing service is not only everywhere, but nowhere – or more correctly, spread
out across the planet in datacentres, instead of our offices and homes. This is one aspect
of making computing into something we take for granted. At the foundations of any such
technology are the tools required to implement mass configuration with surgical precision.
Cfengine is such a tool.
Cfengine was designed to enable scalable configuration management, for the whole system
life-cycle, in any kind of environment. Almost every other system for configuration assumes
that there will be a reliable network in place and that changes will be pushed out top-down
from an authoratative node. Those systems is useless in environments like
• Mobile systems with partial or unreliable connectivity (e.g. a submarine).
• Systems where bandwidths are very low (e.g. a satellite or space probe).
• Systems where computing power is very low (e.g. ad hoc sensors or kitchen appliances).
Cfengine does not need reliable infrastructure. It works opportunistically in almost any
environment, using few resources. It has few software dependencies. So, not only does it
work in all of the traditional fixed-plan scenarios, but it is capable of working in totally ad hoc
deployment: an temporary incident room, a submarine drifting on and off line, a satellite or a
robot explorer.
One could argue ‘well I don’t need that kind of system, because my network is reliable’.
However, your network is not a reliable as you think, and mobility is an increasingly important
topic. Even with a very strong redundant network, the services that support the network can
be paralysed by any of a number of failed dependencies or mishaps. It is crucial in a modern
pervasive environment that systems remain available, fault tolerant and as far as possible
independent of external requirements. This is how to build scalable and reliable services.
Cfengine works in all the places you think it should, and all the new places you haven’t even
thought of yet. How do we know? Because it is based on almost 20 years of careful research
and experience.
1.4 Scaling up
In the past, the only way to scale up system numbers was to make all systems identical. This
is no longer true.
In the late 1960s journalist and futurist Alvin Toffler sketched a pretty compelling vision
of the western world and its post-industrial future. His book Future Shock, which appeared in
1970, was really a reaction to the cold-war fears about a communist industrial state in which
mass production made everything and everyone identical and indistinguishable. His book was
Chapter 1: System automation 3
really a rebuttal to all those who argued that industrialization and mass production implied
that everything had to be exactly the same. and I recommend reading it - it is very well written
and has many lessons for us today. But from his rather long diatribe, I wrote down a single
sentence which for me sums up the lesson that we have failed to learn:
”As technology becomes more sophisticated, the cost of introducing variations
declines.”
In other words, any half-decent technology for mass production would help us to be more
sophisticated and multifarious, not less. In an age when you can get business cards printed on
demand from an ATM at the airport, and personalized coffee mugs in the blink of an eye, there
is no reason to perpetuate the myth that massive infrastructure requires monolithic replication,
and yet people still do. Network engineers do, and system administrators do. They even say
that this is essential for scalability.
The importance of Toffler’s message was that the economics of mass production are not at
odds with the economics of adaptation, but 40 years later, we are still relearning that lesson.
For many users, cfengine is simply a configuration tool – i.e. software for deploying and
patching systems according to a policy. Policy is described using promises – indeed, every
statement in cfengine 3 is a promise to be kept at some time or location. More than this,
however, cfengine is not like most automation tools that ‘roll out’ an image of some software
once and hope for the best. Every promise that you make in cfengine is continuously verified
and maintained. It is not a one-off operation, but an encapsulated process that repairs itself
should anything deviate from the policy.
That clearly places cfengine in the realm of automation, which often begs the question: so
it’s just another scripting language? Certainly cfengine contains a powerful scripting language,
but it is not like any other. Cfengine is not a low level language like Perl, Python or Ruby;
it is a language of promises, in which you express very high level intentions about the system
and the inner details figure out the algorithms needed to implement the result. We’ll return
to this below.
For many, cfengine is a tool for implementing security hardening procedures on systems, and
monitoring them continuously thereafter. This is certainly a major application area. Cfengine
has a reputation for being reliable and secure. That is because its basic design is secure: it is
not possible to send information about policy to cfengine from outside the system. If access
has been granted, it is only possible to send a few simple protocol requests of limited length
to the server. This makes the design safer than most firewalls. Most servers fail security tests
because it is possible to send data to them.
The ability to describe almost any kind of policy for a system means that we can suggest
promises that a system should make and comply with. Thus cfengine can also be thought of
as a compliance engine. It is easily used to comply with frameworks like SOX, ‘EUROSOX’
(the EU 8th Data Directive), ITIL and standards like ISO 17799, ISO 20000, etc.
Finally, although cfengine was not initially conceived for monitoring, it contains one of the
most flexible and lightweight monitoring engines around. You can extract data about system
configuration, usage, resources and log data and turn this into readable reports. Cfengine’s
ability to discover and extract information about the system, combined with its reporting
means that you can turn the system into a simple Configuration Management Database.
In the Community edition, monitoring is a zero-touch background process. With cfengine
commericial extensions, there is almost no limit to the kind of monitoring promises you can
make, and without the embarassing resource spikes that many monitoring systems produce.
Above all, cfengine is aimed to promote human understanding of complex processes. Its
promises are easily documentable using comments that the system remembers and reminds us
about in error reporting. It hides irrelevant and transitory details of implementation so that the
intentions behind the promises are highlighted for all to see. This means that the knowledge
of your organization can be encoded into the cfengine language.
WHY DOES KNOWLEDGE MATTER? There are two reasons: the first is that technical
descriptions are hard to remember. You might understand your configuration decisions when
you are writing them, but a few months later when something goes wrong, you will probably
have forgotten what you were thinking. That costs you time and effort to diagnose. The
second reason is that organizations are fragile to the loss of those individuals who code policy.
If they leave, often there is no one left who can understand or fix the system. Only with proper
documentation is it possible to immunize against loss.
Chapter 2: The components of cfengine 5
2.1 Installation
To install cfengine, you will need a few packages. You require:
OpenSSL Open source Secure Sockets Layer for encryption.
URL: http://www.openssl.org
BerkeleyDB (version 3.2 or later)
Light-weight flat-file database system.
URL: http://www.oracle.com/technology/products/berkeley-db/index.html
In addition...
It is recommended to make the Perl Compatible Regular Expression (PCRE) li-
brary available as this is a significant improvement over the more standard POSIX
libraries. This documentation assumes the use of PCRE
On Windows machines, you need to install the basic Cygwin DLL from
http://www.cygwin.com in order to run cfengine.
Additional functionality (some of which is available only in commercial extensions) also
becomes available if other libraries are present, e.g. OpenLDAP, client libraries for MySQL
and PostgreSQL, etc. It is possible to run cfengine without these, but related functionality
will be missing.
Unless you have purchased ready-to-run binaries, or are using a package distribution, you
will need to compile cfengine. For this you will also need a build environment tools: gcc, flex,
bison.
The preferred method of installation is then
tar zxf cfengine-x.x.x.tar.gz
cd cfengine-x.x.x
./configure
make
make install
This results in binaries being installed in ‘/usr/local/sbin’.
/var/cfengine
/var/cfengine/bin
/var/cfengine/inputs
/var/cfengine/outputs
A trusted cache of the input files must now be maintained in the ‘inputs’ subdirectory.
When cfengine is invoked by the scheduler, it expects to read only from this directory. It
6 Cfengine 3 Concept Guide
is up to the user to keep this cache updated, on each host (this is arranged by the default
configuration files).
Unlike cfengine 2, cfengine 3 does not recognize the CFINPUTS environment variable.
The ‘outputs’ directory is now a record of spooled run-reports. These are often mailed to
the administrator by cf-execd, or can be copied to another central location and viewed in an
alternative browser.
host1 host2
cf−execd cf−execd
cf−agent cf−agent
cf−monitord cf−monitord
cf−server cf−server
cf−runagent cf−runagent
If the network is not working, cfengine just skips these parts and continues with what it
can do. It is fault tolerant and opportunistic.
cf-promises
The promise verifier and compiler. This is used to pre-check a set of configuration
promises before attempting to execute.
cf-agent
Chapter 2: The components of cfengine 7
This is the instigator of change. The agent is the part of cfengine that manipulates
system resources.
cf-serverd
The server is able to share files and receive requests to execute existing policy
on an individual machine. It is not possible to send (push) new information to
cfengine from outside.
cf-execd
This is a scheduling daemon (which can either supplement or replace cron). It
also works as a wrapper, executing and collecting the output of cf-agent and
E-mailing it if necessary to a system account.
cf-runagent
This is a helper program that can talk to cf-serverd and request that it execute
cf-agent with its existing policy. It can thus be used to simulate a push of
changes to cfengine hosts, if their policy includes that they check for updates.
cf-report
This generates summary and other reports in a variety of formats for export or
integration with other systems.
cf-know
This agent can generate an ISO standard Topic Map from a number of promises
about system knowledge. It is used for rendering documentation as a ‘semantic
web’.
In cfengine, what you build is a template of proposed promises for the machines
in an organization such that, if the machines all make and keep these promises,
the system will function seamlessly as planned. This is how it works in a human
organization, and this is how is works for computers too.
Deploy Deploying really means implementing the policy that was already decided. In
transaction systems, one tries to push out changes one by one, hence ‘deploying’
the decision. In cfengine you simply publish your policy (in cfengine parlance these
are ‘promise proposals’) and the machines see the new proposals and can adust
accordingly. Each machine runs an agent that is capable of implementing policies
and maintaining them over time without further assistance.
Manage Once a decision is made, unplanned events will occur. Such incidents usually
set off alarms and humans rush to make new transactions to repair them. In
cfengine, the autonous agent manages the system, and you only have to deal
with rare events that cannot be dealt with automatically.
Audit In traditional configuration systems, the outcome is far from clear after a one-
shot transaction, so one audits the system to determine to discover what actually
happened. In cfengine, changes are not just initiated once, but locally audited and
maintained. Decision outcomes are assured by design in cfengine and maintained
automatically, so the main worry is managing conflicting intentions. Users can sit
back and examine regular reports of compliance generated by the agents, without
having to arrange for new ‘roll out’ transactions.
ROLL-OUT and ROLL-BACK? You should not think of cfengine with a roll-out system,
i.e. one that attempts to force out absolute changes and perhaps reverse them in case of
error. Roll-out and roll-back are theoretically flawed concepts that only sometimes work in
practice. With cfengine, you publish a sequences of policy revisions, always moving forward
(because like it or not, time only goes in one direction). All of the desired-state changes are
managed locally by each individual computer, and continuously repaired to ensure on-going
compliance with policy.
In order to keep operations as simple as possible, cfengine maintains a private working direc-
tory on each machine referred to in documentation as WORKDIR and in policy by the variable
$(sys.workdir). By default, this is located at ‘/var/cfengine’ or ‘C:“var“cfengine’. It
contains everything cfengine needs to run.
Chapter 2: The components of cfengine 9
The figure below shows how decisions flow through the parts of a system.
Version
Policy Definition Point
Control
/any/path Repository
• It makes sense to have a single point of coordination. Decisions are therefore usually made
in a single location (the Policy Definition Point). The history of decisions and changes
can be tracked by a version control system of your choice (e.g. SubVersion).
• Decisions are made by editing cfengine’s policy file ‘promises.cf’ on one of its included
children. This process is carried out off-line.
• Once decisions have been formalized and coded, this new policy is copied manually (a
human decision) to a decision distribution point, which by default is located in the directory
‘/var/cfengine/masterfiles’ on all policy distribution servers.
In this introduction, we shall assume that there is only one central policy distribution
server, a specially-appointed server which is referred to simple as the policy server.
• Every client machine contacts the policy server and downloads these updates. The policy
server can be replicated if the number of clients is very large, but we shall assume here
that there is only one policy server.
Once a client machine has a copy of the policy, it extracts only those promise proposals
that are relevant to it, and implements any changes without human assistance. This is how
cfengine manages change.
WHY DO THIS? Cfengine tries to minimize dependencies by decoupling processes. By
following this pull-based architecture, cfengine will tolerate network outages and will recover
from deployment errors easily. By placing the burden of responsibility for decision at the top,
and for implementation at the bottom, we avoid needless fragility and keep two independent
quality assurance processes apart.
the Community Edition is to copy the distributed policy files that were installed in
‘/usr/local/share/cfengine/’ to a policy distribution point, like this:
1. Decide on your policy server.
2. Become root or Administrator
3. Create the policy source directory:
host# mkdir -p /var/cfengine/masterfiles
host# cp /usr/local/share/cfengine/*.cf /var/cfengine/masterfiles
4. Now start the system.
host# /usr/local/sbin/cf-key
host# cd /var/cfengine/masterfiles
host# /usr/local/sbin/cf-agent --bootstrap
You should browse the files in ‘/var/cfengine/masterfiles’ to see what they contain,
and even make some alterations before doing this. Amongst other things, you will want to
customize things like the ‘resolv.conf’ parameters to your site. If you have used an ealier
version of cfengine before, the contents of these files will not look too mysterious. For the
rest, stay tuned for an overview.
Note: If you have manually configured a different location for the cfengine work directory,
you will need to adapt these lines above to replace ‘/var/cfengine’ with the path you have
configured; e.g. Debian based packages feel that ‘/var/lib/cfengine’ is the right location
for this.
Chapter 3: How to execute and test a cfengine policy 11
Type this in to a file, e.g. ‘emacs ˜/test.cf’. Then check the syntax like this
/usr/local/sbin/cf-promises -f ˜/test.cf
If all is well there should be no output. Now execute as follows:
/usr/local/sbin/cf-agent -f ˜/test.cf
You should see this:
R: Hello world
The ‘R:’ tells you this is the output from a report (as opposed to a log ‘L:’, or the quoted
output of some embedded program ‘Q:’).
This is not a typical cfengine program, primarily because cfengine is not normally meant to
print messages except in exceptional circumstances. As a starter however, it is reassuring to
see some output.
If you repeat the command immediately nothing will happen. But if you wait a minute, it
will work again. Run the command in verbose mode to see why:
12 Cfengine 3 Concept Guide
”/tmp/testfile” # promiser
This example shows how additional attributes are added to the body of the promise. The
right hand side of the perms declaration is a template which we have called ‘p()’, which uses
a parameter. The template is defined below the bundle of promises that uses it, showing how
we can create re-usable sets of parameters. In this case, the example is trivial, but we have
barely begun. When things get more sophisticated, we shall hide a huge amount of detail in
these parameters, thus keeping the main promise uncluttered and its intention clear.
Now execute cf-agent with this promise:
host$ /usr/local/sbin/cf-agent -f /tmp/test.cf -I
-¿ Object /tmp/testfile had permission 600, changed it to 612
host$ ls -l /tmp/testfile
-rw---x-w- 1 mark users 33 2009-06-30 06:06 /tmp/testfile
The ‘-I’ flag tells cfengine to ‘inform’ us about changes only. This provides a digestable
amount of output that is more than the default (which is to only report un-fixable problems
or explicit reports). We see that cfengine creates the file as ordered, and sets the permissions
appropriately. Now try to change the permissions:
host$ chmod 400 /tmp/testfile
host$ ls -l /tmp/testfile
-r-------- 1 mark users 33 2009-06-30 06:06 /tmp/testfile
host$ ls -l /tmp/testfile
-rw---x-w- 1 mark users 33 2009-06-30 06:06 /tmp/testfile
Once again, remember the comment about locking and ifelapsed from the previous
example.
14 Cfengine 3 Concept Guide
Notice that this promise does not have a class expression like cfengine˙3::. The default
class any:: applies if nothing is stated, which means ‘anytime anyplace anywhere’ (but it’s
not a Martini).
”/tmp/shadow”
comment =¿ ”Set the root password”,
edit˙line =¿ SetPasswd(”root”,”xyajd673j.ajhfu”);
˝
This is all we need to see on first inspection to understand the promise that is being made.
The following code belongs to a standard library, and can be reused thus keeping the promise
above clear. However, unlike other systems, you can extend cfengine in its own language. You
do not have to program complex algorithms yourself, or have a development environment.
#
# Library code - hide me
#
”$(user):.*”
########################################
–
field˙separator =¿ ”$(split)”;
select˙field =¿ ”$(col)”;
value˙separator =¿ ”,”;
field˙value =¿ ”$(newval)”;
field˙operation =¿ ”$(method)”;
extend˙fields =¿ ”true”;
˝
files:
”/var/cfengine/inputs”
”/var/cfengine/bin”
These promises contain several attributes in their bodies that we have not seen yet. The
copy˙from attribute tells cfengine how to source (copy) a file from a master location. The
depth˙search tells it to search recursively through the sub-directories and their files.
Try changing the source files and executing the agent.
Again there are library reusable templates:
Here is an exercise: try using the reference manual to look up the elements in this example.
See if you can understand all the parts.
3.5 Reporting
Cfengine contains a report generator called ‘cf-report’. It is configured using control pa-
rameters described in the next chapter. Try:
host$ /usr/local/sbin/cf-reports
host$ ls ˜/.cfagent/reports
host$ mywebbrowser ˜/.cfagent/reports/performance.html
Most of these reports will be blank at the start, until you have run cfengine on some
significant promises.
3.6 cf-execd
Cfengine contains a service for running the agent with its default configuration in
‘WORKDIR/inputs/promises.cf’ called the exec-daemon. If you execute the binary directly
Chapter 3: How to execute and test a cfengine policy 17
it will go into the background and execute ‘cf-agent’ every five minutes by default, with its
default policy.
You can try running it in the foreground:
host$ /usr/local/sbin/cf-execd -F
When you run cfengine like this, any output that comes from cfengine is collected and placed
in ‘WORKDIR/outputs’. If you have configured an email address and your host is running an
SMTP service, then it will be sent as email. To configure this you would add a contol body
to the ‘promises.cf’ file
body executor control
–
splaytime =¿ ”1”;
mailto =¿ ”cfengine˙[email protected]”;
smtpserver =¿ ”localhost”;
mailmaxlines =¿ ”30”;
˝
These other lines change different aspects of the hard-wired behaviour of the executor,
e.g. a load-balancing time delay before execution of the agent, a mail address, the name or
IP address of an SMTP (mail) service, and the maximum number of lines of output to be
included in any email sent.
You should start to see a pattern in the way cfengine is configured. In the next chapter,
we’ll look at these general matters.
18 Cfengine 3 Concept Guide
Chapter 4: A simple crash course in concepts 19
type:
classes::
attribute˙1 =¿ value˙1,
attribute˙2 =¿ value˙2,
...
attribute˙n =¿ value˙n;
We speak of a promiser (the abstract object making the promise), the promisee is the abstract
object to whom the promise is made, and them there is a list of associations that we call the
‘body’ of the promise, which together with the promiser-type tells us what it is all about.
The promiser is always the object affected by the promise.
Not all of these elements are necessary every time. Some promises contain a lot of implicit
behaviour. In other cases we might want to be much more explicit. For example, the simplest
promise looks like this:
commands:
This promise has default attributes for everything except the ‘promiser’, i.e. the command
string that promises to execute. A more complex promise contains many attributes:
files:
The list of promisees is not used by cfengine except for documentation, just as the comment
attribute (which can be added to any promise) has no actual function other than to provide
more information to the user in error tracing and auditing.
20 Cfengine 3 Concept Guide
You see several kinds of object in this example. All literal strings (e.g. ”true”) in cfengine 3
must be quoted. This provides absolute consistency and makes type-checking easy and error-
correction powerful. All function-like objects (e.g. users(”..”)) are either builtin special
functions or parameterized templates which contain the ‘meat’ of the right hand side.
inputs =¿ –
”update.cf”,
”site.cf”,
”library.cf”
˝;
˝
#######################################################
#######################################################
#######################################################
–
splaytime =¿ ”1”;
mailto =¿ ”cfengine˙[email protected]”;
smtpserver =¿ ”localhost”;
mailmaxlines =¿ ”30”;
˝
#######################################################
–
reports =¿ – ”performance”, ”last˙seen”, ”monitor˙history” ˝;
build˙directory =¿ ”/tmp/nerves”;
report˙output =¿ ”html”;
˝
#######################################################
#######################################################
–
allowconnects =¿ – ”127.0.0.1” , ”::1” ˝;
allowallconnects =¿ – ”127.0.0.1” , ”::1” ˝;
trustkeysfrom =¿ – ”127.0.0.1” , ”::1” ˝;
allowusers =¿ – ”root” ˝;
˝
4.3 Variables
Variables are also promises – the promise to represent their values. We can write these in any
promise bundle. Cfengine recognizes two object types: scalars and lists, as well as three data-
types (string, integer and real). Typing in cfengine is dynamic, as in Perl and other scripting
languages. Thus variables of any data-type may be used as strings.
The ‘****’ indicates that any kind of bundle applies here. Scalar variables are referenced
by ‘$(name)’ (or ‘$–name˝’) and they represent a single value at a time.
• Scalars that are written without a context, e.g. ‘$(myvar)’ are local to the current
bundle.
• Scalars are globally available everywhere provided one uses the context to verify them e.g.
‘$(context.myvar)’ may be written to access the variable ‘myvar’ in bundle ‘context’.
An entire list is referred to with the at symbol ‘@’ and it does not usually mmake sense to
use this reference in a string. For instance
reports:
Chapter 4: A simple crash course in concepts 23
cfengine˙3::
means nothing and cannot be expanded; but if we use the scalar reference on a list cfengine
can iterate over the values in the list essentially making this into a list of promises.
To summarize:
• Scalar references to local list variables imply iteration, e.g. suppose we have local list
variable ‘@(list)’, then the scalar ‘$(list)’ implies an iteration over every value of the
list.
• Lists can be passed around in their entirety in any context where a list is expected as
‘@(list)’., e.g.
vars:
• Only local lists can be expanded directly. Thus ‘$(list)’ can be expanded but not
‘$(context.list)’. See below for the explanation.
During list expansion, only local lists can be expanded, thus global list references have to be
mapped into a local context if you want to use them for iteration. See the reference manual
for more information.
4.4 Decisions
Cfengine makes decisions are made behind the scenes and the results of certain true/false
propositions are cached in Booleans referred to as ‘classes’. There are no if-then-else state-
ments in cfengine; all decisions are made with classes.
Cfengine runs on every computer individually and each time it wakes up the underlying
generic agent platform discovers and classifies properties of the environment or context in
which it runs. This information is effectively cached and may be used to make decisions about
configuration.
Classes fall into hard (discovered) and soft (user-defined) types. A single hard class can be
one of several things:
• The name of an operating system architecture e.g. ultrix, sun4, etc.
• The unqualified name of a particular host. If your system returns a fully qualified domain
name for your host, cfengine truncates it at the first dot.
• The name of a user-defined group of hosts.
• A day of the week (in the form Monday, Tuesday, Wednesday, ..).
• An hour of the day, current time zone (in the form Hr00, Hr01 ... Hr23).
• An hour of the day GMT (in the form GMT˙Hr00, GMT˙Hr01 ... GMT˙Hr23). This is
consistent the world over, in case you need virtual simulteneity of change coordination.
24 Cfengine 3 Concept Guide
• Minutes in the hour (in the form Min00, Min17 ... Min45).
• A five minute interval in the hour (in the form Min00˙05, Min05˙10 ... Min55˙00)
• A day of the month (in the form Day1, Day2, ... Day31).
• A month (in the form January, February, ... December).
• A year (in the form Yr1997, Yr2004).
• A shift in Night,Morning,Afternoon,Evening, which fall into six hour blocks starting
at 00:00 hours.
• A ‘lifecycle index’, which is the year number modulo 3 (used in long term resource mem-
ory).
• An arbitrary user-defined string.
• The IP address octets of any active interface (in the form ipv4˙192˙0˙0˙1,
ipv4˙192˙0˙0, ipv4˙192˙0, ipv4˙192).
To see all of the classes define on a particular host, run
host# cf-promises -v
as a privileged user. Note that some of the classes are set only if a trusted
link can be established with cfenvd, i.e. if both are running with privilege, and the
‘/var/cfengine/state/env˙data’ file is secure. More information about classes can be
found in connection with allclasses.
User-defined or soft classes are defined in bundles. Bundles of type common yield classes
that are global in scope, whereas in all other bundle types classes are local. Soft classes are
evaluated when the bundle is evaluated. They can be based on test functions or simply from
other classes:
reports::
alt˙class::
”Boo!”;
˝
(Monday—Wednesday).Hr14.WinXP::
#################################
bundle common g
–
classes:
#################################
#################################
reports:
one.three.!two::
”Success”;
˝
Here we see that class ‘one’ is global while classes ‘two’ and ‘three’ are local. The report
‘Success’ result is therefore true because only ‘one’ and ‘three’ are in scope.
4.5 Loops
If you are looking for loops in cfengine then we need to reprogram you a little, as you are
thinking like a programmer! Cfengine is not a programming language that is meant to give
you low level control, but rather a set of declarations that embody processes. It’s the difference
between the gears on a bicycle and the automated transmission in a transporter.
Loops are executed implicitly in cfengine, but there is no visible mechanism for it – because
that would steal attention from the intention of the promises. The way to express them is
through lists.
Loops are really a way to iterate a variable over a list. Try the following.
–
bundlesequence =¿ – ”example” ˝;
˝
###########################################################
–
vars:
# This is a list
reports:
Chapter 4: A simple crash course in concepts 27
cfengine˙3::
”$(component) is $(array[$(component)])”;
/usr/local/sbin/cf-agent -f ./unit˙loops.cf -K
You see from this that, if we refer to a list variable using the scalar reference operator ‘$()’,
cfengine interprets this to mean: please iterate over all values. Thus, we have effectively a
‘foreach’ loop, without the attendant syntax.
topics A promise to associate knowledge with a name, and possibly other topics, in
cf-know.
occurrences
A promise to point or refer to a knowledge resource, in cf-know.
Chapter 5: Using cfengine as a front-end or replacement for cron 29
The central idea behind this scheme is to set up a regular cron job on every system which
executes cfagent at frequent intervals. Each time cf-agent is started, it evaluates time classes
and executes the shell commands defined in its configuration file. In this way we use cf-agent
as a wrapper for the cron scripts, so that we can use cfengine’s classes to control jobs for
mulitple hosts. Cfengine’s time classes are at least as powerful as cron’s time specification
possibilities, and they add control over location too. This does not restrict you in any way,
See Section 5.5 [Building flexible time classes], page 31. The only price is the overhead of
parsing the cfengine configuration file which is insignificant.
DO I NEED TO USE CRON? No. With cfengine’s cf-execd you don’t have to use cron
– cfengine can schedule itself. Whether you choose to run cf-execd in daemon mode, or in
wrapper mode is entirely up to you. In the commercial versions of cfengine, the exec daemon
has sophisticated features for reliability. In the Community Edition, you might feel comfortable
having something independent watching over cfengine, especially during binary updates during
which live programs can die from faults.
30 Cfengine 3 Concept Guide
promise-type :
Hr00.Min10˙15——Hr12.Min45˙55::
Promise
For example:
bundle agent example
–
commands:
Hr12.Q1::
Q2::
”/path/otherscript”;
If you want to get fancy, you can set parameters for the execution of the script by building a
container for it that traps its output and privileges (applies to root only, since only root has
this power to change privilege).
bundle agent example
–
commands:
Hr12.Q1::
contain =¿ jail(”nobody”,”true”);
˝
Chapter 5: Using cfengine as a front-end or replacement for cron 31
# ...
The containment body provides a safe and flexible environment in which to embed scripts.
The time resolution of the classes is limited by how often you execute cfengine either using
cron or cf-execd. Five minutes is the recommended scheduling interval.
–
splaytime =¿ ”1”; # Minutes
˝
If this number is non-zero, cf-execd goes to sleep after parsing its configuration file and
reading the clock. Every machine’s cf-execd will go to sleep for a different length of time,
which is no longer than the time specified.
A hashing algorithm, based on the fully qualified name of the host, is used to compute a
unique time for hosts. The shorter the interval, the more clustered the hosts will be. The
longer the interval, the lighter the load on your servers. This ‘splaying’ of the run times will
lighten the load on servers, even if they come from domains not under your control but have
a similar cron policy.
In these examples, the left hand sides of the assignments are effectively the ORed result of
the right hand side. This if any classes in the parentheses is defined, the left hand side class
will become defined. This provides a flexible and readable way of specifying intervals of time
within a program, without having to use ‘—’ and ‘.’ operators everywhere.
6 Network services
This chapter describes how you can set up a cfengine network service to handle remote file
distribution and remote execution of cfengine without having to open your hosts to possible
attack using the rsh protocols.
willing. In other words, cfengine simulates a ‘push’ model by polling each client and running
the local cfengine configuration script giving the host the chance to ‘pull’ any updated files
from the remote server, but leaving it up to the client machine to decide whether or not it
wants to update.
Also, in contrast to programs like rdist which distribute files over many hosts, cfengine
does not require any general root access to a system using the ‘.rhosts’ file or the
‘/etc/hosts.equiv’ file. It is sufficient to run the daemon as root. You can not run it by
adding it to the ‘/etc/inetd.conf’ file on your system however. The restricted functionality
of the daemon protects your system from attempts to execute general commands as the root
user using rsh.
To remotely access files on a server you use a copy˙from attribute in a ‘files’ promise:
bundle agent example
–
files:
”/var/cfengine/inputs”
perms =¿ u˙p(”600”),
copy˙from =¿ rcp(”$(master˙location)”,”localhost”),
depth˙search =¿ recurse(”inf”),
action =¿ immediate;
# Library template
–
servers =¿ – ”$(server)”, ”failover.example.org”˝;
source =¿ ”$(file)”;
˝
Assuming that the cf-serverd daemon is running on server-host, cf-agent will make contact
with the daemon and attempt to obtain information about the file. During this process,
cfengine verifies that the system clocks of the two hosts are reasonably synchronized. If they
are not, it will not permit remote copying unles denybadclocks is false in the server control
body.
If cf-agent determines that a file needs to be updated from a remote server it begins
copying the remote file to a new file on the same filesystem as the destination-file. This file
has the suffix ‘.cfnew’.
Only when the file has been successfully collected will cf-agent make a copy of the old
file, (see repository in the Reference manual), and rename the new file into place. This
behaviour is designed to avoid race-conditions which can occur during network connections
and indeed any operations which take some time. If files were simply copied directly to their
Chapter 6: Network services 35
new destinations it is conceivable that a network error could interrupt the transfer leaving a
corrupted file in place. cf-agent places a timeout of a few seconds on network connections
to avoid hanging processes.
Normally the daemon sleeps, waiting for connections from the network. Such a connection
may be initiated by a request for remote files from a running cf-agent program on another
host, or it might be initiated by the program cf-runagent which simply asks the host running
the daemon to run cf-agent or cf-execd program locally.
output....
A client program
Both cf-agent and cf-runagent are clients that can connect to the server.
Permission to connect to the server, and
The server control body must grant access to your computer and public key by
name or IP address, by listing it in one of the lists (see below).
Your public key must be trusted by the server, and you must
trust the server’s public key
By mutually trusting each others’ keys, client and server agree to use that key as
a sufficient identifier for the computer.
Permission to access something
Your host name or IP address must be mentioned in an access promise inside a
server bundle, made by the file that you are trying to access.
If all of the above criteria are met, connection will be established and data will be transferred
between client and server. The client can only send short requests, following the cfengine
protocol. The server can return data in a variety of forms, usually files, but sometimes console
output.
3. Make sure you have created valid keys for the hosts using cf-key.
4. If you are using secure copy, make sure that you have created a key file and that you have
distributed and installed it to all participating hosts in your cluster.
Always remember that you can run cfengine in verbose or debugging modes to see how the
authentication takes place:
cf-agent -v
cf-serverd -v
Chapter 6: Network services 37
cf-agent reports that access is denied regardless of the nature of the error, to avoid giving
away information which might be used by an attacker. To find out the real reason for a denial,
use verbose ‘-v’ or even debugging mode ‘-d2’.
–
access:
”/path/file”
On the client side, i.e. cf-runagent and cf-agent, there are three issues:
1. Choosing which server to connect to.
2. Trusting the identity of any previously unknown servers, i.e. trusting the server’s public
key to be its and no one else’s. (The issues here are the same as for the server.)
3. Choosing whether data transfers should be encrypted (with encrypt).
Because there are two clients for connecting to cf-serverd (cf-agent and cf-runagent),
there are also two ways on managing trust of server keys by a client. One is an automated
option, setting the option trustkey in a copy˙from stanza, e.g.
38 Cfengine 3 Concept Guide
Another way is to run cf-runagent in interactive mode. When you run cf-runagent,
unknown server keys are offered to you interactively (as with ssh) for you to accept or deny
manually:
WARNING - You do not have a public key from host ubik.iu.hio.no = 128.39.74.25
Do you want to accept one on trust? (yes/no)
--¿
localhost.pub -¿ root-128.39.74.71.pub
This would be a silly way to transfer keys between nearby hosts that you control yourself,
but if transferring to long distance, remote hosts it might be an easier way to manage trust.
6.3.6 Encryption
Cfengine provides encryption for keeping file contents private during transfer. It is assumed
that users will use this judiciously. There is nothing to be gained by encrypting the transfer of
public files – overt use of encryption just contributes to global warming, burning unnecessary
CPU cycles without offering any security.
The main role for encryption in configuration management is for authentication. Cfengine
always uses encrypted for authentication, so none of the encryption settings affect the security
of authentication.
40 Cfengine 3 Concept Guide
Chapter 7: Knowledge Management 41
7 Knowledge Management
A truly unique aspect of cfengine its ability to enable integrated knowledge management in its
automation process, and to use its configuration technology as a ‘semantic’ documentation
engine.
Knowledge management is the challenge of our times. Organizations waste an incredible
amount of effort re-learning old lessions because they have not been documented and entered
into posterity. Now you can alleviate this problem with some simple rules of thumb and even
build sophisticated index-databases of documents.
The trouble is that writing is something people don’t like to do, and few are very good
at. To an engineer, it can feel like a waste of time, especially during a busy day, to break off
from the doing to write about the doing. Also, writing requires a spurt of creative thinking
and engineers are often more comfortable with manipulating technical patterns and notations
than writing fluent linguistic formulations that seem overtly long-winded.
Cfengine tries to bridge this gap by making documentation simple and part of the technical
configuration. Cfengine’s knowledge agent then uses AI and network science algorithms to
construct a readable documentation from these technical annotations. It can do this because
a lot of thought has already gone into the meaning of the promise model.
files:
”/var/cfengine/inputs”
handle =¿ ”update˙policy”,
comment =¿ ”Update the cfengine input files from the policy server”,
perms =¿ system(”600”),
copy˙from =¿ rcp(”$(master˙location)”,”$(policy˙server)”),
depth˙search =¿ recurse(”inf”),
file˙select =¿ input˙files,
action =¿ immediate;
If a promise affects another promise is some way, you can make the affected one promise one
of the promisees, like this:
access:
handle =¿ ”serve˙updates”,
admit =¿ – ”217.77.34.*” ˝;
Conversely, if a promise might depend on another in some (even indirect) way, document this
too.
files:
Chapter 7: Knowledge Management 43
”/var/cfengine/inputs”
handle =¿ ”update˙policy”,
comment =¿ ”Update the cfengine input files from the policy server”,
depends˙on =¿ – ”serve˙updates” ˝,
perms =¿ system(”600”),
copy˙from =¿ rcp(”$(master˙location)”,”$(policy˙server)”),
depth˙search =¿ recurse(”inf”),
file˙select =¿ input˙files,
action =¿ immediate;
This use of annotation is the first level of documentation in cfengine. The annotations are
used internally by cfengine to provide meaningful error messages with context and to compute
dependencies that reveal the existence of process chains. These can be turned into a topic
map for browsing the policy relationships is a web browser, using cf-know.
To set up the knowledge base you will need a computer running an Apache web server with
the PHP module installed. The knowledge base will probably run with other web servers too,
but only Apache is currently supported. To generate the graphical representations, you will
currently need the GraphViz package. See the annex at the end for more details.
So let us spend a while showing how to encode knowledge in topic maps using cf-know.
The kind of result you can expect is shown in the pictures below. The example figures
show typical pages generated by the knowledge agent cf-know. The first of these shows how
44 Cfengine 3 Concept Guide
we use the technology to power the web knowledge base in the Cfengine commercial support
portal ‘Copernicus’.
In this use, all of the data are based on documentation for the cfengine software, and most
of the relationships are manually entered.
For a second example, consider how cfengine can generate such a knowledge map analysis
of its own configuration (self-analysis). The data in the images below describe the cfengine
configuration promises. One such page is generated, for instance, for each policy promise, and
pages are generated for reports from different computers etc. You can also create you own
‘topic pages’ for any local (enterprise) information that you have.
In this example, the promise has been given the promise-handle update˙policy, and the
associations and the lower graph shows how this promise relates to other promises through
its documented dependencies (these are documented from the promisees and depends˙on
attributes of other promises.).
The example page shows two figures, one above the other. The upper figure shows the
thirty nearest topics (of any kind) that are related to this one. Here the relationships are
unspecific. This diagram can reveal pathways to related information that are often unexpected,
Chapter 7: Knowledge Management 45
and illustrates relationships that broaden one’s understanding of the place the current promise
occupies within the whole.
Although the graphical illustrations are just renderings of semantic associations shown more
fully in text, they are useful for visualizing several levels of depth in the associative network.
This can be surprisingly useful for brainstorming and reasoning alike. In particular, one can see
46 Cfengine 3 Concept Guide
the other promises that could be affected if we were to make a change to the current promise.
Such impact analyses can be crucial to planning change and release management of policy.
A knowledge base is an implementation of a Topic Map which is an ISO standard technology.
A topic map works like an index that can point to many different kinds of external resources,
and may contain simple text and images internally. So you use it to bind together documents
of any kind. A cfengine knowledge base is not a new document format, it is an overlay map
that joins ideas and resources together, and displays relationships.
sql˙database =¿ ”test˙map”;
sql˙owner =¿ ”mark”;
sql˙type =¿ ”mysql”;
sql˙passwd =¿ ””; # No passwd for localhost
˝
###################################################
bundle knowledge tm
–
topics:
any::
Computers::
Programs::
Services::
occurrences:
httpd::
”http://www.apache.org”
represents =¿ – ”website” ˝;
###################################################
–
forward˙relationship =¿ ”$(f)”;
48 Cfengine 3 Concept Guide
backward˙relationship =¿ ”$(b)”;
associates =¿ – $(name) ˝;
˝
atlas$ mysql
Welcome to the MySQL monitor. Commands end with ; or “g.
Your MySQL connection id is 1
Server version: 5.0.67 SUSE MySQL RPM
Type ’help;’ or ’“h’ for help. Type ’“c’ to clear the buffer.
Database changed
mysql¿ select * from topics;
+------------+-----------------------------------------+-----------+------------+
— topic˙name — topic˙comment — topic˙id — topic˙type —
+------------+-----------------------------------------+-----------+------------+
— WWW — World Wide Web service — WWW — Services —
— named — A name service process — named — Programs —
— httpd — A web service process — httpd — Programs —
— desktop — Common name for a computer for end users— desktop — Computers —
— server — Common name for a computer in a datacent— server — Computers —
— Computers — Generic boxes — Computers — any —
— Processes — Programs running on a computer — Processes — any —
+------------+-----------------------------------------+-----------+------------+
Hereafter, you do not need to parse the entire data set to use the topic map. You can use
a lightweight ‘driver script’ which is sufficient to query the database for the relationships.
bundlesequence =¿ ”tm” ;
Chapter 7: Knowledge Management 49
query˙output =¿ ”text”;
query˙engine =¿ ”none”;
sql˙database =¿ ”test˙map”;
sql˙owner =¿ ”mark”;
sql˙type =¿ ”mysql”;
sql˙passwd =¿ ””; # No passwd for localhost
###################################################
bundle knowledge tm
topics:
any::
Results:
desktop
server
Associations:
Computers ”run”
- Computers
Computers ”are run on”
- any::Computers
Now if we follow
50 Cfengine 3 Concept Guide
Results:
(none)
Associations:
httpd ”implements”
- Services::WWW
Notice how, in this example, there are two results, one URL and one literal text string.
There is also an association to the WWW service. If we follow this:
Results:
(none)
Associations:
(none)
To render this as a web-page, we change the query output to be ‘html’; cf-know will then
render html pages. A simple wrapper script can be created using a simple PHP script to make
this into a web page, e.g.
¡?php
$arg1 = $˙GET[’next’];
Chapter 7: Knowledge Management 51
$cfknow = ”/usr/local/sbin/cf-know”;
$file = ”/path/to/portal/overview.cf”;
if ($arg1)
–
system(”$cfknow -t $arg1 -f $file”);
˝
else
–
system(”$cfknow -t some˙start˙topic -f $file”);
˝
?¿
Here there are insufficient topics to generate any graphs. A topic must have at least two
associations to warrant a diagram.
Occurrences
Specific information resources: these are pointers to the actual documents that
we want to read (like page numbers in an index).
Types map conveniently into cfengine classes. Topics map conveniently into promisers.
Occurrences also map to promisers of a different type. These three label different levels of
granularity of meaning. Types are represent a set of topics, which in turn encompass a set
of occurrences. The primacy of topics in this stems from their ability to form networks by
association.
The classic approach to information modelling is to build a hierarchical decomposition of
non-overlapping objects. Data are forcibly manipulated into non-overlapping containers which
often prove to be overly restrictive. Topic maps allow us to avoid the kinds of mistakes that
have led to monstrosities like the Common Information Model (CIM) with its thousands of
strictly non-overlapping type categories.
Each topic allows us to effectively ‘shine a light’ onto the occurrences of information that
highlight the concepts pertinent to the topic somehow.
7.7.2 cf-know
Cfengine’s knowledge agent cf-know allows you to make promises about knowledge and its
inter-relationships. It is not specifically a generic topic map language: rather it provides a
powerful configuration language for managing a knowledge base that can be compiled into a
topic map.
The full ISO standard topic map model is too rich to be a useful tool for system knowledge
management. However, this is where powerful configuration management can help to simplify
the process: encoding a topic map is a complex problem in configuration, which is exactly
what cfengine is for. Cfengine’s topic map promises have the following form:
”Other topic”;
occurrences:
Topic˙name:: # Topic
any::
˝
This system configuration promise can be mapped by cfengine into a number of other
promise proposals intended for the “tt cf-know agent. Suppressing some of the details, we
have:
type˙files::
54 Cfengine 3 Concept Guide
”/var/cfengine/inputs”
association =¿ a(”promise made in bundle”,”update”,”bundle contains promise”);
”/var/cfengine/inputs”
association =¿ a(”specifies body type”,”perms”,”is specified in”);
”/var/cfengine/inputs”
association =¿ a(”specifies body type”,”mode”,”is specified in”);
”/var/cfengine/inputs”
association =¿ a(”specifies body type”,”copy˙from”,”is specified in”);
# etc ...
occurrences:
˙var˙cfengine˙inputs::
”promise˙output˙common.html#promise˙˙var˙cfengine˙inputs˙update˙cf˙13”
represents =¿ – ”promise definition” ˝;
Note that in this mapping, the actual promise (viewed as a real world entity) is an occurrence
of the topic ‘promise’; at the same time each promise could be discussed as a different topic
allowing meta-modelling of the entity-relation model in the real-world data. Conversely the
topics themselves become configuration items or ‘promisers’ in the promise model. The effect
is to create a navigable semantic web for traversing the policy; this documents the structure
and intention of the policy using a small ontology of standard concepts and can be extended
indefinitely by human domain experts.
You show create a cf-know control body to point to a database:
body knowledge control
–
# Decide the name of a local database
Chapter 7: Knowledge Management 55
sql˙database =¿ ”cf˙knowledge˙map”;
sql˙owner =¿ ”root”;
sql˙passwd =¿ ””;
sql˙type =¿ ”mysql”;
sql˙server =¿ ”localhost”;
˝
In the community edition, you must create the SQL database for cf-know to write to by
hand, then remember to grant access to the owner as specified above or cf-know will not be
able to add data. This database should have the following tables.
CREATE TABLE topics
(
topic˙name varchar(256),
topic˙comment varchar(1024),
topic˙id varchar(256),
topic˙type varchar(256)
);
8 More...
You will find extensive help, examples and documentation as part of the commerical Cfengine
support. Visit the website www.cfengine.com for more details.
58 Cfengine 3 Concept Guide