Once you have prepared the chroot directory structure, you can start moving each service s files into the new location. In this case, you could copy the program s root directory, but this is not likely to be simple and may include extraneous files, which goes against one of the reasons for creating a restricted environment. The easiest method is probably to rebuild the program from a source tarball.
An administrator may want to use RPM packages for services to be deployed because there are certain advantages to using packages instead of compiling from source. RPMs are provided by the Linux distribution, which implies that they have been patched and tested for the specific OS. They are easy to install, upgrade, and remove, which saves time when maintaining large numbers of hosts . Also, RPMs have specific configurations and build settings. This final point straddles the line between benefits and drawbacks. On the one hand, the administrator can be sure that new services installed by an RPM will be identical (including any policy for post-installation steps). On the other hand, many RPMs are designed to be as useful as possible out of the box and may contain configurations or components that administrators would rather remove. Source RPMs provide the best combination of configurability and maintainability. Binary RPMs can be used in chroot environments, but they often pose significant hurdles to creating a working service.
Most Linux source code employs the autoconf utility for configuring the program s settings. The typical install procedure for these types of programs is
./configure make, make install ./configure make make install
This installs the program into a default location, which is most often /usr/local. To compile a program for a chroot environment, all you need to do is change the --prefix option to configure . For example, this is how to install Apache 2.0 to /opt/chroot/apache2 instead of the default /usr/local/apache2:
# cd /usr/local/src/httpd-2.0.49 # ./configure --prefix /opt/chroot/apache2 # make # ldd ./httpd not a dynamic executable
Installing the service from source provides the most benefits for creating a customized binary with a specific configuration. Common configuration steps include removing unnecessary functionality and building statically linked versions of the binary. For example, if a binary has IPv6 support that you don t need, remove that support when you build the program. It isn t necessary to the core function of the program even though there might not be any known security risk to including it. By building a static version of the program, you reduce the number of dynamic libraries that must be copied into the chroot directory structure. This reduces the amount of administration overhead and stays in line with the chroot philosophy of creating a minimal environment.
Most software provides a detailed list of configuration options if you type
./configure --help
This will help you determine if you can build static or shared versions, disable unnecessary options, and other build steps.
If establishing an install order and fighting not-uncommon-enough circular dependencies is too difficult, then considering rolling your own RPM. This combines the ease of package management with the customization afforded by building from source code. Additionally, you can create an RPM that can be installed into a chroot directory, but is recorded in the host system s RPM database. To do this properly requires careful editing of the source RPM s spec file. This can turn into a daunting task; but the reward for creating an RPM ready for deployment into a chroot environment surpasses the pain.
First, take a look at the spec file snippet in Figure 9-3. This file has already been modified to build a binary RPM that installs every related file into a chroot environment. In the case of OpenSSH, this not only includes the sshd daemon, but configuration information typically stored in the /etc/directory such as host keys and startup scripts.
The RPM s attributes can be verified with the -qip options:
# rpm -qip openssh-chroot-3.6.1p2-8mdk.i586.rpm Name : openssh-chroot Relocations: /opt/chroot Version : 3.6.1p2 Vendor: (none) Release : 8mdk Build Date: Fri 23 Apr 2004 1:11:57 AM EDT Install Date: (not installed) Build Host: Melnibone Group : Networking/Remote access Source RPM: openssh-chroot- 3.6.1p2-8mdk.src.rpm Size : 356180 License: BSD Signature : (none) URL : http://www.openssh.com/ Summary : OpenSSH free Secure Shell (SSH) implementation Description : Modified the original spec file with a customized build that deploys to /opt/chroot.
To get to this point we needed to modify three components of the spec file: tags, macros, and instructions. Tags provide summary information about the package. The most important tag for chroot -related packages is the Prefix value. Macros define file paths, compile options, and package options. The instructions control the flow of building the source RPM and creating the final binary package.
The specific steps to modify a source RPM vary among packages, but mostly relate to where the final files are installed and what supporting files must be included. The most important aspect of the RPM is that the Relocations tag must report a directory. It doesn t matter if the directory is /opt/chroot and we want to install to /var/chroot. All that matters is that the RPM is relocatable. Once that is set, it is trivial to install to an alternate location.
Table 9-1 lists the most relevant tags of the spec file. Tag values are assigned on the same line as the tag. The value can be a string or a macro. This example uses a string for Summary and a macro for Name.
spec Tag | Notes |
---|---|
Name | The name of the RPM. Append a value such as -chroot to create a unique name. |
Version | Version information. |
Release | Release information. |
Prefix | This is rarely present in a source RPM, but it is the most important tag when building a package for a chroot environment. This tag enables a package to be relocatable with the command rpm --relocate /old/path=/new/path |
Source[n] | Source file archive(s). |
Patch[n] | Patch file(s). Patch files are important because they either apply architecture-specific fixes for the package or apply security fixes. |
Summary: OpenSSH free Secure Shell (SSH) implementation Name: %{name}
If a spec tag s value is set by a macro, the macro can either be defined by the environment or within the file. Macros are set in the spec file with the %define instruction. For example, the previous Name tag s value is defined this way:
%define name openssh-chroot Name: %{name}
Table 9-2 lists most of the important macros used to build and modify a binary RPM. This list is not complete, but you should know at least these macros if you want to modify an existing source RPM. Table 9-3 lists spec file instructions.
spec Macro | Notes |
---|---|
%{_prefix} | Default: /usr |
%{_exec_prefix} | Default: %{_prefix} |
%{_lib} | Default: lib |
%{_libdir} | Default: %{_exec_prefix}/%{_lib} |
%{_libexecdir} | Default: %{_exec_prefix}/libexec |
%_unpackaged_files_terminate_build | Default: 1 |
spec Instruction | Notes |
---|---|
%define | Define a macro and its value. Reference the value with this format: %{macro_name} |
%prep | The steps to prepare the source for configuration. |
%build | The command line to configure and compile the source code. |
%description | Default: < text > |
%doc | Remove. |
%files | This is important! These files are placed in the package. Include each file required by the program. You can add other files, such as /etc/passwd or /etc/group to ensure that every dependency is met. |
%changelog | Describe the modifications made. |
The complete list of macros can be found in the /usr/lib/rpm/macros file. Use the ~/.rpmmacros file to set macro values specific to your user account. These will be used during the rpmbuild process and applied to any packages you create from a spec file.
Here is an example of how to modify a spec file so that it can be installed with the relocatable option. OpenSSH is a good example because it relies on system files (/etc/passwd, /etc/shadow) that must also be considered when changing %build , %install , and %files steps. The %{chroot} macro was prepended to several options to the configure command.
%build %serverbuild CFLAGS="$RPM_OPT_FLAGS" ./configure \ --prefix= %{chroot} %{_prefix} \ --sysconfdir= %{chroot} %{_sysconfdir}/ssh \ --mandir= %{chroot} %{_mandir} \ --libdir= %{chroot} %{_libdir} \ --libexecdir= %{chroot} %{_libdir}/ssh \ --datadir= %{chroot} %{_datadir}/ssh \ --disable-largefile \ --with-pam \ --with-default-path=/bin:/usr/bin \ --with-privsep-path=/var/empty \ --with-superuser-path=/sbin:/bin:/usr/sbin:/usr/bin \ --with-md5-passwords \ --without-4in6 \ --without-sectok \ --without-skey \ --without-tcp-wrappers make
It is very important to notice that the installation files are all prefixed with the %{chroot} macro. If this were not the case, files would be installed to directories without a common root (other than /). There are three configuration directives that do not have the %{chroot} prefix:
--with-default-path --with-privsep --with-superuser-path
Each of these configuration options are specific to OpenSSH and affect how the installed binary operates. Consequently, each of these paths is relative to the chroot base path. For example, --with-default-path defines the default file path given to users when they authenticate. When the sshd daemon is running inside the chroot environment, /opt/chroot/bin and /opt/chroot/usr/bin appear to the daemon as /bin and /usr/bin. It would be incorrect to give the daemon /opt/chroot/bin as a default path because that would really imply /opt/chroot/opt/chroot/bin to the daemon.
A customized spec file that creates a relocatable RPM means that you can install and manage the RPM normally, without supplying additional command line options or creating a secondary RPM database in the chroot directory. Use the --relocate option to install a chroot -capable RPM into an alternate directory:
# rpm --relocate /old/path=/new/path ...
The /old/path value cannot be the root (/) and will be the new prefix for all files installed by the package. This is why it is necessary to massage the spec file to support relocation.
The rpm command provides a command line switch to set an alternate root directory into which the package will be installed. By default, the root directory is /, as one expects. If you want to install into the chroot environment, /opt/chroot, you ll have to prep the environment before installing any packages. Otherwise, you ll receive an error similar to the following:
# rpm --install --root /opt/chroot openssh-3.6.1p2-8mdk.i586.rpm error: cannot open lock file /opt/chroot/var/lib/rpm/RPMLOCK in shared mode error: cannot open Packages database in /opt/chroot/var/lib/rpm
It is easy to establish the new RPM root and database structure in the chroot environment:
# mkdir -p /opt/chroot/var/lib/rpm # rpm --initdb --root /opt/chroot # ls -l /opt/chroot/var/lib/rpm/ total 8 -rw-r--r-- 1 root root 12288 Apr 22 14:23 Packages -rw-r--r-- 1 root root 0 Apr 22 14:23 RPMLOCK
You re not out of the woods yet, because library dependencies will need to be met for each of the packages to be installed. Luckily, RPM errors are friendly enough to tell you what s missing:
# rpm --install --root /opt/chroot openssh-3.6.1p2-8mdk.i586.rpm warning: /mnt/iso/Mandrake/RPMS/openssh-3.6.1p2-8mdk.i586.rpm: V3 DSA signature: NOKEY, key ID 70771ff3 error: Failed dependencies: openssl >= 0.9.7 is needed by openssh-3.6.1p2-8mdk libc.so.6 is needed by openssh-3.6.1p2-8mdk libc.so.6(GLIBC_2.0) is needed by openssh-3.6.1p2-8mdk libc.so.6(GLIBC_2.1) is needed by openssh-3.6.1p2-8mdk libc.so.6(GLIBC_2.2) is needed by openssh-3.6.1p2-8mdk libc.so.6(GLIBC_2.3) is needed by openssh-3.6.1p2-8mdk libcrypto.so.0.9.7 is needed by openssh-3.6.1p2-8mdk libnsl.so.1 is needed by openssh-3.6.1p2-8mdk libutil.so.1 is needed by openssh-3.6.1p2-8mdk libz.so.1 is needed by openssh-3.6.1p2-8mdk
It is possible to set up a skeleton chroot directory structure and step through the RPMs in their required order. However, such a kludge leads to an inelegant procedure for most binary packages and often leads to the undesirable necessity of using the --nodeps option during install. The --nodeps option ignores dependencies and, even if the RPM installs successfully, a critical error may be silently suppressed by this method.
The rpm command has an option called --relocate that will change the directory location for a base path common to all files in the package. Refer to the previous section for more information on this option.
There is a legitimate argument that a complex procedure only needs to be performed once and can then be automated by some creative scripting. The real disadvantage of using binary RPMs is that each RPM adds more and more items that the administrator probably doesn t want in the chroot environment. Consequently, it might be a better idea to build a custom package or just use a source tarball.