One way to manage local configuration of multiple systems is to put the configuration files and other mechanisms into the files and install scripts of a Debian package. Some advantages of doing this:

The disadvantage of building configuration packages:

Setup basic package

  1. mkdir _packagename_-1
  2. cd _packagename_-1
  3. dh_make --native
    1. s
  4. debian/changelog
    1. unstable -> company

    2. _username_@company.com

  5. debian/control
    1. Maintainer: _x_-team@company.com

    2. Section: _same as package it configures_
    3. Depend: on the package and versions appropriate
    4. Section and Priority to match upstream package
    5. Description: fill in both single line and longer description. List files being configured.
  6. Makefile
    1. debian/rules calls this without args to "build". Do nothing on the first target (eg. all:)
    2. calls clean. Do nothing here either.
    3. calls install. cp and mkdir relative to $(DESTDIR) to put files in the package.

conffiles

Roughly 20% of the packages in Debian and Ubuntu ship default configuration files. If these are simply replaced, an upstream update later that modifies the same configuration file will throw dpkg into an interactive conflict resolution system. This is best avoided to make updates non-interactive. To avoid dpkg handling, the upstream package is diverted to a non-active file, and restored on removal of the config package. Placing this diversion and replacement package in its own config package allows the package to be installed by debian-installer before first boot.

The replacement file is best provided as a regular package file (not a conffile) somewhere other than the original location, and symlinked from /etc. This avoids making the replacement file also a conffile. There are complex interaction cases where a package may be removed but its configuration files remain on the system. If the replacements are also configuration files, there are twice as many cases of package installation states to deal with, and no preinst or postrm scripts to execute any logic to handle the additional cases. conffiles are listed in /var/lib/dpkg/info/*.conffiles for each package.

The recommended method to assemble -config packages is to divert and symlink in the postinst, and remove symlinks and diversions in the prerm script. The symlinks are only created if the path is either not present or is already a symlink, and only removed if the path is a symlink. One suggested location is /etc/site/. This requires a purge of the conffiles in the package build, and will generate a linitian error.

The config-package-dev package provides CDBS rules files that help automate much of the work of creating Debian configuration packages using the divert-and-symlink technique with careful error checking and support for apply simple modifications to a Debian upstream configuration file in a way that is easy to maintain over time. It is available in Debian lenny or later. You can read the config-package-dev documentation at http://debathena.mit.edu/config-package-dev for details on how to use it.

Another option is to replace both the file and the checksum so dpkg is unaware of a change, though this would result in new upstream configuration files replacing the locally customized one.

debian/postinst

#!/bin/sh
set -e
PKG=company-service-config
if [ "$1" = configure ] ; then
        for f in auto.master gssapi_mech.conf
        do
                dpkg-divert --add --package ${PKG} --rename \
                        --divert /etc/$f.distrib /etc/$f
                [ \! -e /etc/$f -o -L /etc/$f ] && ln -sf /etc/site/$f /etc/$f
        done
fi
#DEBHELPER#
exit 0

debian/prerm

#!/bin/sh
set -e
PKG=company-service-config
if [ "$1" = remove ] ; then
        for f in gssapi_mech.conf auto.master
        do
                [ -L /etc/$f ] && rm /etc/$f
                dpkg-divert --remove --package ${PKG} --rename \
                        --divert /etc/$f.distrib /etc/$f
        done
fi
#DEBHELPER#
exit 0

To prevent files in /etc/site in the -config package from becoming conffiles themselves, in the -config debian/rules file, remove or purge the automatically generated DEBIAN/conffiles file after dh_installdeb runs.

debian/rules

binary-arch: build install
        ...
        dh_installdeb
        rm debian/company-service-config/DEBIAN/conffiles
        ...

debconf-generated configuration files

Roughly 5% of Debian packages use the debconf database and custom scripts using that data to generate configuration files. These scripts are located in /var/lib/dpkg/info/*.config. While there aren't a large number of these packages, they tend to be the most critical and important packages, and each one is a custom script that must be understood before you take over control of its configuration file. If dlocate /etc/filename doesn't locate a package, there's a good chance the configuration file is a debconf-generated file.

In the ideal case, there are values you can put in the debconf system that will generate the correct file. These can be done using debconf-set-selections and dpkg-reconfigure in the -config postinst script or in the installer preseed. Many .config scripts are rudimentary and are incapable of generating the required configuration file.

Typically, you should start by diverting the existing file using the method described above for conffiles, but also take some action (read the package.config script) that prevents that script from regenerating a configuration file on the real path. Ideally the script would respect the diversion, but none of them do at present. Some typical methods that disable particular .config scripts are:

  1. Presence or absence of a comment or directive in the configuration file itself (eg. ##DEBCONF##)
  2. A debconf variable (eg. package/override)
  3. Test whether configuration file is really a symlink now

Diverting the /var/lib/dpkg/info/package.config script in advance of package installation doesn't work.

ucf

Debian/etch has 113 packages (about 1% of the source archive) using ucf for configuration file handling, up from just autofs in sarge and dapper. ucf attempts to provide conffile behavior for scripts that are autogenerated. It is not yet in wide use. A real file exists somewhere else on the system, and on first install this is copied to the /etc pathname. On upgrades, the checksum of the /etc configuration file is compared with the checksum of the original, and is upgraded if no end-user changes were made. Otherwise the /etc configuration file is left unchanged.

The ucf system should be turned off for files that are provided by a -config package, and turned back on if the -config package is removed. The -config package would need to have encoded inside it the same ucf command that took over management in the first place.

debian/preinst

        ucf --purge /etc/auto.master

debian/postrm

        ucf /usr/share/autofs/conffiles/auto.master /etc/auto.master

This doesn't work, as autofs re-ucf's its config files and then asks whether to overwrite. If you answer yes, ucf will follow your symlink back to the /etc/site config file and overwrite it.

Solution: divert the usr/share/autofs/conffiles/auto.master file as well, either leaving it empty or making it a symlink to /etc/site as well. Doing both seems to be sufficient to preserve the local changes.

fully custom

There are also packages with scripts that fully automate the generation and long term maintenance of their configuration files. Each one of these is a special case, without even debconf's generalized input model.

bind mount

Some configuration files may need to be taken over at specific stages of bootup, but left unmodified until then. If there is no good mechanism otherwise to disable a package from rewriting a configuration file, or if it has to be returned to unmodified state before the next boot, a read-only bind mount in a bootup script may be the only way.

file

package

method

disabled by

/etc/nsswitch.conf

base-files

conffile

dpkg-divert and bind-mount

/etc/ldap/ldap.conf

libldap2

conffile

dpkg-divert

/etc/libnss-ldap.conf

libnss-ldap

debconf

libnss-ldap/override

/etc/pam_ldap.conf

libpam-ldap

debconf

libpam-ldap/override

/etc/krb5.conf

krb5-config

debconf

symlink

/etc/pam.d/common-auth

libpam-runtime

conffile

dpkg-divert

/etc/pam.d/common-account

libpam-runtime

conffile

dpkg-divert

/etc/ssh/sshd_config

ssh-krb5

debconf

ssh/new_config

openssh-server

debconf

/etc/security/access.conf

libpam-modules

conffile

dpkg-divert

/etc/sudoers

sudo

custom script

existence of file

/etc/krb5.keytab

/etc/resolv.conf

resolvconf

dpkg-divert

/etc/resolvconf/resolv.conf.d/{tail|head}

/etc/resolv.conf

resolvconf

hierarchical

echo searchline > /etc/resolvconf/run/interface/zzzinterface

/etc/postfix/main.cf

postfix

debconf

postfix/main_mailer_type

/etc/cron-apt/action.d/5-install

cron-apt

hierarchical

~3-download without -d flag. Other options as necessary.

/etc/syslog-ng/syslog-ng.conf

/etc/inittab

debootstrap

debian-installer

/etc/lsb-release

base-files

conffile

dpkg-divert

/etc/hosts

netcfg

debian-installer/DHCP

unmanaged after install

/etc/apt/apt.conf

apt-setup base-installer

debian-installer

preseed file

/etc/motd

base-files

custom script

/etc/profile.d/_fixprofile.sh /etc/profile.d/_fixprofile.csh

Alternatives to config packages

Any alternative configuration file handling method still has to inform the native Debian/Ubuntu configuration handling systems that the native system (dpkg) should leave the new files alone and ignore changes to them. Most documentation on the web does not mention this. The problems arise later when there are updates to the packaged systems.

References

Using patch files

Description of the Problem

Some changes to the configuration files are small and simple. So simple that can be represented by a patch. When the change isn't needed anymore the configuration file should return to the original state. It should respect the modifications made by the local administrator.

Solution

A patch management system to patch the configuration files. This is similar to the patch system used to manage source packages in Debian, like dpatch or quilt. The system should keep record of the patches installed or not installed, permit a easy way to install or remove the configuration and upgrading the configured packages without conflicts in the configuration files.

Implementation

At the core of the implementation is the command dpatch. It's called by a wraparound script, so it can apply the patches to the root of the Linux system and the patches files are inside the configuration directory of the package. This wraparound script is called spatch, is placed in /usr/share/$packname and is customized to the configuration package. This script spatch is only called by the local administrator if the patch system is broken in anyway. The script gen-spatch inside the non-oficial package cal-scripts can generate spatch commands.

To configure the others packages the command update-package do one of the three things:

It have the option --silent to allow the command to run unattended.

When update-package changes the configurations files it notifies the daemons to use the new configuration.

Example

The command gen-spatch is:

#!/bin/bash
cat > spatch <<EOF
#!/bin/bash
PACKNAME=$1
APPLYDIR=$2
PATCHESDIR=$3
pushd \${PATCHESDIR} > /dev/null
OPT="--workdir \${APPLYDIR}"
while [ \$# -gt 0 ]; do
        case \$1 in
                help)
                        dpatch \$*
                        exit 1
                        ;;
                -*)
                        OPT="\${OPT} \$1"
                        ;;
                *)
                        break
                        ;;
        esac
        shift || true
done
case \$1 in
    list*)
        dpatch \${OPT} \$*
        ;;
    patch-template)
        dpatch \${OPT} \$*
        ;;
    version)
        dpatch \${OPT} \$*
        ;;
    *)
        CMD=\$1
        shift
        dpatch \${OPT} \$CMD --stampdir=\${PATCHESDIR}/debian/patched \$*
esac
popd > /dev/null
EOF

As an example the update-package will have commands like:

CONFIG=/etc/${PACKNAME}/${PACKNAME}.conf
source ${CONFIG}
function update-clean-patches () {
    deapply-patches $*
    if [ $CLEAN = no ] ; then
        ${SPATCH} apply $1
    fi
}
# Doing updates
update-clean-patches 10_bootlogd_v00
if [ -r /boot/grub/menu.lst ] ; then
    update-clean-patches 10_grub_menu.lst_v00 10_grub_menu.lst
fi
# openssh-server on etch don't need patch
deapply-patches 10_sshd_config_v00 10_sshd_config
if egrep "[[:space:]]*X11Forwarding[[:space:]]+yes" /etc/ssh/sshd_config > /dev/null ; then
    echo "openssh-server on etch don't need patch"
else
    update-clean-patches 10_sshd_config_v00 10_sshd_config
    if [ ${RESTART} = "yes" ] ; then
        invoke-rc.d ssh reload
    fi
fi
#Patching /etc/modules
ModulesAllPatches="20_modules_firewalls_v00 20_modules_routers_v00 \
20_modules_tagus_policy_v01 20_modules_tagus_policy_v00 \
10_modules_prerequisites_v00"
deapply-patches $ModulesAllPatches
update-clean-patches 10_modules_prerequisites_v00
update-clean-patches 20_modules_tagus_policy_v01 20_modules_tagus_policy_v00
case $TpSrvConfNetOptionsRouter in
    Yes|yes|YES)
        update-clean-patches 20_modules_routers_v00
        ;;
esac
case $TpSrvConfNetOptionsFirewall in
    Yes|yes|YES)
        update-clean-patches 20_modules_firewalls_v00
        ;;
    *)
esac

Problems

Is responsibility of the local administrator to run:

It's possible to automate this tasks by using apt options, by droping a file inside /etc/apt/apt.conf.d with something like the following example:

DPkg::Pre-Invoke  { "/usr/sbin/update-package --revert --silent;" };
//DPkg::Pre-Install-Pkgs { "/usr/bin/update-tp-conf-srv --apt"; };
DPkg::Post-Invoke { "/usr/sbin/update-package --silent;" };

References

deb http://debian.tagus.ist.utl.pt/debian etch/updates main contrib

deb http://debian.tagus.ist.utl.pt/debian etch/proposed-updates main contrib

dpsyco approach

The dpsyco package implements a system to define and apply a local policy. This policy define users, groups that automatically exists or are removed from the systems. Permits to auto-configure the users that can have access to mysql database or samba. Have a system to automatically apply this changes or using patches to changes configuration files. The packages allready in Debian etch: dpsyco, dpsyco-*

On the reverside it lacks documentation on its design or capabilities. Help is needed to understand how it works.

References

http://www.opal.dhs.org/programs/dpsyco/