I recently found myself wishing to be able to remotely unlock my LUKS partitions on (re)boot. The Arch Linux wiki has some information on this, but this was not sufficient for my case, as my network assigns dynamic IP addresses, which I normally push to my DIY DDNS server using a cURL script. Therefore, it became necessary to be able to use cURL during in the initramfs/early userspace environment.

Deploying cURL

Create /etc/initcpio/hooks/hookname (where hookname is the name of your new hook where curl will be used) with the following contents:

run_hook () {
	# Your code using curl here, e.g.
	curl --insecure https://192.168.0.10/example/blahblah
}

cURL has difficulty with CA certificates in this environment, so we pass --insecure to disable checking of CA certificates for now. Note also that cURL has difficulty resolving domain names, so we use the IP address for now.

Next, create /etc/initcpio/install/hookname with the following contents:

build ()
{
	add_runscript
	add_binary curl
}
help ()
{
	echo Example hook using cURL
}

Finally, edit /etc/mkinitcpio.conf and add hookname to HOOKS in an appropriate place (for example, after netconf dropbear but before encryptssh).

Entropy and random number generation

As things are, this will result in cURL hanging for a considerable period of time on boot, as there is no entropy available for random number generation. Keyboard-mashing and mouse-movement can alleviate this problem, but this is obviously not possible remotely.

We can solve this by adding random.trust_cpu=on to the Linux kernel parameters. For example, using GRUB, edit /etc/default/grub and add random.trust_cpu=on to GRUB_CMDLINE_LINUX (that's on, not true!).

CA certificates

In order to allow cURL to check CA certificates, we need to include /etc/ssl/certs. As files here symlink into /etc/ca-certificates, we need to include that too. In /etc/initcpio/install/hookname, at the end of build add:

	add_full_dir /etc/ssl/certs
	add_full_dir /etc/ca-certificates # /etc/ssl/certs files symlink into here

We can now omit --insecure from the cURL command.

DNS lookups

To allow cURL to resolve domain names, we need to include libnss_{dns,files}.so. In /etc/initcpio/install/hookname, at the end of build add:

	for i in /usr/lib/libnss_dns* /usr/lib/libnss_files*; do
		add_file $i
	done

We also need to manually generate an /etc/resolv.conf file, as this is not done for us. In /etc/initcpio/hooks/hookname, before the cURL call add:

	# Generate resolv.conf
	source /tmp/net-eth0.conf
	echo nameserver $IPV4DNS0 > /etc/resolv.conf
	echo nameserver $IPV4DNS1 >> /etc/resolv.conf

Replace eth0 with the (kernel) name of your network device. We can now use domain names in the cURL command.

Applying our changes

Now run:

sudo mkinitcpio -p linux
sudo grub-mkconfig -o /boot/grub/grub.cfg

We are now complete, and can reboot the system to see our script in action!