Cryptographic operations on Linux depend on the kernel's random pool, and a depleted pool causes everything from slow TLS handshakes to multi-second SSH key generation to outright application hangs. Modern kernels (5.4+) largely solved the historic "blocking on /dev/random" problem, but virtual machines, freshly-booted containers, and embedded systems still suffer entropy starvation. This guide explains the kernel pool, the available entropy sources, and the daemons that keep the pool full on hosts that need them.
What "entropy" actually means here
The kernel maintains a CSPRNG (cryptographically secure pseudo-random number generator) seeded from physical entropy sources: interrupt timing, disk timing, CPU instructions like RDRAND, hardware RNGs (TPM, virtio-rng), and human input on desktops. Once seeded, modern /dev/urandom never blocks. The legacy /dev/random and getrandom(GRND_RANDOM) can still block on early-boot machines that have not gathered enough entropy yet.
cat /proc/sys/kernel/random/entropy_avail # bits available, target 256+
cat /proc/sys/kernel/random/poolsize # max pool size (typically 256 on 5.18+)
cat /sys/devices/virtual/misc/hw_random/rng_current # active hardware RNG
cat /sys/devices/virtual/misc/hw_random/rng_available
On kernel 5.18+ the pool reports a fixed target (256 bits) once initially seeded; the legacy "growing pool" model is gone. The number to watch is whether the pool is initially seeded at boot, not the steady-state value.
Detecting unseeded boot
dmesg | grep -i 'random'
journalctl -k -b 0 | grep -E 'crng init|random:.*ready'
You want a line like random: crng init done appearing within a few seconds of boot. If it appears 30+ seconds in or never appears, your application's first cryptographic call after boot may stall.
Hardware RNG and rng-tools
If your CPU supports RDRAND/RDSEED and the kernel exposes a hardware RNG, harvest it with rngd:
sudo apt install rng-tools-debian # Debian/Ubuntu (use 'rng-tools' on RHEL family)
sudo systemctl enable --now rngd
systemctl status rngd
ls /dev/hwrng # device exists?
sudo rngd -f -r /dev/hwrng -v & # run in foreground for testing
rngd reads from the hardware source, runs FIPS 140-2 statistical tests on the output, and feeds it into the kernel pool. On a server with a TPM or virtio-rng, this guarantees fast initial seeding.
haveged: the software-only fallback
On older systems without a hardware RNG and with low interrupt activity (think early-boot containers), haveged uses CPU timing jitter to generate entropy:
sudo apt install haveged
sudo systemctl enable --now haveged
systemctl status haveged
cat /proc/sys/kernel/random/entropy_avail
Note that on very modern kernels, haveged may be unnecessary β the kernel's own jitter sources are sufficient. Test on your specific workload and remove if the pool is healthy without it.
Virtio-rng for VMs
Cloud providers expose a paravirtualised RNG via the host's true random source. For KVM/QEMU:
lsmod | grep virtio_rng
ls /dev/hwrng
sudo dmesg | grep -i virtio_rng
If you are running on KVM and do not see the device, ensure the VM's XML or libvirt domain definition includes a <rng model='virtio'> element. Almost every cloud provider enables this by default; bare-metal hypervisors and home labs often do not.
Container-specific issues
Containers share the host's kernel pool β entropy is not duplicated per namespace. Consequences:
- If the host is healthy, the container is healthy.
- If the container starts immediately after host boot before the pool is seeded, the first crypto call inside the container can stall.
/dev/randomand/dev/urandomare device nodes mapped from the host; they behave identically to the host view.
For minimal images that run cryptographic operations at start (TLS server boot, SSH host key generation), consider initialising on the host then snapshotting the image with the keys baked in, or use --device=/dev/urandom to ensure the device is mapped.
Application-side best practice
Almost every modern crypto library should call getrandom(2) with the default flags (GRND_INSECURE=0, no GRND_RANDOM). This blocks only until the pool is initially seeded β usually milliseconds β and never blocks again. If your application explicitly opens /dev/random, audit the code: /dev/urandom is the correct choice for nearly every use case.
Monitoring the pool
#!/bin/bash
ent=$(cat /proc/sys/kernel/random/entropy_avail)
seeded=$(journalctl -k -b 0 | grep -c 'crng init done')
boot_age=$(awk '{print int($1)}' /proc/uptime)
echo "entropy_avail=$ent seeded=$seeded boot_age_sec=$boot_age"
if [ "$seeded" -eq 0 ] && [ "$boot_age" -gt 60 ]; then
echo "WARN: kernel CRNG not seeded after 60 seconds"
fi
Push this into your time-series monitoring; alert when an instance comes up and CRNG is not seeded within 60 seconds.
FIPS-mode and audit considerations
Hosts running in FIPS mode have additional constraints: only specific RNG sources are permitted, and rngd must run in FIPS mode (--fips-only on newer versions). Consult your distribution's FIPS guidance β this is one of the few areas where defaults can fail compliance even when the application works.
Common pitfalls
- Reading from
/dev/randomin application code; on busy servers this is almost always a mistake. Switch to/dev/urandomorgetrandom(). - Disabling
havegedafter a TLS slowness incident "because it was not the cause" β leaving it disabled invites the next incident. - Running rngd without verifying FIPS-failure handling; bad RNG output is silently fed into the pool.
- Trusting
entropy_availvalues on kernel 5.18+ as a "fullness" gauge β they are deliberately fixed once seeded.
Entropy is one of those topics that is invisible until it bites β and then the bite is "nginx took 90 seconds to start." Confirm CRNG seeds quickly at boot, run rngd or virtio-rng on every server, monitor the seeding event, and verify your applications use getrandom(). Five minutes of attention prevents a class of incidents that is unfailingly painful when it happens.