Monthly Archives: May 2014

More entropy with haveged

When a system’s entropy pool is depleted, reads from /dev/random will block. For applications that require lots of entropy, in environments where little entropy is available, long delays can result.

A side-note: on Linux, information about the amount of entropy available can be found under /proc/sys/kernel/random/, along with other parameters of the kernel entropy device and a UUID source. Be aware that other systems may not have this interface.

So if you are running out of entropy, what can you do? The haveged program exists to remedy this problem. It implements a variant of the HAVEGE (HArdware Volatile Entropy Gathering and Expansion) algorithm. In brief, HAVEGE leverages the fact that modern processors have thousands of bits of volatile internal state that affect how long it takes to execute particular routines. The nondeterminism in the time taken to execute a particular routine, also known as flutter, can be determined by reading the hardware clock counter. Using this entropy to seed a PRNG, HAVEGE can provide orders of magnitude more entropy than the standard Linux entropy device.

Let’s install haveged and see it in action:

sudo yum install -y haveged
sudo systemctl start haveged.service

That’s all there is to it. This runs /usr/sbin/haveged -w 1024 -v 1 --Foreground. The -w argument specifies the write wakeup threshold. When /dev/random has fewer than this many bits of entropy available, processes writing to the entropy pool are awakened. haveged wakes up, produces some entropy and feeds it to Linux for other applications to use.

The availability and quality of entropy can be tested using the rngtest tool, available in the rng-tools package. Compare running cat /dev/random | rngtest -c 1000 both with and without haveged working to feed /dev/random. You should find that haveged does a good job of ensuring ample entropy is available for programs.

Another solution to low entropy on Linux is rngd, which works similarly to haveged but reads entropy from hardware RNGs. Of course, you need a hardware RNG for rngd to be effective. The default location for a hardware RNG is /dev/hwrandom; rngd uses this device by default but can be configured to use any device that provides the Linux /dev/random ioctl API. Some Linux distributions (including recent releases of Fedora) ship with rngd enabled by default.

Let it again be noted that the entropy devices provided by other operating systems may (read: do) operate differently from the Linux entropy device, and some have native support for hardware RNGs when present, so while the approach to entropy replenishment shared by haveged and rngd works well for Linux, it may be incorrect or simply unnecessary for other systems.

Docker build context and symbolic links

Docker is an application container system for Linux. Under the hood it’s like FreeBSD jails, but on top of that it provides powerful image specification and indexing capabilities. Images are built up in layers; each image depends on some other image (down to a base image), so a particular image might be a small delta on some shared dependency.

In investigating ways to Dockerize FreeIPA, particularly for ease of sharing development builds, it makes sense to base builds on an image that contains all the build dependencies. Since the dependencies are the same for any build, they can be made available in a single image to shave down the build time and reduce the size of the final images.

So there will be one Dockerfile for the builddeps image. But we will need another Dockerfile for the build itself, which will depend on the builddeps image. Each Dockerfile must reside in its own directory – there is no facility for specifying a different filename, e.g. Dockerfile.builddep – yet each Dockerfile needs to access some files in the root of the repository, e.g. freeipa.spec.in.

My initial approach is to have the builddep Dockerfile live in the repository at docker/freeipa-builddep/Dockerfile. The file consists of instructions specifying the image to build the new image FROM, files to ADD into the image, and commands to RUN. The initial Dockerfile is:

FROM fedora:20
ADD ../../freeipa.spec.in freeipa.spec.in
RUN cp freeipa.spec.in freeipa-builddep.spec
RUN yum-builddep freeipa-builddep.spec

Let’s attempt to build the image:

% sudo docker build .
Uploading context 3.072 kB
Uploading context
Step 0 : FROM fedora:20
 ---> b7de3133ff98
Step 1 : ADD ../../freeipa.spec.in freeipa.spec.in
2014/05/19 16:34:21 ../../freeipa.spec.in: no such file or directory

The context of a build is the contents of the directory containing the Dockerfile. Attempting to reference files outside the context fails. The ADD instruction documentation does kindly mention this.

We certainly don’t want multiple copies of freeipa.spec.in floating around, so perhaps we can use a symbolic link. The Dockerfile now reads:

FROM fedora:20
ADD freeipa.spec.in freeipa.spec.in
RUN cp freeipa.spec.in freeipa-builddep.spec
RUN yum-builddep freeipa-builddep.spec

Creating the symlink and trying the build again:

% cd docker/freeipa-builddep/
% ln -s ../../freeipa.spec.in
% docker build .
Uploading context 3.072 kB
Uploading context
Step 0 : FROM fedora:20
 ---> b7de3133ff98
Step 1 : ADD freeipa.spec.in freeipa.spec.in
2014/05/19 16:45:06 freeipa.spec.in: no such file or directory

Docker really does not like symlinks.

I’m not sure how to proceed from here, and will be seeking feedback from the other FreeIPA developers since the other options are either intrusive (different Dockerfile = different branch) or hacky (e.g. pulling things in from URLs, or multiple copies of spec file in repository). Perhaps I am overlooking a nice solution, or perhaps one will come about soon given that Docker is still under heavy development.

Stay tuned.