Expose config options for cleartext stratum port

This commit is contained in:
2026-08-01 06:31:15 +03:00
commit a2ae800a19
36 changed files with 4585 additions and 0 deletions
+114
View File
@@ -0,0 +1,114 @@
#!/bin/bash
# Kamado Pool — stratum TLS certificate init (oneshot, idempotent).
#
# Generates the persisted self-signed stratum certificate the stunnel
# daemon serves. Regenerates only when files are missing or the cert-format
# version marker is outdated, so miners' pinned fingerprints survive
# restarts and updates. Run the "Regenerate TLS Certificate" action to
# force a fresh one.
#
# Env (set by main.ts): TLS_DIR (defaults to /root/.kamado/tls).
set -euo pipefail
TLS_DIR="${TLS_DIR:-/root/.kamado/tls}"
CRT="${TLS_DIR}/stratum.crt"
KEY="${TLS_DIR}/stratum.key"
CERT="${TLS_DIR}/stratum.pem"
MARKER="${TLS_DIR}/cert_version"
mkdir -p "${TLS_DIR}"
# Bump TLS_CERT_VERSION any time the cert format/extensions change.
# The startup check regenerates whenever the marker file is missing
# or doesn't match this version. This is more reliable than poking
# at the existing cert's extensions — we know *exactly* when a new
# shape is required and the upgrade self-heals on next boot.
# v4: broaden subjectAltName to cover mDNS / LAN / Tor hostnames
# so miner firmwares that verify the SAN against the hostname
# they were pointed at (e.g. AxeOS connecting to host.local)
# stop failing with MBEDTLS_ERR_X509_CERT_VERIFY_FAILED.
TLS_CERT_VERSION=4
NEEDS_REGEN=false
if [[ ! -f "${CERT}" || ! -f "${CRT}" || ! -f "${KEY}" ]]; then
NEEDS_REGEN=true
elif [[ ! -f "${MARKER}" ]] \
|| [[ "$(cat "${MARKER}" 2>/dev/null)" != "${TLS_CERT_VERSION}" ]]; then
echo "kamado-tls: TLS cert is older format (want v${TLS_CERT_VERSION}); regenerating"
NEEDS_REGEN=true
fi
if [[ "${NEEDS_REGEN}" == "true" ]]; then
echo "kamado-tls: generating self-signed stratum TLS cert v${TLS_CERT_VERSION}"
# Write the extensions to a config file rather than rely on
# `-addext`: some openssl builds emit them into unpredictable
# locations (e.g. CSR instead of the cert), and this is the
# documented, cross-version way to pin the full extension set.
CONF=$(mktemp)
cat > "${CONF}" <<'OPENSSL_CONF'
[ req ]
default_bits = 2048
default_md = sha256
prompt = no
distinguished_name = req_dn
x509_extensions = v3_cert
[ req_dn ]
CN = kamado-pool
[ v3_cert ]
basicConstraints = critical, CA:FALSE
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectKeyIdentifier = hash
subjectAltName = @alt_names
[ alt_names ]
# Specific StartOS / local names the pool might be reached through.
DNS.1 = kamado-pool.embassy
DNS.2 = kamado-pool
DNS.3 = localhost
# Wildcard SANs covering the TLDs miners typically use:
# *.local -> mDNS / Bonjour (e.g. obese-admirer.local on AxeOS)
# *.embassy -> StartOS inter-service hostnames
# *.onion -> Tor hidden services
# *.home.arpa -> RFC 8375 home network namespace
# *.lan -> common consumer router default TLD
# *.internal -> some LAN setups
# Strictly leftmost-label wildcards per RFC 6125; libraries that
# enforce this (mbedtls, OpenSSL, BoringSSL, Go crypto/tls) all
# accept them.
DNS.4 = *.local
DNS.5 = *.embassy
DNS.6 = *.onion
DNS.7 = *.home.arpa
DNS.8 = *.lan
DNS.9 = *.internal
IP.1 = 127.0.0.1
OPENSSL_CONF
openssl req -x509 -newkey rsa:2048 -nodes \
-keyout "${KEY}" \
-out "${CRT}" \
-days 3650 \
-config "${CONF}" \
>/dev/null 2>&1
rm -f "${CONF}"
# stunnel reads cert+key in either order, but cert-first is the
# convention openssl and most tooling expect.
cat "${CRT}" "${KEY}" > "${CERT}"
chmod 600 "${KEY}" "${CERT}"
printf '%s\n' "${TLS_CERT_VERSION}" > "${MARKER}"
# Log the extensions so operators can verify the cert is sane
# from the service logs without needing to exec into the
# container.
echo "kamado-tls: cert extensions:"
openssl x509 -in "${CRT}" -noout -ext subjectAltName,extendedKeyUsage,keyUsage 2>&1 \
| sed 's/^/ /'
fi
FINGERPRINT=$(openssl x509 -in "${CRT}" -noout -fingerprint -sha256 | cut -d= -f2)
printf '%s\n' "${FINGERPRINT}" > "${TLS_DIR}/fingerprint.txt"
echo "kamado-tls: stratum TLS SHA256 fingerprint: ${FINGERPRINT}"