Radagast — stunnel client identity and kelp tunnels

Parent: Infrastructure TLS; Radagast host overview

Configured and verified on 2026-10-17. Radagast initiates mutually authenticated TLS to kelp using a distinct RSA-4096 client identity signed by the existing pomelo CA. Its private key was generated on Radagast and remains there; only the CSR and signed public certificate crossed hosts. Kelp already trusted this CA, so no kelp configuration reload or certificate replacement was needed.

Identity and files

Client subject: C=UK, O=Critchley, CN=radagast.critchley.biz; SAN DNS:radagast.critchley.biz; basicConstraints CA:FALSE; extendedKeyUsage clientAuth. Valid from 2026-10-17 until 2035-01-03, before the CA expires on 2035-09-02. Serial 69D78E389A682321565A82E4BB34284A. Certificate SHA256 fingerprint: 31:BE:26:B8:7B:E6:42:77:81:58:8A:F4:D6:09:E9:7A:B6:F5:8B:B1:A2:1F:D0:A5:8A:F5:77:6E:8C:37:8B:B2.

On Radagast: /usr/local/etc/stunnel/pki/radagast.key (root:stunnel, 0640); radagast.pem (signed public certificate); CA.pem (public trust anchor); radagast.csr (public request). The pki directory is root:stunnel, 0750. On pomelo: public issuance records are /home/john/ssl/C/clients/radagast/radagast.csr and radagast.pem. The signing key remains /home/john/ssl/C/CA/key on pomelo. Kelp's /etc/stunnel/server.pem matches the same CA (SHA256 13:BE:92:0E:8C:43:43:36:0F:B3:8A:B8:B4:D0:DE:02:BB:26:F5:01:62:E6:35:1C:8C:DD:5E:01:38:4E:64:65).

Issued following Option B: fresh per-host client certificate. CSR creation and verification used openssl req -config /dev/null because Radagast's base openssl expects a missing /etc/ssl/openssl.cnf. The CSR explicitly included the subject and extensions. Pomelo signed with openssl x509 -req -copy_extensions copy -days 3000 and a random 128-bit serial; no CA key or shared pomelo client key was copied to the guest.

Source installation and service

Built security/stunnel from the existing ports tree, installing stunnel-5.82,1 linked to the already installed OpenSSL 3.5.9. No binary package installation. Installation command, run as root on Radagast:

make -C /usr/ports/security/stunnel BATCH=yes MAKE_JOBS_NUMBER=2 install

Configuration is /usr/local/etc/stunnel/stunnel.conf (0644, root:wheel). Service drops privileges to stunnel. It is enabled across guest reboots with stunnel_enable=YES in /etc/rc.conf. Operations:

sysrc stunnel_enable=YES
service stunnel start
service stunnel status
sockstat -4 -l
# Logs are written to /var/log/messages.

Client configuration

# Documentation: notes ssl/radagast
pid = /var/run/stunnel/stunnel.pid
setuid = stunnel
setgid = stunnel
syslog = yes
debug = notice

client = yes
cert = /usr/local/etc/stunnel/pki/radagast.pem
key = /usr/local/etc/stunnel/pki/radagast.key
CAfile = /usr/local/etc/stunnel/pki/CA.pem
verify = 2
checkHost = John Critchley
sslVersionMin = TLSv1.2
delay = yes
socket = r:SO_KEEPALIVE=1
socket = r:TCP_KEEPIDLE=60
socket = r:TCP_KEEPINTVL=20
socket = r:TCP_KEEPCNT=3

[kelp-socks5]
accept = 127.0.0.1:1080
connect = kelp.critchley.biz:11080

[kelp-dante]
accept = 127.0.0.1:12081
connect = kelp.critchley.biz:12080

Both local listeners bind only to loopback. delay=yes resolves kelp's DNS when connecting, avoiding startup-only DNS caching. The 1080 endpoint is kelp's microsocks internet proxy. The 12081 endpoint is kelp's loopback-only Dante service used by SOCKS5 BIND; it can CONNECT to kelp-local services but is not an internet egress proxy because Dante uses external:127.0.0.1. Reverse SSH and VNC BIND services were subsequently configured on 2026-10-17; remote access on kelp:2225 and kelp:15905.

Verification

openssl verify -purpose sslclient -CAfile /usr/local/etc/stunnel/pki/CA.pem /usr/local/etc/stunnel/pki/radagast.pem
curl --fail --silent --show-error --head --max-time 25 --proxy socks5h://127.0.0.1:1080 https://www.critchley.biz/rainbow/distribution-gallery.png
nc -w 3 -X 5 -x 127.0.0.1:1080 127.0.0.1 22 < /dev/null
nc -w 3 -X 5 -x 127.0.0.1:12081 127.0.0.1 22 < /dev/null

Verified: certificate chain and sslclient purpose OK; HTTP 200 through the 1080 TLS proxy; both nc tests returned kelp's SSH-2.0-OpenSSH_10.0p2 Debian-7+deb13u4 banner. Radagast's stunnel logs recorded acceptance of the expected kelp certificate for both services.

# Expected to FAIL: no client certificate presented.
openssl s_client -connect kelp.critchley.biz:11080 -CAfile /usr/local/etc/stunnel/pki/CA.pem -verify_return_error -brief -tls1_2 < /dev/null

The negative test failed with TLS alert handshake failure. Kelp's /var/log/stunnel.log confirmed peer did not return a certificate. This verifies certificate enforcement, rather than merely a running service.

version 2  ·  created 2026-10-17  ·  updated 2026-10-17  ·  tags radagast, kelp, stunnel, tls, pki, freebsd