spiped Secure Pipe Daemon 1.6.4 on AWS User Guide
Overview
This guide covers launching and verifying spiped Secure Pipe Daemon 1.6.4 on Ubuntu 24.04 from cloudimg on Amazon EC2. It is one version of the cloudimg Hardened WireGuard VPN & VPN, Proxy and Remote Access AMIs listing on AWS Marketplace; you pick it as the software version when you subscribe and launch. The other VPN, proxy and remote access servers in the listing are described on the listing's guide hub.
spiped (pronounced "ess-pipe-dee") is a small daemon from Tarsnap that creates a symmetrically encrypted and authenticated pipe between two socket addresses. Both ends hold the same key file. The server side (spiped -d) accepts encrypted connections and forwards them, decrypted, to a fixed target; the client side (spiped -e, or the one-shot spipe) accepts plaintext connections on your machine and forwards them encrypted. Every connection is authenticated with the shared key and protected with AES-256 and HMAC-SHA256, with a Diffie-Hellman exchange per connection for forward secrecy. A connection that cannot prove the key never reaches the target. spiped is a headless network service with no web console.
In this image the server side listens on port 8022 and forwards to the instance's own SSH server, so port 8022 carries SSH to this instance through the encrypted pipe. You can point it at any other TCP service on the instance instead (see Step 8).
What cloudimg adds
- The current upstream release, verified. Ubuntu 24.04 only carries spiped 1.6.2 in its community-maintained universe component. This image ships spiped 1.6.4 (the newest release), built from the unmodified Tarsnap release tarball after its SHA-256 checksum was checked against the value Tarsnap publishes on its website and in the release announcement signed by Colin Percival. The binaries are built as position-independent executables with full RELRO, a stack protector and
_FORTIFY_SOURCE=3, and the compiler and build tools are removed again before the image is captured. - A unique key per instance, generated on first boot. No key is baked into the image. On first boot the instance generates its own 256-bit key from the kernel's random number generator into
/etc/spiped/spiped.key, readable by root only. Neither daemon can start until that key exists. - The key is never shown or written elsewhere.
/root/spiped-credentials.txtholds the key's SHA-256 fingerprint and the endpoints, never the key. Each daemon receives a private read-only copy from systemd when it starts, so thespipedservice account cannot read the key file and owns no file on disk. - First boot proves the pipe. Before it marks the instance ready, first boot checks that the right key reaches SSH through port 8022 and through the loopback client, and that a wrong key and a plaintext connection are refused. If any check fails, both daemons stay stopped.
- Forward secrecy required. The server side runs with
-g, so it refuses clients that try to skip the per-connection Diffie-Hellman exchange. - Hardened services. Both daemons run as an unprivileged
spipeduser with no capabilities, a read-only system, no access to home directories or devices and a restricted set of system calls. A guard refuses to start the loopback client on anything but a loopback address, and refuses a key file that is not root-owned and0600. - No route to the instance metadata service. Both daemons are blocked from the EC2 instance metadata service at the system level (IPv4 and IPv6).
- Key-only SSH. Password and keyboard-interactive login and root login are disabled for SSH, which is also what port 8022 forwards to.
Prerequisites
- An AWS account and permission to launch EC2 instances
- An EC2 key pair in the Region you launch in
- spiped on the machine you will connect from:
sudo apt-get install spiped(Ubuntu, Debian),brew install spiped(macOS) orpkg install spiped(FreeBSD). The spiped package from your distribution or Homebrew works as the client.
Recommended instance type: m5.large. spiped itself uses very little CPU and memory; t3.micro or larger is enough for SSH and light traffic.
Connecting to your instance
| Version | Operating system | SSH user |
|---|---|---|
| spiped Secure Pipe Daemon 1.6.4 on Ubuntu 24.04 | Ubuntu 24.04 LTS | ubuntu |
| Port | Protocol | Purpose | Who should reach it |
|---|---|---|---|
| 22 | TCP | SSH administration (and to copy the key the first time) | Your administrators |
| 8022 | TCP | spiped server side: the encrypted, key-authenticated pipe to SSH on this instance | The machines that hold the key |
| 9022 | TCP | spiped loopback demonstration client, on 127.0.0.1 only (not reachable from the network) | Nobody off the instance |
Step 1: Launch the instance
Option A: AWS Marketplace console
- Open the cloudimg Hardened WireGuard VPN & VPN, Proxy and Remote Access AMIs listing on AWS Marketplace and choose View purchase options, then Subscribe. One subscription covers every version in the listing.
- Once the subscription is active, choose Launch your software.
- Choose One-click launch from AWS Marketplace (or Launch from EC2 Console for the full launch wizard). In Version, choose spiped Secure Pipe Daemon 1.6.4 on Ubuntu 24.04, then choose your Region.
- Pick an instance type (
m5.largerecommended; the software charge is $0.04 per vCPU per hour) and your key pair. - Security group: the listing's default group allows SSH (22) and spiped (8022). Restrict both to the addresses you will connect from.
- Choose your VPC and subnet, leave the metadata defaults (the image already requires IMDSv2), then choose Launch.
Option B: AWS CLI
Run this on your own workstation. It creates a security group that allows SSH and the pipe from your own address range only, then launches the instance. Replace the AMI ID with the one shown for your Region on the Marketplace launch page, and the VPC, subnet, key pair and CIDR range with your own:
SG=$(aws ec2 create-security-group --group-name spiped \
--description "spiped secure pipe" --vpc-id vpc-0123456789abcdef0 \
--query GroupId --output text)
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 22 --cidr <your-mgmt-cidr>
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 8022 --cidr <your-mgmt-cidr>
aws ec2 run-instances \
--image-id ami-0123456789abcdef0 \
--instance-type m5.large \
--key-name my-key-pair \
--security-group-ids "$SG" \
--subnet-id subnet-0123456789abcdef0 \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=spiped}]'
You do not need --metadata-options: the AMI already makes IMDSv2 required.
Step 2: Connect and read the instance details
Connect as ubuntu with the key pair you chose:
ssh -i ~/.ssh/my-key-pair.pem ubuntu@<public-ip>
First boot finishes within a minute of launch. It generates this instance's key, starts both daemons, checks them and then writes /root/spiped-credentials.txt, readable only by root. This command prints it without the fingerprint line:
sudo grep -v '^KEY_SHA256=' /root/spiped-credentials.txt
# spiped 1.6.4 - written by spiped-firstboot (firstboot). The key is unique to this instance; nothing was baked into
# the image. The key itself is /etc/spiped/spiped.key (0600 root): anyone holding it can open (and impersonate) this
# pipe, so copy it only over SSH and never paste it into chat, e-mail or a ticket.
#
KEY_FILE=/etc/spiped/spiped.key
SPIPED_PORT=8022
SPIPED_VPC_IP=172.31.20.15
SPIPED_PUBLIC_IP=203.0.113.10
SPIPED_TARGET=127.0.0.1:22
SPIPED_LOCAL_CLIENT=127.0.0.1:9022
#
# Copy the key to your machine (run THERE; it travels inside SSH and is never shown on screen):
# ssh -i <your-key.pem> ubuntu@<instance-address> 'sudo cat /etc/spiped/spiped.key' > spiped.key && chmod 600 spiped.key
# sha256sum spiped.key # must print the KEY_SHA256 above
# Then, on your machine: spiped -e -s '[127.0.0.1]:8022' -t '[<instance-address>]:8022' -k spiped.key
# ssh -p 8022 ubuntu@127.0.0.1
# Self-test: sudo spiped-selftest New key: sudo spiped-rotate-key Guide: https://www.cloudimg.co.uk/guides/spiped-secure-pipe-daemon-1-6-4-on-ubuntu-24-04-aws/
SPIPED_VPC_IP is the instance's private address and SPIPED_PUBLIC_IP its public address (none in a subnet without public addresses). To see the key's fingerprint, run sudo grep '^KEY_SHA256=' /root/spiped-credentials.txt. The fingerprint is not secret, but the key file is.
Step 3: Confirm both daemons are running
systemctl is-active spiped spiped-client spiped-firstboot
sudo ss -Hltn | awk '{print $4}' | sort
active
active
active
0.0.0.0:22
0.0.0.0:8022
127.0.0.1:9022
127.0.0.53%lo:53
127.0.0.54:53
[::]:22
The server side is on port 8022. The demonstration client is on 127.0.0.1:9022 only. The two :53 sockets are Ubuntu's local DNS resolver, which listens on loopback only.
Step 4: Run the self-test
The image includes a self-test that exercises the whole pipe without printing the key:
sudo spiped-selftest
ok key fingerprint matches /root/spiped-credentials.txt (264acc198c84...)
ok right key on 8022 reaches sshd (SSH-2.0-OpenSSH_9.6p1)
ok loopback client 127.0.0.1:9022 -> 8022 -> sshd
ok a wrong key is refused on 8022
ok a plaintext client on 8022 never sees sshd
SELFTEST_OK
You can also see the round trip yourself. A plaintext connection to the loopback client on 9022 is encrypted by spiped -e, decrypted by spiped -d on 8022 and handed to SSH, which answers with its banner:
timeout 5 bash -c 'exec 3<>/dev/tcp/127.0.0.1/9022; head -1 <&3'
SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.20
Step 5: Copy the key to your machine
spiped uses a pre-shared key: the machine you connect from needs the same key file. Copy it over SSH, which encrypts it in transit and never shows it on screen. Run this on your own machine, not on the instance:
ssh -i ~/.ssh/my-key-pair.pem ubuntu@<public-ip> 'sudo cat /etc/spiped/spiped.key' > spiped.key
chmod 600 spiped.key
sha256sum spiped.key
On macOS use shasum -a 256 spiped.key. The fingerprint must match the KEY_SHA256 line in /root/spiped-credentials.txt on the instance. Anyone who holds the key can open the pipe, so never paste it into chat, e-mail or a ticket, keep it 0600, and do not commit it to source control.
Step 6: Connect through the pipe
On your machine, start the client side of the pipe. It listens on your own 127.0.0.1:8022 and forwards everything, encrypted, to the instance's port 8022:
spiped -e -s '[127.0.0.1]:8022' -t '[<public-ip>]:8022' -k spiped.key
ssh -i ~/.ssh/my-key-pair.pem -p 8022 ubuntu@127.0.0.1
spiped -e runs in the background and writes its process ID to the file [127.0.0.1]:8022.pid in the current directory. Stop it with kill "$(cat '[127.0.0.1]:8022.pid')" when you are done. SSH will ask you to accept the host key the first time, exactly as on port 22: it is the same SSH server.
For a one-off connection without a background daemon, use spipe as SSH's proxy command:
ssh -i ~/.ssh/my-key-pair.pem -o ProxyCommand="spipe -t '[<public-ip>]:8022' -k spiped.key" ubuntu@<public-ip>
Once the pipe works you can remove port 22 from the instance's security group and reach SSH only through 8022. Keep a way back in (for example AWS Systems Manager Session Manager, or a second security group you can attach) before you do.
Step 7: Confirm a connection without the key is refused
A client with a different key never completes spiped's handshake, so it never reaches SSH. On your machine:
head -c 32 /dev/urandom > wrong.key
spipe -t '[<public-ip>]:8022' -k wrong.key < /dev/null; echo "exit $?"
rm -f wrong.key
spipe: Handshake failed
exit 1
A plain TCP client sees only spiped's handshake bytes, never SSH's banner. The self-test in Step 4 checks both cases on the instance itself.
Step 8: Point the pipe at another service (optional)
The server side's target is set in /etc/spiped/spiped.conf. As shipped it is the instance's SSH server:
SPIPED_SERVER_SOURCE=[0.0.0.0]:8022
SPIPED_SERVER_TARGET=[127.0.0.1]:22
To protect a different service on the instance, for example a PostgreSQL server listening on 127.0.0.1:5432, change SPIPED_SERVER_TARGET to [127.0.0.1]:5432 with sudoedit /etc/spiped/spiped.conf, then run sudo systemctl restart spiped. Your clients then reach PostgreSQL through their local spiped -e exactly as in Step 6. Keep the target on loopback so the service itself is never exposed to the network.
The loopback client (SPIPED_CLIENT_SOURCE, 127.0.0.1:9022) is a demonstration and must stay on a loopback address: spiped-guard refuses to start it anywhere else, because a plaintext listener on the network would let anyone in without the key. Run the client side on the machines you connect from. You can stop it with sudo systemctl disable --now spiped-client.
Step 9: Rotate the key (optional)
To replace the key, for example when someone who held it leaves, run on the instance:
sudo spiped-rotate-key
It generates a new 256-bit key, restarts both daemons, runs the self-test and updates the fingerprint in /root/spiped-credentials.txt. The rotation runs as a system job, so a dropped SSH connection cannot leave it half-done; if it fails, both daemons stay stopped and journalctl -u spiped-rotate-key says why. Every client holding the old key is cut off immediately: copy the new key to them as in Step 5.
Step 10: Logs
spiped writes start-up messages and errors to the journal:
sudo journalctl -u spiped -u spiped-client -n 20 --no-pager
First boot also logs to /var/log/cloudimg-firstboot.log. Neither log contains the key.
How the secure start works
spiped-firstboot.serviceruns once, on the instance's first boot. It reads the instance's addresses from the instance metadata service (IMDSv2), generates a 256-bit key with the kernel's random number generator into/etc/spiped/spiped.key(owner root, mode0600), creates the ready marker and starts both daemons.spiped.serviceandspiped-client.servicestart only when the ready marker exists, so neither can ever run without this instance's own key. Before each start,spiped-guardchecks the key file (root-owned,0600, at least 256 bits, not a link) and that the loopback client listens on loopback.- systemd reads the key as root and gives each daemon a private, read-only copy under
/run/credentials/(LoadCredential). Thespipeduser cannot read/etc/spiped/spiped.keyand owns no file. - First boot then runs the self-test: the right key reaches SSH on 8022 and through 9022, a wrong key and a plaintext client are refused. Only then does it write
/root/spiped-credentials.txt. If any step fails, both daemons are stopped and the ready marker is removed, so the next boot starts over.
Security recommendations
- Restrict ports 22 and 8022 in the security group to the addresses you connect from. When the pipe works, consider closing port 22 entirely and using 8022 only.
- Treat
spiped.keylike a private key: copy it only over SSH, keep it0600, and rotate it withsudo spiped-rotate-keywhen anyone who held it should lose access. - Keep
SPIPED_SERVER_TARGETon a loopback address, and keep the loopback client on loopback. - Keep the instance patched:
sudo apt-get update && sudo apt-get upgrade. Unattended security updates are enabled.
Support and licensing
spiped is open-source software by Colin Percival and Tarsnap Backup Inc., released under the BSD 2-Clause licence (one bundled header is under the BSD 3-Clause licence). The licence texts and the build provenance are in /usr/local/share/doc/spiped/. cloudimg is not affiliated with or endorsed by Tarsnap. For help with this image, contact cloudimg support through the AWS Marketplace listing.