Documentation on the installation, setup, and usage of Yellowdog Updater, Modified (YUM) to install RedHat Package Manager (RPM) packages on RedHat Enterprise Linux. More information on building RPM packages is available.
These notes focus on yum for RedHat Enterprise Linux. Fedora ships with yum already installed. The notes are based on yum version 2.0.7, with notes for more recent versions where possible. Use the most recent stable version of yum, if possible.
Consider also Current, an open source Red Hat Network (RHN) server. I have not setup Current; consult a brief discussion and implementation plan for RedHat Enterprise Linux updates and system administration for thoughts on up2date versus yum. See also RPMforge.
Installation
RedHat Enterprise Linux systems (as of versions 3 and 4) must install the YUM package. If installing via KickStart, install YUM as part of the %post install script. The following example shows installation from a private Network File System (NFS) mount on a secure build network.
%post
export RH_MOUNT=/tmp/bootstrap
mkdir -p $RH_MOUNT
/etc/init.d/portmap start
mount -t nfs 192.0.2.1:/install $RH_MOUNT
export RH_RELEASE=rhel
export RH_VERSION=`rpm -q --queryformat '%{VERSION}' redhat-release`
# install package, default configuration
rpm -i $RH_MOUNT/yum/$RH_RELEASE.rpm
cp $RH_MOUNT/yum/$RH_RELEASE.conf /etc/yum.conf
chmod +r /etc/yum.conf
# attempt package updates
yum -d 0 -e 0 -t -y update
Client Configuration
By default, YUM reads /etc/yum.conf. Always use the gpgcheck=1 option to prevent the installation of unsigned packages. Additional package sources can be defined by adding more [name] blocks, for example local YUM servers in addition to the vendor supplied ones. If possible, use $releasever and other variables to keep the configuration files portable between releases. The following definitions consult an example yum.example.org web server for packages:
# base packages for RHEL
[rhelbase]
name=RedHat Linux $releasever Install
baseurl=http://yum.example.org/redhat/$releasever/$basearch/
gpgcheck=1
# up2date ported updates
[rhelupdates]
name=RedHat Linux $releasever Updates
baseurl=http://yum.example.org/redhat/updates/$releasever/$basearch/
gpgcheck=1
# all system types check here (noarch, other highly portable packages)
[siteall]
name=Sitewide Packages
baseurl=http://yum.example.org/all/
gpgcheck=1
# local Fedora, RHEL packages
[siterpms]
name=Site $releasever Packages
baseurl=http://yum.example.org/site/$releasever/
gpgcheck=1
# packages if YUM0 environment variable set properly before yum run
[sitegroup]
name=Site Group
baseurl=http://yum.example.org/group/$YUM0/$releasever/
gpgcheck=1
Client systems should also periodically run yum clean to clear out old headers and packages. Use a cron job, or a CFEngine shellcommands statement:
shellcommands:
redhat::
"/usr/bin/yum -y -d 0 -e 0 clean all" umask=022 ifelapsed=1439
Importing Signatures
With the gpgcheck=1 option set in yum.conf, all packages must be signed, and yum must be able to verify the signatures on packages. On current versions of Redhat, public keys must be registered via the rpm --import command. Installation of the vendor supplied keys can be done during a KickStart install under the %post section:
%post
rpm --import /usr/share/rhn/RPM-GPG-KEY
rpm --import /usr/share/rhn/BETA-RPM-GPG-KEY
Check the /usr/share/rhn directory for other public keys to install. Older RedHat systems had to register the keys via gpg --import. Bear in mind an imported signature allows anyone with access to the private key of the signature to run arbitrary commands as the super user.
Public keys should be managed via some sort of configuration management, so that local public keys can be expired periodically or when package signers leave the site. I strongly recommend having a different public key for each package signer. One problem with maintaining keys is that rpm --import will allow the same public key to be installed multiple times. A workaround is to erase all public keys before installing the required public keys.
#!/bin/sh
/bin/rpm -q gpg-pubkey --qf '%{name}-%{version}-%{release}\n' | \
sort | uniq | while read pkgname; do
/bin/rpm --erase --allmatches -- "$pkgname"
done
for file in /var/cfengine/local/rpm-pgp-keys/*; do
/bin/rpm --import -- "$file"
done
Using the CFEngine configuration management software, the /var/cfengine/local/rpm-pgp-keys directory can be maintained under version control, and public keys updated when the directory changes, calling the above erase and import code as /usr/sbin/update-rpm-keys:
copy:
redhat::
# PGP keys for RPM verification
${masterfiles}/etc/rpm-pgp-keys
dest=/var/cfengine/local/rpm-pgp-keys
mode=444 recurse=1 backup=false type=checksum purge=true
server=${policyhost}
define=rpm_pgp_keys_copied
shellcommands:
rpm_pgp_keys_copied::
"/usr/sbin/update-rpm-keys /var/cfengine/local/rpm-pgp-keys"
Server Configuration
Systems used to build and sign packages must not host packages. Instead, sign packages on separate build systems, then copy the packages to the YUM server. This way, an attacker that compromises a YUM server will not be able to install and run arbitrary software on clients.
YUM servers need only run a web server to provide packages to client systems, and maintain metadata files.
Web Server
An example Apache virtualhost configuration for yum.example.org is available. Save it under /etc/httpd/conf.d on a RedHat system and restart Apache. The web server configuration must agree with the baseurl values set in the yum.conf configuration files on the client systems. The following list of directories to create are compatible with the yum.conf information outlined above, with the addition of a SRPMS directory to store *.src.rpm files under. Change FIXME_YUM_DIR to /var/www/yum or where ever the area is located on the YUM server.
If possible, use a distinctive name for the package directories, such as RPMS. This allows wrapper scripts to easily locate all package directories metadata must be maintained on.
# where to stash *.src.rpm files
FIXME_YUM_DIR/SRPMS
# RedHat RPMS for RHEL 3 and 4 AS, both base and updates, i386 and x86_64
FIXME_YUM_DIR/redhat/3AS/i386/RPMS
FIXME_YUM_DIR/redhat/3AS/i386/headers
FIXME_YUM_DIR/redhat/3AS/x86_64/RPMS
FIXME_YUM_DIR/redhat/3AS/x86_64/headers
FIXME_YUM_DIR/redhat/4AS/i386/RPMS
FIXME_YUM_DIR/redhat/4AS/i386/headers
FIXME_YUM_DIR/redhat/4AS/x86_64/RPMS
FIXME_YUM_DIR/redhat/4AS/x86_64/headers
FIXME_YUM_DIR/redhat/updates/3AS/i386/RPMS
FIXME_YUM_DIR/redhat/updates/3AS/i386/headers
FIXME_YUM_DIR/redhat/updates/3AS/x86_64/RPMS
FIXME_YUM_DIR/redhat/updates/3AS/x86_64/headers
FIXME_YUM_DIR/redhat/updates/4AS/i386/RPMS
FIXME_YUM_DIR/redhat/updates/4AS/i386/headers
FIXME_YUM_DIR/redhat/updates/4AS/x86_64/RPMS
FIXME_YUM_DIR/redhat/updates/4AS/x86_64/headers
# for noarch.rpm, other highly portable packages
FIXME_YUM_DIR/all/RPMS
FIXME_YUM_DIR/all/headers
# site packages, i386 and x86_64 mixed
FIXME_YUM_DIR/site/3AS/RPMS
FIXME_YUM_DIR/site/3AS/headers
FIXME_YUM_DIR/site/4AS/RPMS
FIXME_YUM_DIR/site/4AS/headers
# for packages by $YUM0 name. Create '$YUM0' directory to keep YUM happy?
FIXME_YUM_DIR/group/$YUM0/3AS/RPMS
FIXME_YUM_DIR/group/$YUM0/3AS/headers
FIXME_YUM_DIR/group/$YUM0/4AS/RPMS
FIXME_YUM_DIR/group/$YUM0/4AS/headers
The YUM server will consume a large amount of space; ensure that at least 40G is available under the packages directory.
Metadata
Under old versions of yum, the yum-arch command generates header files under the headers directory. The following command will find all RPMS directories and run yum-arch in the parent directory of each.
$ find FIXME_YUM_DIR -type d -name RPMS | sed 's/RPMS$//' | \
while read dir; do yum-arch -q $dir; done
Current versions of yum require the createrepo command, found on Fedora in the createrepo package.
# yum -y install createrepo
# createrepo /var/www/yum/fedora/4/RPMS
Always run yum-arch or createrepo after adding new packages. When transfering packages from a build system, include a post-transfer command to rebuild the metadata. Also consider a periodic job to keep the metadata built, in the event the post-transfer command fails, such as yum-update-repos. For example, under CFEngine:
shellcommands:
role_yum_server::
"${yum_script_dir}/yum-update-repos" umask=022 ifelapsed=299
up2date to yum
Redhat will only offer technical support to systems updated through up2date. However, updating via a local yum repository is permitted by RedHat, saves bandwidth, avoids the need to register each system, and provides local control of the update process. If in doubt, have a lawyer review the RedHat Subscription Agreement, or ask RedHat directly.
up2date2yum can download updates for RedHat Enterprise Linux via up2date and make them available to YUM. The system running up2date2yum must have entitlements from RedHat, or otherwise be able to access updates from RedHat. An entitlement server is required for each supported hardware architecture.
To test new packages, place updates into a test/RPMS directory, then move the packages to the updates/RPMS directory once checks on test systems pass. Another option would be to control yum update runs on systems, so that test systems install new packages first. I recommend moving packages to different directories, as this supports creation of different release branches that different systems may subscribe to (stable, security, unstable, and so forth).
Vendor packages could be audited and resigned, though for most sites the audit effort will not be worth the time or money. Resigning may be necessary where junior administrators can update packages for test systems, but only a senior admin sign off on production system changes. Resigning vendor packages may not be possible in some cases.
Tips
Set exclude=… statements inside the yum configuration to ignore certain packages during a yum update.