Sophie

Sophie

distrib > Mandriva > 8.1 > i586 > by-pkgid > dc430da5aacc0cead97c2e2ef0c82561 > files > 34

cfengine-1.6.3-4mdk.i586.rpm

<html>
<body bgcolor=#eeeeee>
<h1>MANAGING NETWORK SECURITY WITH CFENGINE</h1>

<h2>Mark Burgess</h2>

Computer security is about protecting the data and availability of an
association of hosts. Briefly, the key words are authentication, privacy,
integrity and trust.  To understand computer security we have to
understand the interrelationships between all of the hosts and
services on our networks as well as the ways in which those hosts can
be accessed.  Tools which allow this kind of management are complex
and usually expensive.  A simple free software program which is in
widespread use and whose functionality is at least equal to commerical
packages is cfengine.  Cfengine runs on nearly every Unix-like system
and on NT with the cygwin tools installed.

<p> For a computer to be secure it must be *physically secure* --- if
we can get our hands on a host then we are never more than a
screwdriver away from all of its assets---but assuming that hosts are
physically secure, we then wish to deal with the issues of software
security which is a much more difficult topic.  Software security is
about access control and software reliability.  No single tool can
make computer systems secure.  Major blunders have been made out of
the belief that a single product (e.g. a `firewall') would solve the
security problem. For instance, a few years ago a cracker deleted all
the user directories from a dialup login server belonging to a major
Norwegian telecommunications company, from the comfort of his web
browser. This was possible, even through a firewall, because the web
server on the host concerned was incorrectly configured. The bottom
line is that there is no such thing as a secure operating system, firewall
 or none.  What is required is a persistent mixture of vigilence and
adaptability.

<p> For many, security is perceived as being synonymous with network
privacy or network intrusion.  Privacy is one aspect of security, but
it is not the network which is our special enemy. Many breaches of
security happen from within. There is little difference between the
dangers of remote access from the network or direct access from a
console: privacy is about access control, no matter where the
potential intruder might be.  If we focus exclusively on network
connectivity we ignore a possible threat from internal employees
(e.g. the janitor who is a computer expert and has an axe to grind, or
the mischievous son of the director who was left waiting to play mom's
office, or perhaps the unthinkable: a disgruntled employee who feels
as though his/her talents go unappreciated).  Software security is a
vast subject, because modern computer systems are complex. It is only
exacerbated by the connectivity of the internet which allows millions
of people to have a go at breaking into networked systems. What this
points to is the fact that a secure environment requires a tight
control of access control on every host individually, not merely
at specific points such as firewalls.

<p> This article is not
a comprehensive guide to security. Rather it is an attempt to
illustrate how cfengine can be used to help you automate a level of
host integrity on all the hosts of your network.  Cfengine is a
network configuration tool with two facets.  It is a language used to
build an `expert system'. An expert system describes the way you would like your
hosts and network to look and behave. CFengine is also a software robot which
compares the model you have described with what the world really looks
like and then sets to work correcting any deviations from that picture.
In many ways it is like an immune system, neutralizing and repairing
damaged parts. Unlike many shell-script packages for sysadmin,
cfengine is a C program which means light on system resources. Also it
works on a principle of `convergence'. Convergence means that each
time you run cfengine the system should get closer to the model which
you have described until eventually when the system is the model,
cfengine becomes quiescent, just like an immune system. In the words
of one user your hosts `never get worse'. This assumes of course that
the model you have is what you really want. Using cfengine, model
building becomes synonymous with formulating and formalizing a system
policy.  

<p> What makes cfengine a security tool is that security
policy is a part of system policy: you cannot have one without the
other.  You will never have security unless you are in control of your
network.  Cfengine monitors and indeed repairs hosts with simple
easily controllable actions.  From an automation perspective, security
is no different from the general day to day business of system
maintenance, you just need to pay more attention to the details. We
cannot speak of `have security' and `have not security'. There is
always security, it is simply a matter of degree: weak or strong;
effective or ineffective.

<h2>A word of warning</h2>

Before starting it is only proper to state the obvious. You should
never trust anyone's advice about configuration or security without
running it past your own grey matter first. The examples provided here
are just that: examples. They might apply to you as written and they
might need to be modified. You should never accept and use an example
without thinking carefully and critically first!
Also, in any book of recipies or guide to successful living you
know that there are simplified answers to complex questions and
you should treat them as such. There is no substitute for real
understanding.

<h2>Automation</h2>

Even in the smallest local area network you will want to build a
scheme for automating host configuration and maintenance, because
networks have a way of growing from one host into many quite quickly.
It is therefore important to build a model which scales. A major
reason for using cfengine is precisely for scalability. Whether you
have one host or a hundred makes little difference. Cfengine is
instructed from a central location, but its operation is completely
and evenly spread across the network. Each host is responsible
for obtaining a copy of the network model from a trusted source
and is then responsible for configuring itself without intervention
from outside. Unlike some models, cfengine does not have to rely on
network communication or remote object models.
<p>
We also need
integration, or the ability to manage the interrelationships between
hosts.  It is no good having complete control of one important host
and thinking that you are secure. If an intruder can get into any
host, he or she is almost certain to get into the ones that matter,
especially if you are not looking at all of them.  Using cfengine is a
good way of forcing yourself to formulate a configuration/security
policy and then stick to it.  Why cfengine?  There are three reasons:
i) it forces a discipline of preparation which focuses you on the
problems at the right level of detail, ii) it provides you with
`secure' scalable automation and a common interface to all your hosts,
and iii) it scales to any number of hosts without additional burdens.
We'll need to qualify some of these points below.
<p>
The first step in security management is to figure out a security
policy. That way, you know what *you* mean by security and if that
security is breached, you will know what to do. In many cases you can
formulate a large part of your security policy as cfengine code. That
makes it formal, accurate and it means that it will get done by the
robot without requiring any more work on your part.
<p>
As an immune system, cfengine will even work fine in a partially
connected environment it makes each host responsible for its own
state.  It is not reliant on network connectivty for remote method
invocations or CORBA-style object requests as is, say, Tivoli. All it needs is an
authentic copy of the network configuration document stored locally on
each host.  If this is the case, a detached host will not be left
unprotected, at worst it might lag behind in its version of the
network configuration.

<h2>Trust</h2>

There are many implicit trust relationships in computer systems.
It is crucial to understand them. If you do not understand where
you are placing your trust, your trust can be exploited by
attackers who have thought more carefully than you have.
<p>
For example, any NFS server of users' home-directories trusts the root
user on the hosts which mount those directories.  Some bad accidents
are prevented by mapping root to the user nobody on remote systems,
but this is not security, only convenience.  The root user can always
use `su' to becomes any user in its password file and access/change
any data within those filesystems. The .rlogin and hosts.equiv files
on Unix machines grant root (or other user) privileges to other hosts
without the need for authentication.
<p>
If you are collecting software from remote servers, you should make
sure that they come from a machine that you trust, particularly if
they are files which could lead to privileged access to your system.
Even checksums are no good unless they also are trustworthy.
For example, it would be an extremely foolish idea to copy a binary
program such as /bin/ps from a host you know nothing about.  This
program runs with root privileges. If someone were to replace that
version of ps with a Trojan horse command, you would have effectively
opened your system to attack. Most users trust anonymous FTP servers
where they collect free software.  In any remote copy you are setting
up an implicit trust relationship.  First of all you trust integrity
of the host you are collecting files from.  Secondly you trust that
they have the same username database with regard to access
control. The root user on the collecting host has the same rights to
read files as the root user on the server. The same applies to any
matched user name.

<h2>Why trust cfengine?</h2>

Cfengine has a very simple trust model. It trusts the integrity of its
input file and any data which is explicitly chooses to download. 
Cfengine places the responsibility on root@localhost not
on any outsiders. *You* can make cfengine destroy your system, just as
you can destroy it yourself, but no one else can, so as long as you
are careful with the input file you are trusting essentially no-one.
We shall qualify this below for remote file copying.

<p>
Cfengine assumes that its input file is secure. Apart from that input
file, no part of cfengine accepts or uses any configuration
information from outside sources.  The most one could do from an
authenticated network connection is to ask cfengine to carry out (or
not) certain parts of its model, thus in the worst case scanario an
outside attacker could spoof cfengine into configuring the host
correctly.  In short, no one except root@localhost can force cfengine
to do anything (unless root access to your system has already been
compromised by another route). This means that there is a single point
of failure. The input file does not even have to be private as long as
it is authentic. No one except you can tell cfengine what to do.
<p>
There is a catch though. Cfengine can be used to perform remote file
transfer.  In remote file transfer one is also forced to trust the
integrity of the data received, just as in any remote copy scheme.
Although cfengine works hard to authenticate the identity of the host,
once the host's identity is verified it cannot verify the accuracy of
unknown data it has been asked to receive.  Also, as with all remote
file transfers, cfengine could be tricked by a DNS spoofing into
connecting to an imposter host, so use the IP addresses of hosts, not
their names if you don't trust your DNS service.  In short, these
faults are implicit in remote copying. They do not have to do with
cfengine itself.  This has nothing to do with encryption as users
sometimes believe: encrypted connections do not change these trust
relationships---they improve the privacy of the data being transmitted
not their accuracy or trustworthiness.
<p>
The point of cfengine is normally to have only one global
configuration for every host. This needs to be distributed somehow
which means that hosts must collect this file from a remote server.
This in turn means that you must trust the host which has the master
copy of the cfengine configuration file.

<h2>Configuration</h2>

The beginning of security is correct host configuration. Even if
you have a firewall shielding you from outside intrusion, an
incorrectly configured host is a security risk. Host configuration
is what cfengine is about, so we could easily write a book on this.
Rather than reiterating the extensive documentation, let's just
consider a few examples which address actual problems and get
down to business without further ado.
<p>
A cfengine configuration file is composed of objects with the
following syntax (see the cfengine documentation):
<pre>
  rule-type:

    classes-of-host-this-applies-to::

          Actual rule 1
          Actual rule 2 ...

</pre>
The rule-types include checking file permissions, editing textfiles,
disabling (renaming and removing permissions to) files, controlled 
execution of scripts and a variety of other things relating to host
configuration. Some of the `control' rules are simply flags which
switch on complex (read `smart') behaviour. 
Every cfengine program needs an actionsequence which tells it
the order in which bulk configuration operations should be
evaluated. e.g.

<pre>

control:

  actionsequence = ( netconfig copy processes editfiles )

</pre>
You should look at the cfengine manual to get started
with your configuration.
<p>
Let us step through
some basic idioms which can repeated in different contexts.

As representative examples we shall take solaris and GNU/Linux
as example operating systems. This is not to single them out
as being particularly secure or insecure, it is merely due to their
widespread use and for definiteness.

<h2>Disabling and replacing software</h3>

One of the simplest things which we are asked to do constantly
is to disable dangerous programs as bugs are discovered. CERT
security warnings frequently warn about programs with flaws
which can compromise a system. In cfengine, disabling a file
means renaming it to *.cf-disabled and setting its permission to 400.
<pre>
 disable:

   #
   # CERT security patches
   #

   solaris:: 

     /usr/openwin/bin/kcms_calibrate
     /usr/openwin/bin/kcms_configure
     /usr/bin/admintool
     /etc/rc2.d/S99dtlogin
     /usr/lib/expreserve

   linux::

      /sbin/dip-3.3.7n
      /etc/sudoers
      /usr/bin/sudoers

</pre>
Although this is a trivial matter, the fact that it is automated means
that cfengine is checking for this all the time. As long as a host is
up and running (connected to the network or not) cfengine will be
ensuring the named file is not present.
<p>
Another issue is to replace standard vendor programs with drop-in replacements.
For example, most admins would like to replace their vendor sendmail
with the latest update from Eric Allman's site. One way to do this
is to compile the new sendmail into a special directory, separate
from vendor files and then to symbolically link the new program into
place.
<pre>

 links:

   solaris||linux::

    /usr/lib/sendmail      ->!  /usr/local/lib/mail/bin/sendmail-8.9.3
    /usr/sbin/sendmail     ->!  /usr/local/lib/mail/bin/sendmail-8.9.3
    /etc/mail/sendmail.cf  ->!  /usr/local/lib/mail/etc/sendmail.cf

</pre>
The exclamation marks mean (by analogy with the csh) that existing
file objects should be replaced by links to the named files. Again
the integrity of these links is tested every time cfengine runs.
If the object /usr/lib/sendmail is not a link to the named file, the old
file is moved and a link is made. If the link is okay, nothing happens.
After putting the new sendmail in place, you will need to
make sure that the restricted shell configuration is in order.

<pre>
   #
   # Sendmail, restricted shell needs these links
   #

   solaris::

     # Most of these will only be run on the MailHost
     # but flist (procmail) is run during sending...

     /usr/adm/sm.bin/vacation -> /usr/ucb/vacation
     /usr/adm/sm.bin/flist   ->  /home/listmgr/.bin/flist

   linux::

     /usr/adm/sm.bin/vacation -> /usr/bin/vacation

</pre>
<p>
Link management is a particularly useful feature of cfengine.
By putting links (actually all system modifications) into the
cfengine configuration and never doing anything by hand,
you build up a system which is robust to reinstallation. If you
lose your host, you just have to run cfengine once or twice
to reconstruct it.
<p>
Of course, the fundamental tenet of security is to be able to
restrict privilege to resources. We therefore need to check the permissions on
files. For instance, a recent CERT advisory warned of problems with
some free unix mount commands which were setuid root. If we suppose
there is a group of hosts called `securehosts' which we don't need to worry
about, then we could remove the setuid bits on all other hosts as
follows:
<pre>

 files:

   !securehosts.linux::

      /bin/mount     mode=555 owner=root action=fixall
      /bin/umount    mode=555 owner=root action=fixall

   securehosts.linux::

      /bin/mount      m=6555 o=root action=fixall
      /bin/umount     m=6555 o=root action=fixall

</pre>
One area where cfengine excels over other tools is in its ascii file
editing abilities. Editing textfiles in a non-destructive way is such
an important operation that having used it you will wonder how you
every managed without it! Here are some simple but real examples
of how file editing can be used.
<pre>

 editfiles:

   # sun4, who are they kidding?

   { /etc/hosts.equiv

   HashCommentLinesContaining "+"
   }

   #
   # CERT security patch for vold vulnerability
   #

   sunos_5_4::

      { /etc/rmmount.conf

      HashCommentLinesContaining "action cdrom"
      HashCommentLinesContaining "action floppy"
      }

</pre>
TCP wrapper configuration can be managed easily by maintaining
a pair of master files on a trusted host. Files of the form
<pre>

 # /etc/hosts.allow (exceptions)
 #
 # Public services

 sendmail: ALL
 in.ftpd:  ALL
 sshd:     ALL

 # Private services

 in.fingerd:  .mydomain.country LOCAL
 in.cfingerd: .mydomain.country LOCAL
 cfd:         .mydomain.country LOCAL
 sshdfwd-X11: .mydomain.country LOCAL

 # Portmapper has to use IP series

 portmap: 128.39.89. 128.39.74. 128.39.75.
</pre>
and
<pre>

 # /etc/hosts.deny (default)

 ALL: ALL

</pre>
may be distributed to each host by cfengine
<pre>
copy:

 /masterfiles/hosts.deny dest=/etc/hosts.deny 
                         mode=644
                         server=trusted
 /masterfiles/hosts.allow dest=/etc/hosts.allow 
                          mode=644 
                          server=trusted
</pre>
and installed as follows
<pre>
 editfiles:

      { /etc/inet/inetd.conf

      # Make sure we're using tcp wrappers

      ReplaceAll "/usr/sbin/in.ftpd"    With "/local/sbin/tcpd"
      ReplaceAll "/usr/sbin/in.telnetd" With "/local/sbin/tcpd"
      ReplaceAll "/usr/sbin/in.rshd"    With "/local/sbin/tcpd"
      ReplaceAll "/usr/sbin/in.rlogind" With "/local/sbin/tcpd"

 processes:

      "inetd" signal=hup

</pre>
The services which we do not need should be removed altogether.
There's no sense in tempting fate:
<pre>

editfiles:

      { /etc/inetd.conf

      # Eliminate unwanted services

      HashCommentLinesContaining "rwall"
      HashCommentLinesContaining "/usr/sbin/in.fingerd"
      HashCommentLinesContaining "comsat"
      HashCommentLinesContaining "exec"
      HashCommentLinesContaining "talk"
      HashCommentLinesContaining "echo"
      HashCommentLinesContaining "discard"
      HashCommentLinesContaining "charge"
      HashCommentLinesContaining "quotas"
      HashCommentLinesContaining "users"
      HashCommentLinesContaining "spray"
      HashCommentLinesContaining "sadmin"
      HashCommentLinesContaining "rstat"
      HashCommentLinesContaining "kcms"
      HashCommentLinesContaining "comsat"
      HashCommentLinesContaining "xaudio"
      HashCommentLinesContaining "uucp"
      }

</pre>


<h3>Process monitoring</h3>


When it comes to process management we are usually interested in
three things: i) making sure certain processes are running,
ii) making sure some processes are NOT running and iii)
sending HUP signals to force configuration updates.
To HUP a daemon and make sure that it is running, we write
<pre>
processes:

 linux::
  
  "inetd"  signal=hup restart "/usr/sbin/inetd"   useshell=false
  "xntp"              restart "/local/sbin/xntpd" useshell=false
 
</pre>
The useshell option tells cfengine that it should not use a shell
to start the program. The idea here is to protect against IFS attacks.
Unfortunately some programs require a shell in order to be started,
but most do not. This is an extra precaution.
When the cron daemon crashes, restarting it can be a problem
since it does not close its filed descriptors properly when forking.
The dumb-option helps here:
<pre>

  "cron" matches=>1 restart "/etc/init.d/cron start"  useshell=dumb

</pre>
To kill processes which should not be running, we write:

<pre>

 processes:

   solaris::

   #
   # Don't want CDE stuff or SNMP peepholes...
   #

    "ttdbserverd" signal=kill
    "snmpd"       signal=kill
    "mibiisa"     signal=kill

</pre>

A couple of years ago, a broken cracked account was revealed at
Oslo College by the following test in the cfengine configuration:

<pre>
processes:

   # Ping attack ?

   "ping"  signal=kill inform=true

</pre>
There are few legimate reasons to run the ping command more than a few
times. The chances of cfengine detecting single pings is quite small.
But coordinated ping attacks are another story. When it was revealed
that a user had twenty ping processes attempting to send large ping
packets to hosts in the United States it was obvious the the account
had been compromised. Fortunately for the recipient, the ping command
was incorrectly phrased and would probably not have been noticed.

<pre>
processes:

     "sshd"        
                  restart "/local/sbin/sshd"
                  useshell=false    

     "snmp"       signal=kill
     "mibiisa"    signal=kill

     "named"      matches=>1
                  restart "/local/bind/bin/named"
                  useshell=false

     # Do the network community a service and run this

     "identd"   restart "/local/sbin/identd" inform=true

</pre>
Process management also includes the garbage collection
which we shall return to briefly.

<h2>Monitoring files</h2>

Almost all security programs available are for the monitoring of
file integrity. Cfengine also incorporates tools for monitoring
files. Here are some of the elements in the faily complex files
command:
<pre>

 files:

     classes::

        /file-object
                          mode=mode
                          owner=uid-list
                          group=gid-list
                          action=fixall/warnall..
                          ignore=pattern
                          include=pattern
                          exclude=pattern
                          checksum=md5
                          syslog=true/on/false/off

</pre>

 In additions to these, there are extra flags for BSD filesystems and
ways of managing file ACLs for systems like NT.
Here are some examples of basic checks on file permissions:

<pre>

 classes:

  # Define a class of hosts based on a test...

  have_shadow = ( `/bin/test -f /etc/shadow` )

  NFSservers = ( server1 server2 )

 files:

   any::

      /etc/passwd mode=0644 o=root  g=other  action=fixplain

   have_shadow::

      /etc/shadow mode=0400 o=root  g=other  action=fixplain

   # Takes a while so do this at midnight and only on servers

   NFSservers.Hr00::

      /usr/local 
            mode=-0002   Check no files are writable!
            recurse=inf 
            owner=root,bin 
            group=0,1,2,3,4,5,6,7,staff
            action=fixall

</pre>
In the last example we parse through a whole file system (recurse=inf)
and as a result we get a number of checks for free. Any previously
unknown setuid programs are reported as well as any suspicious
filenames (see below).

<h3>The setuid log</h3>

Cfengine is always on the lookout for files which are setuid or setgid
root.  It doesn't go actively looking for them uninvited, but whenever
you get cfengine to check a file or directory with the files feature,
it will make a note of setuid programs it finds there. These are
recorded in the file cfengine.host.log which is stored under
/etc/cfengine or /var/log/cfengine.
When new setuid programs are discovered, a warning is printed, but only
if you are root. If you ever want a complete list, delete the log
file and cfengine will think that all of the setuid programs it finds
are new. The log file is not readable by normal users.

<h3>Suspicious filenames</h3>

Whenever cfengine opens a directory and scans through files and
directories (recursively) (files, tidy, copy), it is also on the
lookout for for suspicious filenames, i.e. files like "..  ."
containing only space and/or dots. Such files are seldom created by
sensible sources, but are often used by crackers to try to hide
dangerous programs. Cfengine warns about such files. Although not
necessarily a security issue, cfengine will also warn about filenames
which contain non-printable characters if desired, and directories
which are made to look like plain files by giving them filename
extensions.
<pre>

control:

   #
   # Security checks
   #

   NonAlphaNumFiles = ( on )
   FileExtensions = ( o a c gif jpg html ) # etc
   SuspiciousNames = ( .mo lrk3 lkr3 )

</pre>
The file extension list may be used to detect concealed directories during
these searches, if users create directories which look like common
files this will be warned about. Additional suspicious filenames
can be checked for automatically as a matter if course. This is commented
further below.

The mail spool directory is a common place for users to try to hide
dowloaded files. These options inform about files which do not have
the name of a user or are not owned by a valid user:
<pre>

 control:

   WarnNonOwnerMail = ( true )
   WarnNonUserMail = ( true )  # Warn about mail which is not owned by a user

</pre>
Corresponding commands exist to delete these files without further ado.
This can be a useful way of cleaning up after users whose accounts
have been removed.


<h3>Checksums and Tripwire functionality</h3>

Cfengine can be used to check for changes in files which only something
as exacting as an MD5 checksum/digest can detect. If you specify a
checksum database and activate checksum verification,
<pre>

control:

  ChecksumDatabase = ( /etc/cfengine/cache.db )

  ChecksumUpdates = ( false )

files:

    /filename checksum=md5 ....
    /dirname  checksum=md5 recurse=inf....

    # If the database isn't secure, nothing is secure...

    /etc/cfengine/cache.db  mode=600 owner=root fixall

</pre>
then cfengine will build a database of file checksums and warn you when
files' checksums change. This makes cfengine act like Tripwire
(currently only with MD5 checksums). It can be used to show up Trojan
horse versions of programs. It should be used sparingly though since
database management and MD5 checksum computation are resource
intensive operations and this could add significant time to a cfengine
run. The ChecksumUpdates variable (normally false) can be set to true
to update the checksum database when programs change for valid
reasons.

Warnings are all every fine and well, but the spirit of cfengine is
not to bother us with warnings, it is to fix things automatically.
Warning is a useful supplement, but in security breaches it is better
to fix the problem, rather than leaving the host in a dangerous state.
If you are worried about the integrity of the system then don't just
warn about checksum mismatches here, make an md5 copy comparison
against a read-only medium which has correct, trusted version of the
file on it. That way if a binary is compromised you will not only warn
about it but also repair the damage immediately!

The control variable ChecksumUpdates may be switched to on
in order to force cfengine to update its checksum database after
warning of a change.

<h3>FileExtensions</h3>

This list may be used to define a number of extensions
which are regarded as being plain files by the system.
As part of the general security checking cfengine will
warn about any directories which have names using
these extensions. They may be used to conceal directories.
<pre>

  FileExtensions = ( c o gif jpg html )

</pre>

<h3>NonAlphaNumFiles</h3>

If enabled, this option causes cfengine to detect and
disable files which have purely non-alphanumeric
filenames, i.e. files which might be accidental or
deliberately concealed. The files are then marked
with a suffix .cf-nonalpha and are rendered
visible.
<pre>

  NonAlphaNumFiles = ( on )

</pre>
These files can then be tidied (deleted) or disabled by searching for
the suffix pattern. Note that alphanumeric means ascii codes less than
32 and greater than 126.

<h3>Defensive garbage collection</h3>

We tend to be worried about the fact that crackers will destroy our
systems and make them unusable, but many operating systems are
programmed to do this to themselves!  There are few systems which can
survive a full system disk and yet many logging agents go on filling
up disks without ever checking to see how full they are getting. In
short they choke themselves in a self-styled denial of service attack.
Cfengine can help here by rotating logs frequently and by tidying
temporary file directories:
<pre>

disable:

  Tuesday.Hr00::

   #
   # Disabling these log files weekly prevents them from
   # growing so enormous that they fill the disk!
   #

   /local/iu/httpd/logs/access_log   rotate=2
   /local/iu/httpd/logs/agent_log    rotate=2
   /local/iu/httpd/logs/error_log    rotate=2
   /local/iu/httpd/logs/referer_log  rotate=2

  FTPserver.Sunday::

   /local/iu/logs/xferlog rotate=3

tidy:

    /tmp pattern=* age=1

</pre>


Process garbage collection is just as important. 
There are lot's of reasons why process tables
fill up with unterminated processes. One example
is faulty X terminal software which does not kill
its children at logout. Another is that programs
like netscape and pine tend to go into loops from
which they never return, gradually loading the system
with an ever increasing glacial burden. Just killing
old processes can cause your system to spring back
from its ice age blues (hopefully without littering
the system with too many dead mammoths or bronze age
axe-bearers). If the host concerned has important
duties then this lack of responsiveness can compromise
key services. It also gives local users a way of carrying
out denial of service attacks on the system.
<p>
If users always log out at the end of the day and
log in again the day after then this is easy to address
with cfengine. Here is some code to kill commonly hanging
processes. Note that on BSD like systems process options
"aux" are required to see the relevant processes: 
<pre>
processes:

  linux|freebsd|sun4::

      SetOptionString "aux"

  any::

  "Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec"  

      signal=kill 

      include=ftpd
      include=tcsh 
      include=xterm  
      include=netscape
      include=ftp
      include=pine
      include=perl
      include=irc
      include=java
      include=/bin/ls
      include=emacs
      include=passwd

</pre>
This pattern works like this: as processes become more than a day old
they name of the month appears in the date of the process start
time. These are matched by the regular expression. The include
lines then filter the list of the processes further picking out
lines which include the specified strings.
On some BSD-like systems the default ps option string is
"-ax" and you might need to reset it to something
which adds the start date in order to make this work.


Another job for process management is to clean up processes which
have hung, gone amok or which are left over from old logins. Here
is a regular expression which detects non-root processes which
have clocked up more than 100 hours of CPU time. This is a depressingly
common phenomenon when a program goes into an infinite loop. It can
starve other processes of resources in a very efficient denial
of service attack.
<pre>
 any::

  #
  # Kill processes which have run on for too long e.g. 999:99 cpu time
  # Careful a pattern to match 99:99 will kill everything!
  #

  "[0-9][0-9][0-9][0-9]:[0-9][0-9]" signal=term exclude=root
       "[0-9][0-9][0-9]:[0-9][0-9]" signal=term exclude=root     
</pre>
Under NT this is not so simple, since the process table for
the cygwin library applies only to processes which have been
started by programs working under the Unix process emulation.
Hopefully this short-coming can be worked around at some point
in the future.

<h3>Anonymous FTP example</h3>

Configuring a service like anonymous FTP requires a certain amount of
vigilance. It is a good idea to automate it and let cfengine make sure
that things don't go astray.  Note that we constantly ensure that the
ls program used by the anonymous ftp server is a trusted program by
checking it with an md5 signture of a trusted version of the
program. If for some reason it should be replaced with a Trojan horse,
cfengine would notice the incorrect checksum (md5) and move the bad
program to ls.cf-saved and immediately replace it with the correct
version without waiting for the adminstrator to act. The inform and
syslog options ask for an explicit warning to be made about this copy.
Here is a complete anonymous ftp setup and maintenance program for
solaris hosts.
<pre>

control:

   actionsequence = ( directories copy editfiles files )

   # Define variables

   ftp = ( /usr/local/ftp )
   uid = ( 99 )  # ftp user
   gid = ( 99 )  # ftp group

directories:

 solaris::

   $(ftp)/pub      mode=644 owner=root group=other
   $(ftp)/etc      mode=111 owner=root group=other
   $(ftp)/dev      mode=555 owner=root group=other
   $(ftp)/usr      mode=555 owner=root group=other
   $(ftp)/usr/lib  mode=555 owner=root group=other

files:

  solaris::

   $(ftp)/etc/passwd mode=644 o=root    action=fixplain
   $(ftp)/etc/shadow mode=400 o=root    action=fixplain
   $(ftp)/pub        mode=644 owner=ftp action=fixall  recurse=inf

copy:

  solaris::

      # Make sure ls is a trusted program by copying 
      # a secure location...

   /bin/ls dest=$(ftp)/usr/bin/ls 
           mode=111 
           owner=root 
           type=checksum
           inform=true
           syslog=true

   /etc/netconfig dest=$(ftp)/etc/netconfig mode=444 o=root

   /devices/pseudo/mm@0:zero      dest=$(ftp)/dev/zero      mode=666 o=root
   /devices/pseudo/clone@0:tcp    dest=$(ftp)/dev/tcp       mode=444 o=root
   /devices/pseudo/clone@0:udp    dest=$(ftp)/dev/udp       mode=666 o=root
   /devices/pseudo/tl@0:ticotsord dest=$(ftp)/dev/ticotsord mode=666 o=root

   /usr/lib        dest=$(ftp)/usr/lib recurse=2     
                   mode=444 
                   owner=root
                   backup=false
                   include=ld.so*
                   include=libc.so*
                   include=libdl.so*
                   include=libmp.so*
                   include=libnsl.so*
                   include=libsocket.so*
                   include=nss_compat.so*
                   include=nss_dns.so*
                   include=nss_files.so*
                   include=nss_nis.so*
                   include=nss_nisplus.so*
                   include=nss_xfn.so*
                   include=straddr.so*

   /usr/share/lib/zoneinfo dest=$(ftp)/usr/share/lib/zoneinfo
                    mode=444 recurse=2 o=root type=binary

editfiles:

   solaris::
         
    #
    # Make sure that umask is right for ftpd
    # or files can be left 666 after upload!
    #

  { /etc/rc2.d/S72inetsvc

  PrependIfNoSuchLine "umask 022"
  }

  { $(ftp)/etc/passwd

  AutoCreate
  EmptyEntireFilePlease
  AppendIfNoSuchLine "ftp:x:$(uid):$(gid):Anonymous FTP:$(ftp):/bin/sync"
  }

  { $(ftp)/etc/group

  AutoCreate
  EmptyEntireFilePlease
  AppendIfNoSuchLine "ftp::$(gid):"
  }

  {  $(ftp)/etc/shadow

  AutoCreate
  EmptyEntireFilePlease
  AppendIfNoSuchLine "ftp:NP:6445::::::"
  }

  # Finally...useful for chown

  { /etc/passwd

  AppendIfNoSuchLine "ftp:x:$(uid):$(gid):Anonymous FTP:$(ftp):/bin/sync"
  }

  { /etc/group

  AppendIfNoSuchLine "ftp::$(gid):"
  }



</pre>

<h3>WWW security</h3>

The security of the web is a slightly paradoxical business.  On the
one hand, we make a system for distributing files to anyone without
the need for passwords, and on the other hand we are interested in
limited who gets what information and who can change what. If you want
web privacy you have to exclude the possibility of running untrusted
CGI scripts, i.e. CGI programs which you did not write yourself since
CGI programs can circumvent any server security.  This is because of a
fundamental weakness in the way that a WWW server works.  It makes
user-CGI scripts incompatible with the idea of private WWW areas.
<p>
The problem with CGI is this: in order for the httpd daemon to be able
to read information to publish it, that information must be readable
by the UID with which httpd runs (e.g. the www special user (you
should not run with uid nobody since that can be mixed up with NFS
mappings)).  But CGI programs automatically run with this www UID
also. Since it is not possible to restrict the actions of CGI programs
which you did not write yourself, any CGI program has automatically
normal file permission access to any file which the server can see. A
CGI program could choose to open a restricted file circumventing the
security of the daemon. In short, privacy requires a separate UID (a
separate daemon and port number) or a separate server host altogether.
<p>
Provided you acknowledge this weakness, you can still use cfengine to administrate
the permissions and access files on say two WWW servers from
your central location. Let us imagine having a public WWW server
and a private WWW server and assume that they have a common
user/UID database. We begin by defining a user-ID and group-ID
for the public and private services. These need to have different
ID's in order to prevent the CGI trick mentioned above.

<pre>
editfiles:

 wwwpublic::

  { $(publicdocroot)/.htaccess

  AutoCreate
  EmptyEntireFilePlease
  AppendLine "order deny,allow"
  AppendLine "deny from all"
  AppendLine "allow from all"
  }

 wwwprivate::

  { $(privatedocroot)/.htaccess

  AutoCreate
  EmptyEntireFilePlease
  AppendLine "order deny,allow"
  AppendLine "deny from all"
  AppendLine "allow .mydomain.country"
  }

</pre>
Your documnts should be owned by a user and group which is
*not* the same as the UID/GID the daemon runs with, otherwise
CGI programs and server-side emebellishments could write and
destroy those files. You will also want to ensure that the files
are readable by the www daemon, so a files command can be used to this end.
You might want a group of people to have access to the files to
modifiy their contents.
<pre>

 files:

 wwwprivate::

   $(privatedocroot) mode=664 owner=priv-data group=priv-data act=fixall

 wwwpublic::

   $(publicdocroot) mode=664 owner=public-data group=public-data act=fixall


</pre>



<h2>Pitfalls</h2>

Cfengine's ability to run your network depends on the fact that
it gets run. Normally you will run cfengine every hour or so
as a cron task, but if you use cfengine itself to update cfengine's
configuration from a trusted host then a syntax error can bring
this model to a quick halt. If cfengine cannot parse its configuration
file it will not be able to update, so one error here would be a
distaster. The solution is to use a separate, simple script which
only updates the configuration in case of accidents.

For example, you can get cfengine to install itself in the cron
file like this:

<pre>

control:

  cfbin = ( /usr/local/sbin )

editfiles:

   { /var/spool/cron/crontabs/root

    AppendIfNoSuchLine "0,30 * * * * $(cfbin)/cfwrap $(cfbin)/cfnormal"
    AppendIfNoSuchLine "15 * * * * $(cfbin)/cfwrap $(cfbin)/cfupdate"
    }      

</pre>
cfwrap is a wrapper script included with cfengine which mails the
output of cfengine to someone more useful than root (the owner of the cron
job). cfnormal is then a small script which sets environment variables
to point to your cfengine input files and runs cfengine:

<pre>
#!/bin/sh
# cfnormal

CFINPUTS /etc/cfengine/inputs  ; export CFINPUTS
/etc/cfengine/bin/cfengine      
</pre>
cfupdate,  on the other hand, runs a special file whose job
it is to copy cfengine and its configuration to a known local
file system, e.g. /etc:

<pre>
#!/bin/sh
# cfnormal

CFINPUTS /etc/cfengine/inputs  ; export CFINPUTS
/etc/cfengine/bin/cfengine -f cf.update 
</pre>
and cfupdate is a cfengine program which makes sure that
the configuration file is up to date
<pre>
#
# Script only distributes the configuration
#

control:

 actionsequence = ( copy )
 domain = ( iu.hioslo.no )

copy:

     /local/share/cfengine dest=/etc/cfengine
                           recurse=inf
                           mode=a+rx
                           type=binary
                           exclude=*.lst
                           server=trustedhost

     /local/sbin/cfengine  dest=/etc/cfengine/bin/cfengine 
                           mode=755  
                           type=checksum 
                           server=trustedhost
</pre>
The purpose of this roundabout method is that, should network
connections go down, cfengine will have everything it needs to do its
job on a local file system, just like an immune system. Even if you
insert a typo into the main cfengine configuration file (run by
cfnormal) updates will get distributed around the network, so, while you will
be able to shoot yourself in the foot, you will not be able to
shoot yourself in the head.  Of course cfengine will not be able
to copy file updates from a server if the network is unavailable, but
it will still do its job of checking and watching over the system in
every other respect. In this way, it is impossible to perform a
complete denial of service attack on cfengine. This can be contrasted
with other systems which use network protocols in every operation.
<p>
If you use cfengine on hosts which have mounted NFS filesystems,
it is a bad idea to give hosts setuid permissions on those NFS
file systems. This can lead to accidents (this is precisely why
the root -> nobody mapping exists). Normally cfengine detects
NFS filesystem boundaries and does not descend into such filesystems
during recursive operations, but if you make filesystems setuid root
this can fail.
<p>
Always remember that processes which are started by a script or by
cfengine inherit the environment variables which the parent script
has, including the timezone, path and umask. If you are unwary, you
might end up resetting the system clock or permission mask for certain
services. Be careful.


<h2>Miscellaneous Security of cfengine itself</h2>
<pre>

 control:

   SecureInput  = ( on ) 

</pre>
If this is set cfengine will not read any files which are not owned by
the uid running the program, or which are writable by groups or others.

<h3>Privacy (encryption)</h3>

Encryption (privacy) is not often a big deal in system
administration. With the exception of the distribution of passwords and secret
keys themselves, there is little or no reason to maintain any level of
privacy when transferring system files (binaries for instance).  If
you find yourself using a tool like cfengine to transmit company
secrets from one place to another you should probably book yourself
into the nearest asylum for a checkup. Cfengine is not about super-secure
communication, but it can be used to perform the simple job of file
distribution through an encrypted link (e.g. as a NIS replacement or
other password distributor). Cfengine uses the triple DES implemenation
in Eric Young's SSLeay distribution (or equivalent) to provide
`good enough' privacy during remote copying. 
<p>
The most important issue in system security is authentication.
Without the ability to guarantee the identity of a user or of trusted
information it is impossible to speak of security at all.  Although
services like pidentd can go some way to confirming the identity of a
user, the only non-spoofable way of confirming identity is to use a
shared secret --- i.e. a password. A password works by demanding that
two parties who want to trust one another must both know a piece of
information which untrusted parties do not.
<p>
Following the second world war, the now famous pair, Julius and Ethel Rosenberg
were convicted and executed for spying on the U.S. bomb project for
the Soviet Union in 1953. At one point they improvised a clever
password system: a cardboard Jell-O box was torn in two and one half
given to a contact whom they later would need to identify.  The
complex edge shape and colour matching made a complex key quite
impossible to forge. Our bodies use a similar method of receptor
identification of molecules for immune responses as well as for smell
(with some subtleties).  Without matching secrets it is impossible to
prove someone's identity.
<p>
To copy a file over an encrypted link, you write:
<pre>

 copy:

    source dest=destination secure=true server=trusted

</pre>
Bear in mind that the server must be a trusted host. Privacy
won't help you if the data you are collecting are faulty.
In order to use the DES algorithm there must be a secret key known by
both hosts. You can use the program cfkey to generate a new key
file. This file must then be distributed.  In programs like ssh a
method of key-exchange is used.  The problem of how secret keys are
distributed is subtle.  The process must be bootstrapped, preferably
under secure conditons.
<p>
Under secure communications cfengine conceals the names and contents
of files. Initially private keys are used to transmit a session key
which is combined with part of the private key to randomize it, and
also to avoid replay attack. Provided the key files are private, this
has the added side effect of authenticating both hosts for one another.
<p>
On the server side, you can choose whether root on a client host
should have root privileges to read protected files on the server. In the
cfd.conf file you make a list, rather like for NFS:
<pre>
admit:

  /filetree *.domain.country root=myhost,yourhost

  /etc/shadow *.domain.country secure=true

</pre>
In the second example, you can also restrict access to certain
files to secure lines, i.e. demand that clients use a private
connection to collect the file, in order to prevent wiretapping.

<h3>Adaptive locks. </h3>

Cfengine treats all of its operations as transactions
which are locked. Locking prevents contention from competing processes
and it also places reasonable limits on the execution of the program.
The fact that operations are locked means that several cfengine
programs can coexist without problems. Two locking parameters control
the way in which operations can procure locks.  The IfElapsed
parameter tells operations that they can only be performed if a
certain period of time has elapsed since the last time the action was
performed. This is anti-spamming protection.  The ExpireAfter
parameter tells cfengine that no action should last more than a given
length of time. This is protection against hanging sub-processes.

<h3>Spoofing</h3>

Spoofing refers to attempts to masquerade as another host when sending
network transmissions. The cfd program which can be used to
transfer files or activate cfengine remotely attempts to unmask such
attempts by performing double reverse lookups in the name service. This
verifies by a trusted server that the socket address and the host name
are really who they claim to be. If you have the TCP wrappers package
on your system (libwrap) then cfd will use this as additional protection. 
Also if you have
<pre>

  CheckIdent = ( on )

</pre>
cfd will demand verification of connections by attempting to connect to a pidentd
server on the calling host. Secret keys also provide protection against
spoofing by providing a conformation of trustworthiness based on a shared
secret.

<h3>Race conditions in file copying</h3>

When copying files from a source, it is possible that something
might go wrong during the operation and leave a corrupt file in
place. For example, the disk might become full while copying
a file. This could lead to problems. Cfengine deals with this
by always copying to a new file on the destination filesystem
(prefix .cfnew) and then renaming it into place, only
if the transfer was successful. This ensures that there is
space on the filesystem and that nothing went wrong with
the network connection or the disk during copying.

<h3>size= in copy</h3>

As a further check on copying, cfengine allows you to define acceptable
limits on the size of files. After all, sometimes errors might occur
quite independently of anything you are doing with cfengine. Perhaps the
master password file got emptied somehow, or got replaced by a binary,
through some silly mistake. By checking making an estimate of the
expected size of the file and adding it to the copy command, you can
avoid installing a corrupt file and making a localized problem into a
global one.

<h3>useshell= and owner= in shellcommands</h3>

There are dangers in starting scripts from programs which run with root
privileges. Normally, shell commands are started by executing them with
the help of a /bin/sh -c command. The trouble with this is that
it leaves one open to a variety of attacks. One example is fooling the
shell into starting foreign programs by manipulating the IFS
variable to treat '/' as a separator. You can ask cfengine to start
programs directly, without involving an intermediary shell, by setting
the useshell variable to false. The disadvantage is that you will
not be able to use shell directives such as | and > in
your commands. The owner=uid directive executes shell commands
as a special user, allowing you to safely run scripts without
root privilege.


<h2>Firewalls</h2>

Cfengine is a useful tool for implementing, monitoring and maintaining
firewalls. You can control what programs are supposed to be on the
firewall and what programs are not supposed to be there. You can control
file permissions, processes and a dozen other things which make up the
configuration of a bastion host. 
By referencing important programs against a read only medium you
can not only monitor host integrity but always be certain that
you are never more than a cfengine execution away from correctness.

<h2>Summary</h2>

Cfengine is not a tool, it is an environment for managing
host configuration and integrity. In this article it has only
been possible to scratch the surface of what cfengine can do.
To fully understand the syntax of the examples here you should
read the documentation for cfengine.
<p>
The big advantage of cfengine over many other configuration schemes is
that you can have *everything* in one file (or set of files). The
global file is common to every host and yet it can be as general or as
specific as you want it to be.  You can use it as a
front end for cron, and you can use its advanced features to make your
hosts *converge* to a desired, correct state.

Cfengine 1.5.0 is available for most kinds of Unix and for NT (with
the cygwin-32 package). It is easily portable to other platforms.

You can read more about it and obtained it from
http://www.iu.hioslo.no/cfengine


</body>
</html>