spiped Secure Pipe Daemon on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and configuration of spiped on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. spiped, pronounced "ess pipe dee", is a secure pipe daemon: it creates a symmetrically encrypted and authenticated pipe between two socket addresses, so you can connect to one address and transparently reach another across an untrusted network. It is similar in spirit to an SSH port forward, but it is a purpose built daemon rather than a side effect of a shell session, and it uses a pre shared symmetric key instead of SSH credentials.
The image builds spiped 1.6.4 from the official signed upstream release tarball (www.tarsnap.com/spiped/spiped-1.6.4.tgz), with the tarball verified against the upstream published SHA-256 during the build, so the exact version is reproducible and there is no third party package repository on the running VM. Both daemons run under systemd as the unprivileged spiped user. Unattended security upgrades keep the base OS patched.
A pipe has two ends, and this image ships both. That is what makes it provable the moment it boots, with no second machine to set up first:
-
spiped.serviceis the server side. It accepts encrypted connections on TCP 8022 and forwards the decrypted stream to the service you are protecting. -
spiped-client.serviceis the client side. It accepts plaintext connections on 127.0.0.1:9022 and forwards them encrypted to the server side.
As shipped the client side loops back to the server side on the same VM, so connecting to 127.0.0.1:9022 traverses the complete encrypt then decrypt path and reaches the protected service. In a real deployment you keep the server side here and run the client side on your own machine; the shipped client is both a working end to end proof and the template you copy for that remote endpoint.
Secure by design, with nothing baked in. spiped uses a symmetric key, so whoever holds the key can both open and impersonate the pipe. A key shipped inside the image would therefore be a shared secret on every customer VM and would defeat the product entirely. This image never ships key material. On the very first boot of every VM a fresh 256 bit key is generated from the kernel random source, unique to that instance, and recorded in /root/spiped-credentials.txt (mode 0600, root only). Both daemons are held behind a bootstrap gate until that has happened, so neither can ever start with missing or shared key material.
The key is a credential gate, not just encryption. spiped authenticates during its handshake, so a peer that cannot prove it holds this VM's key is dropped before any byte reaches the protected service. A plaintext client, or a client with the wrong key, never gets through at all.
What is included:
-
spiped 1.6.4 built from the pinned, checksum verified upstream source, with both
spipedand thespipeone shot client, run under systemd as the unprivilegedspipeduser -
An encrypted pipe endpoint on TCP 8022 and a local plaintext endpoint on 127.0.0.1:9022, wired together and to this VM's SSH service as a working demonstration you repoint at your own service
-
A per instance 256 bit key generated on first boot, documented with a fingerprint and a transportable copy in
/root/spiped-credentials.txt(0600) -
A hardened baseline: the plaintext endpoint bound to loopback only, an unprivileged runtime user, and
CAP_NET_BIND_SERVICEgranted so you can move the encrypted endpoint to a privileged port such as 443 without editing the unit -
Everything driven from one short, commented file at
/etc/spiped/spiped.conf, so you retarget the pipe without touching systemd units
Key facts
| Item | Value |
|---|---|
| Platform | Ubuntu 24.04 LTS on Azure |
| Default administrative user | azureuser |
| Encrypted pipe endpoint | TCP 8022 (all interfaces) |
| Local plaintext endpoint | TCP 9022 (loopback only) |
| Key file | /etc/spiped/spiped.key (0640 root:spiped) |
| Credentials file | /root/spiped-credentials.txt (0600 root:root) |
| Configuration | /etc/spiped/spiped.conf |
Prerequisites
-
Active Azure subscription, SSH public key, VNet and subnet in target region
-
Subscription to the spiped listing on Azure Marketplace
-
Network Security Group rules allowing TCP 22 for administration, and TCP 8022 from the clients that will use the pipe
-
A way to copy a small secret to the machine that will run the client side, over a channel you already trust
Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM). Encryption throughput scales with CPU, so busy pipes should use Standard_D2s_v5 or larger.
Step 1: Deploy from the Azure Portal
Search spiped in Marketplace, select the cloudimg publisher, and click Create. Configure the Network Security Group to allow TCP 8022 from your client networks, and TCP 22 for administration. Leave the plaintext port 9022 closed; it is bound to loopback and is not meant to be reachable from the network.
Step 2: Deploy from the Azure CLI
RG="pipe-prod"; LOCATION="eastus"; VM_NAME="pipe1"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/spiped-ubuntu-24-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az vm create \
--resource-group "$RG" --name "$VM_NAME" \
--image "$GALLERY_IMAGE_ID" \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values "$SSH_KEY" \
--public-ip-sku Standard
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 8022 --priority 1001
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 22 --priority 1002
Step 3: First boot
On first boot the image generates this VM's 256 bit key, writes it to /etc/spiped/spiped.key, records its fingerprint and a transportable copy in /root/spiped-credentials.txt, and only then releases the two spiped units to start. This completes within a few seconds. SSH in as azureuser and read the details:
sudo cat /root/spiped-credentials.txt
The file names the key file, its SHA-256 fingerprint, a base64 copy you can carry to the client machine, and the two endpoints. Keep it root only; it is the one place the key exists in a form you can copy.
Step 4: Confirm both ends of the pipe are running
Both units run under systemd as the unprivileged spiped user. ss confirms the encrypted endpoint is listening on all interfaces and the plaintext endpoint is bound to loopback only.
systemctl is-active spiped.service
systemctl is-active spiped-client.service
ps -o user= -C spiped | sort -u | tr -d ' '
ss -tlnp | grep -E ':8022 |:9022 '
Expected output:
active
active
spiped
LISTEN 0 10 127.0.0.1:9022 0.0.0.0:* users:(("spiped",pid=3406,fd=3))
LISTEN 0 10 0.0.0.0:8022 0.0.0.0:* users:(("spiped",pid=3405,fd=3))

You can also confirm the build:
timeout 10 spiped -v </dev/null 2>&1
spiped 1.6.4
Note the `