It can be used as a USB C “gadget” with an iPad Pro (or similar device);
All files except for /boot are encrypted;
A full desktop environment is available on demand via RDP; and
The system still works as a desktop device in a pinch (BYO keyboard, mouse, and monitor).
Be aware that this guide was written using the 64-bit 2021.2 Kali Linux image; YMMV with other images!
It should be possible to adapt the steps here for other Debian-based operating systems with a Raspberry Pi 4B compatible image. It should also be possible to do this all in fewer steps; the guide below is split up in a very step-by-step fashion, and is in no way optimized for speed.
A second “bootstrap” microSD card that’s at least 32 GB in size. (You need something twice the size that your operating system image requires. This will just be used to “bootstrap” the encrypted microSD card, so it’s only necessary if you’re spinning the Pi up for the first time.)
A USB microSD card reader (since you’ll need to have both microSD cards connected to the Pi briefly.)
Physical access to a Linux system. (This could actually be the Pi itself, if you’ve already got it up and running with another operating system.)
An HDMI monitor, microHDMI-to-HDMI cable, and a USB keyboard (only needed until we set up network access and USB gadget mode).
Create the bootstrap microSD (if necessary)
If you’re setting the Pi up for the first time, you’ll need to burn a Kali Linux microSD card to bootstrap off of. (If you already have a working Pi, then this can be skipped.)
There’s a small amount of free space on the Kali ROOTFS partition; it may be useful to drop any of the SSH private keys here that you’ll eventually want to use to use to log into the Pi here to make it easier to copy them into the right locations later.
We’ll need more space in ROOTFS than the Kali image provides out-of-the-box. The kalipi-config tool can make this happen, but unfortunately it doesn’t recognize the the 64-bit images as a Raspberry Pi! To fix this, you’ll need to edit /usr/bin/kalipi-config and hack the is_pi() function so that it always returns 0. Once you’ve done this, run sudo kalipi-config and use Advanced Options → Expand Filesystem to reclaim the rest of your microSD card’s space.
You’re now ready to bootstrap your actual system!
Set up the encrypted microSD sard
Now comes the moment of truth: Shut down and unplug the Pi, remove the bootstrap microSD card and the reader, put the microSD card you just created (from the reader, with the encrypted ROOTFS) into the Pi, and then plug the Pi back in. If everything went right, you should be prompted to enter the decryption passphrase you set for the microSD card, after which boot will continue and you’ll be able to log into the desktop environment!
(Note that the console unlock message can sometimes get lost in the initial dmesg output.)
First boot
After the first successful boot there’s some basic housekeeping that we should do.
Kali Linux on the Raspberry Pi isn’t configured to use swap, which makes sense because normally it’s running from a slow microSD card. Still, having some swap can aid system stability. We’re going to split the baby by enabling ZRAM.
Begin by create /usr/local/sbin/zram.sh:
Then create the systemd service file /etc/systemd/system/zram.service:
Finally, make sure that everything’s enabled.
You should reboot after doing all of this.
Network access and USB gadget mode
Create /usr/local/sbin/usb0up.sh:
Create /usr/local/sbin/usb0down.sh:
The usb0down.sh script is something you won’t find in other tutorials about setting up a Raspberry Pi in USB gadget mode. Those all focus on bringing the usb0 interface up — none cover how to tear it down successfully. Unfortunately, iPadOS 15 doesn’t like it when USB ethernet gadget goes partially down when exiting the initramfs (we’ll cover this part of things in the next section). To work around this, we need to have the ability to completely remove usb0 so that the device doesn’t exist at all when the initramfs terminates and normal userland takes over.
Now that we can bring usb0 completely up and down, let’s tie things together. Create the systemd service file /etc/systemd/system/usb0.service:
Finally, let’s activate everything.
Second moment of truth: Shut down the system, remove the power, and connect the Pi to your iPad over USB C. The Pi should power on, and then shortly after you unlock the ROOTFS the iPad should be assigned an IPv4 address via the ethernet device “Kali Linux”. You should then be able to SSH in as kali@10.55.0.1.
Third moment of truth: Reboot your system. After a few moments you should be able to SSH into it as root@10.55.0.1 (over USB C) and be prompted to unlock your root device. After you type in your decryption passphrase, SSH should automatically close and your system should continue to boot. In a few more moments you should be able to SSH back in as kali@10.55.0.1.
You can also still unlock the system at the console, which is handy if you want to use the Pi as a stand-alone computer.
Note an annoying feature of this setup — you have to SSH in as root to do the initial unlock, but then will need to SSH in a second time as kali once the system is fully up. Partly, this is due to the fact that there’s not really a way to hand SSH off from the initram environment to the full system (this is why you have to log in once to unlock, and again to use the system once it’s fully up). Theoretically it should be possible to add a kali user to the initramfs, but doing so would require both the dropbear initramfs hooks to be modified (which, as previously mentioned, is fragile w.r.t. upgrades) and a lot more magic in generally than seems advisable.
Network hardening
Now that we’ve got the Pi working with our iPad, we’re going to lock down networking a bit
If you’re going to be using this device covertly, you almost certainly also want to run sudo systemctl disable NetworkManager.service so that the Pi doesn’t attempt to immediately connect to whatever network you plug it into.
Remote desktop
You should now be able to log in using RDP. Standard resolutions work well, but HiDPI/Retina is only marginally more responsive than a slideshow.
As with the dropbear configuration in the previous section, please do not set up RDP like I’m presenting here if you’re using a device that’s exposed to a larger network, or worse yet the internet as a whole. In the real world, RDP servers should only be accessible over SSH, a VPN, or some other secure wrapper — never exposed directly as we’re doing here. The reason we can get away with less is (again) because we’re only exposing RDP over the usb0 interface, and the only other device that ever lives on that network is the iPad.
NOTE
I use Jump Desktop as my RDP client, rather than Microsoft Remote Desktop — while Microsoft’s offering is overall nicer, Jump Desktop is faster and will connect even when the iPad’s Wi-Fi is disconnected (Microsoft will refuse to connect if Wi-Fi is disabled, even though the Pi is accessible via USB ethernet!).