openSUSE:Packaging UsrEtc
This document describes how openSUSE wants to handle the configuration file split between /etc and /usr/etc.
Rationale
The handling of RPM for configuration file updates is not good. It may have been acceptable for standard distributions, but even there, it led to many bug reports. Users had to manually merge their changes, but seldomly did that, and then wondered why their service did not work anymore. Anyhow, for transactional-updates, this does not work anymore at all. The goal is to separate the distribution-provided configuration files from changes the admin makes.
What do we want to do?
In the longterm, /etc will only contain configuration files that are host-specific or have been modified by the admin. All distribution-provided configuration files are located below /usr/etc and are not modifiable by the admin (with a read-only root filesystem, this would not even be possible). Instead, the applications need to be enhanced, as far as possible and necessary, to read the configuration files from several locations. Additionally, the distribution provided configuration files should be moved from /usr/lib and consolidated in /usr/etc as far as possible.
Upstream compatibility
What we call "UsrEtc" is meanwhile called "hermetic-usr" upstream. More can be found here:
- Fitting Everything Together
- Configuration Files Specification
- Tracking upstream projects that do not support hermetic-usr for configuration
What does this mean for the system administrator?
Update
Check for *.rpmnew and *.rpmsave files! This is even more important now that distribution-made changes and administrator-made changes get merged in a timely manner. Make sure that the libnss_usrfiles2 package is installed and /etc/nsswitch.conf contains:
services: files usrfiles protocols: files usrfiles rpc: files usrfiles ethers: files usrfiles
Variant 1 (ideal case)
In the ideal case, an application reads the configuration files from four places:
- /usr/etc/example.conf
- /usr/etc/example.conf.d/*.conf
- /etc/example.conf
- /etc/example.conf.d/*.conf
/usr/etc/example.conf or /usr/etc/example.conf.d always exist and will be provided by the distributor. These files must never be touched by an administrator. If /etc/example.conf exists, /usr/etc/example.conf and /usr/etc/example.conf.d will be ignored, and only /etc/example.conf will be used. Which means this file needs to be a full copy. Additionally, all files from /etc/example.conf.d/*.conf will be read in lexicographic order and applied to the entries of the full configuration file; such that overlapping changes from the most recently read files win.
If a system administrator wants to change a configuration variable, he has to drop a file with that change into /etc/example.conf.d/, e.g. /etc/example.conf.d/override.conf.
Variant 2
If there is no support for /etc/example.conf.d/*.conf, /usr/etc/example.conf will always be used, and /etc/example.conf contains only the overrides. An example for this is transactional_update (see section of this name below).
Variant 3
If the configuration file is something complex which does not allow overrides of single entries, /etc/example.conf must be a full copy of /usr/etc/example.conf and will be the only file read.
What does this mean for the developer/packager?
The developer/packager has to modify the package to fit into one of the three above variants. Files in /usr/etc must not be marked as configuration file (the %config RPM keyword must not be used).
RPM Macros
There will be a new RPM macro for this directory:
%_distconfdir /usr/etc
This allows distributions to change the directory for their needs, if necessary.
Moving of configuration files
If configuration files which are marked as %config(noreplace) were modified by the administrator and are then moved from /etc to /usr/etc by rpm, rpm will save the modified configuration files as *.rpmsave files at the end of the update process. These files need to be renamed back to the original file name. To make sure that no old, outdated *.rpmsave configuration files are suddently active again after an update, these files should be moved away at the beginning of the update process. For the pam package, the following two fragemnts in the %pre and %posttrans solved this:
%pre for i in securetty pam.d/other pam.d/common-account pam.d/common-auth pam.d/common-password pam.d/common-session ; do test -f /etc/${i}.rpmsave && mv -v /etc/${i}.rpmsave /etc/${i}.rpmsave.old ||: done %posttrans # Migration to /usr/etc. for i in securetty pam.d/other pam.d/common-account pam.d/common-auth pam.d/common-password pam.d/common-session ; do test -f /etc/${i}.rpmsave && mv -v /etc/${i}.rpmsave /etc/${i} ||: done
Inbetween the package gets updated and until all updates have been applied and the %posttrans section gets executed, the package could be broken and not be usable in pre/post install sections of other RPMs!
Additional helper tools
We are currently developing libeconf, a library which can read nearly all kinds of key/value configuration files and automatically combine all configuration files in the correct order to present them to the application. This could help in many cases to adjust the applications.
Packages
kbd
PAM configuration file for vlock was moved to /usr/lib/pam.d, see the pam package for configuration.
kubic-control
The default configuration file are stored in /usr/etc/kubicd/, the overrides are stored in /etc/kubicd/ (Variant 2).
less
/etc/lesskey and the corresponding /etc/lesskey.bin were moved to /usr/etc. aaa_base prefers the /etc version over the /usr/etc version (variant 3).
netcfg
The files ethers, networks, protocols and services where moved to /usr/etc. /etc/nsswitch.conf was adjusted to first read the files in /etc, and if there is no file or the file does not contain the searched entry, it will read the file in /usr/etc (variant 2).
openssh
/etc/ssh/sshd_config was moved to /usr/etc/ssh/sshd_config. /etc/ssh/sshd_config and /etc/ssh/sshd_config.d/*.conf will additionally be looked at (variant 1). The /etc/ssh/sshd_config.d method should be preferred, but is not useable for all config options. The same applies to /etc/ssh/ssh_config.
permissions
/etc/permissions and /etc/permissions.* except permissions.local are no configuration files nor templates and no admin should modify them. For this reasons they were moved to /usr/share/permissions. The distribution specific snippets in /etc/permissions.d will be moved to /usr/etc/permissions.d.
pam/pam-config
PAM reads the configuration files from three places:
- /usr/etc/pam.d
- /usr/lib/pam.d
- /etc/pam.d
The pam-config utility reads the configuration files from these three places, too, but it only writes to /etc/pam.d.
If a file in /etc/pam.d exists, a file with the same name in /usr/lib/pam.d will be ignored. A system administrator has to make manual changes, copy the PAM config file from /usr/lib/pam.d/ to /etc/pam.d/, and modify that.
Some PAM modules are using variables from login.defs. Variant 1 is used for this, meaning that /usr/etc/login.defs, /etc/login.defs and /etc/login.defs.d/*.defs will be looked at.
The pam_securetty.so plugin is reading the securetty file. It will first determine if /etc/securetty exists, and only if it does not, /usr/etc/securetty is used (variant 3).
Accepted upstream: pull request.
rebootmgr
The distribution-provided configuration file is /usr/etc/rebootmgr.conf. Changes are written to /etc/rebootmgr.conf and are merged during start of rebootmgrd (variant 2).
shadow
/etc/login.defs was moved to /usr/etc/login.defs. /etc/login.defs and /etc/login.defs.d/*.defs will additionally be looked at (variant 1).
PAM configuration files were moved to /usr/etc/pam.d; see the pam section above for configuration.
Accepted upstream pull request.
sudo
PAM configuration files were moved to /usr/etc/pam.d; see the pam section above for configuration.
TODO
- /etc/sudoers needs to be moved to /usr/etc
- /etc/sudoers.d needs a /usr/etc/sudoers.d fallback directory for distribution config snippets
- /etc/openldap/schema needs to be moved to /usr/etc/openldap/schema, needs openldap adjustments.
transactional-update
transactional-update first reads /usr/etc/transactional-update.conf and then merges it with /etc/transactional-update.conf (variant 2).
util-linux
/etc/login.defs are read through libeconf from /etc and /usr/etc (variant 1). If /etc/default/su does not exist, /usr/etc/default/su is read (variant 3).
PAM configuration files were moved to /usr/etc/pam.d; see the pam section above for configuration.
Upstream pull request.
/etc/profile.d/*
Files in
- /usr/etc/profile.d
- /etc/profile.d
are read, prefering the ones in /etc/profile.d.
/etc/slp.d/*
The host admin has to maintain /etc/slp.reg.d. It should not be packaged, but it may become %doc. The host may announce unwanted or wrong data, depending on how the service is configured. (Comment by Olaf Hering on opensuse-factory@opensuse.org)
/etc/xdg/autostart/*
/usr/etc/xdg/autostart can also be used now in addition to the /etc/xdg/autostart directory. See boo#1173316.
/etc/logrotate.d/*
Somebody needs to rewrite logrotate first. boo#1173319
/etc/skel/*
/usr/etc/skel is now read in addition to /etc/skel. Files and directories in /etc/skel are preferred. More details in boo#1173321.
/etc/rpm/* macros
Use /usr/lib/rpm/macros.d instead, i.e. %{_rpmmacrodir}.
Notes
- More background informations can be found in the Atomic Updates and /etc Document. (2019-08-16)
- Kubic blog post by T. Kukuk about /etc, /usr/etc (2019-12-05)