coreos: sish edge config for production
- sish config mirrors kubernetes/base/sish (HTTP by Host on :80, SNI passthrough on :443, raw TCP on 22 and 20000-20099), single tenant via bind-any-host, domain tunnel.traberph.de - host key and connector key provisioned from gitignored coreos/.secrets/ - MemoryMax=256M for sish - Zincati reboot window 03:00-04:00 UTC, daily sish update within v2 with rollback - ignore *.ign (contains the host key) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+147
-22
@@ -1,29 +1,37 @@
|
||||
variant: fcos
|
||||
version: 1.6.0
|
||||
# cirrus: 5001 admin sshd | 5002 sish SSH | 22,80,443 raw TCP -> k8s gateway
|
||||
# cirrus: 5001 admin sshd | 5002 sish SSH | 80 HTTP by Host | 443 TLS by SNI (passthrough)
|
||||
# 22, 20000-20099 raw TCP forwards
|
||||
|
||||
passwd:
|
||||
users:
|
||||
- name: core
|
||||
ssh_authorized_keys:
|
||||
- ssh-ed25519 AAAA_REPLACE_ADMIN_KEY admin
|
||||
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILL4RXmGVhbcCdh3a6TdgR+7EER250UUDk0VtrwUvb9E philipp@philipp-laptop
|
||||
|
||||
storage:
|
||||
directories:
|
||||
- path: /var/lib/sish/keys # sish host key, generated on first start
|
||||
- path: /var/lib/sish/keys
|
||||
mode: 0700
|
||||
user: { id: 65532 }
|
||||
group: { id: 65532 }
|
||||
files:
|
||||
# Edge SSH host key (connectors pin its public half). Kept only locally in coreos/.secrets/
|
||||
# (gitignored), so back it up outside this folder. Build: butane --files-dir coreos ...
|
||||
- path: /var/lib/sish/keys/ssh_host_ed25519_key
|
||||
mode: 0400
|
||||
user: { id: 65532 }
|
||||
group: { id: 65532 }
|
||||
contents:
|
||||
local: .secrets/ssh_host_ed25519_key
|
||||
- path: /var/lib/sish/pubkeys/clients # k8s tunnel client keys (authorized_keys format)
|
||||
mode: 0644
|
||||
contents:
|
||||
inline: |
|
||||
ssh-ed25519 AAAA_REPLACE_CLIENT_KEY k8s-tunnel
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEsHP4H4HLHCEhycaAV+YZZV/HOr7HSiDkgpMA+WLO56 connector-cumulus
|
||||
- path: /etc/ssh/sshd_config.d/10-cirrus.conf
|
||||
mode: 0644
|
||||
contents:
|
||||
|
||||
inline: |
|
||||
Port 5001
|
||||
AuthenticationMethods publickey
|
||||
@@ -34,6 +42,65 @@ storage:
|
||||
contents:
|
||||
inline: |
|
||||
(allow sshd_t commplex_link_port_t (tcp_socket (name_bind)))
|
||||
# Same sish config as kubernetes/base/sish/config.yml (+ the cirrus overlay values),
|
||||
# only the SSH port differs (5002 instead of 2222).
|
||||
- path: /etc/sish/config.yml
|
||||
mode: 0644
|
||||
contents:
|
||||
inline: |
|
||||
# Listeners
|
||||
ssh-address: ":5002"
|
||||
http-address: ":80"
|
||||
https: false # sish never terminates TLS; :443 is an SNI passthrough listener
|
||||
|
||||
# Single tenant: connectors may claim any hostname containing a dot, wildcards included
|
||||
# (*.example.com). Only a name without a dot falls back to <name>.<domain>.
|
||||
bind-any-host: true
|
||||
verify-dns: false # _sish TXT ownership checks, pointless with bind-any-host
|
||||
domain: tunnel.traberph.de # the edge's own name (A/AAAA -> VPS)
|
||||
|
||||
# SNI passthrough + multiple connectors per hostname
|
||||
sni-proxy: true
|
||||
sni-load-balancer: true
|
||||
tcp-load-balancer: true
|
||||
http-load-balancer: true
|
||||
|
||||
# Connectors get exactly what they ask for, or the bind fails
|
||||
bind-random-ports: false
|
||||
bind-random-subdomains: false
|
||||
bind-random-aliases: false
|
||||
force-requested-subdomains: true
|
||||
force-requested-ports: true
|
||||
bind-wildcards: true
|
||||
# Ports connectors may claim. Must match the nftables rule below, otherwise a claimed
|
||||
# port is silently unreachable.
|
||||
# 22 gitea ssh, 443 SNI, 20000-20099 reserved for raw tcp forwards.
|
||||
port-bind-range: "22,443,20000-20099"
|
||||
|
||||
# PROXY header version for connectors that request it (sish-client default: v2)
|
||||
proxy-protocol: true
|
||||
proxy-protocol-version: "2"
|
||||
|
||||
# Default is 5s, which kills idle websockets/SSE/slow uploads
|
||||
idle-connection-timeout: 1h
|
||||
|
||||
# Auth: public keys only
|
||||
authentication: true
|
||||
authentication-keys-directory: /pubkeys
|
||||
private-keys-directory: /keys
|
||||
|
||||
# No web UI / consoles
|
||||
redirect-root: false
|
||||
admin-console: false
|
||||
service-console: false
|
||||
load-templates: false
|
||||
# Default -1 makes the HTTP muxer io.ReadAll() every request/response body into memory
|
||||
# (for the console), even with consoles disabled: large uploads OOM-kill sish.
|
||||
# 0 = never buffer, stream bodies through.
|
||||
service-console-max-content-length: 0
|
||||
|
||||
log-to-stdout: true
|
||||
log-to-file: false
|
||||
- path: /etc/containers/systemd/sish.container
|
||||
mode: 0644
|
||||
contents:
|
||||
@@ -51,30 +118,65 @@ storage:
|
||||
AddCapability=CAP_NET_BIND_SERVICE
|
||||
NoNewPrivileges=true
|
||||
ReadOnly=true
|
||||
Volume=/var/lib/sish/keys:/keys:Z
|
||||
Volume=/etc/sish:/config:ro,Z
|
||||
Volume=/var/lib/sish/keys:/keys:ro,Z
|
||||
Volume=/var/lib/sish/pubkeys:/pubkeys:ro,Z
|
||||
Exec=--ssh-address=:5002 \
|
||||
--domain=cirrus.example.com \
|
||||
--private-keys-directory=/keys \
|
||||
--authentication-keys-directory=/pubkeys \
|
||||
--http-address=127.0.0.1:5080 \
|
||||
--http-request-port-override=5080 \
|
||||
--https-request-port-override=5080 \
|
||||
--port-bind-range=22,80,443 \
|
||||
--bind-random-ports=false \
|
||||
--force-requested-ports=true \
|
||||
--force-tcp-address=true \
|
||||
--tcp-load-balancer=true \
|
||||
--idle-connection=false \
|
||||
--proxy-protocol=true \
|
||||
--proxy-protocol-version=userdefined
|
||||
Exec=--config=/config/config.yml
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
MemoryMax=256M
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
# OS updates: Zincati stages new FCOS releases automatically, this limits the reboot to a window
|
||||
- path: /etc/zincati/config.d/55-updates-strategy.toml
|
||||
mode: 0644
|
||||
contents:
|
||||
inline: |
|
||||
[updates]
|
||||
strategy = "periodic"
|
||||
[[updates.periodic.window]]
|
||||
days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
|
||||
start_time = "03:00" # UTC
|
||||
length_minutes = 60
|
||||
# sish updates: no floating tags upstream (only vX.Y.Z), so podman auto-update can't follow a
|
||||
# version line. This bumps Image= to the newest tag within TRACK and rolls back if sish
|
||||
# doesn't come up again.
|
||||
- path: /usr/local/bin/sish-update
|
||||
mode: 0755
|
||||
contents:
|
||||
inline: |
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
TRACK=v2. # "v2." = minor + patch releases, "v2.24." = patch releases only
|
||||
unit=/etc/containers/systemd/sish.container
|
||||
repo=ghcr.io/antoniomika/sish
|
||||
|
||||
current=$(sed -n "s|^Image=$repo:||p" "$unit")
|
||||
latest=$(podman search --list-tags --limit 10000 --format '{{.Tag}}' "$repo" \
|
||||
| grep -E "^${TRACK//./\\.}[0-9]+(\.[0-9]+)*$" | sort -V | tail -n1)
|
||||
if [[ -z $latest || $(printf '%s\n' "$current" "$latest" | sort -V | tail -n1) == "$current" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
set_image() {
|
||||
sed -i "s|^Image=.*|Image=$repo:$1|" "$unit"
|
||||
systemctl daemon-reload
|
||||
systemctl restart sish.service
|
||||
}
|
||||
|
||||
echo "sish: $current -> $latest"
|
||||
podman pull -q "$repo:$latest" >/dev/null
|
||||
set_image "$latest"
|
||||
sleep 30
|
||||
if ! ss -Htln 'sport = :5002' | grep -q .; then
|
||||
echo "sish $latest not listening on :5002, rolling back to $current" >&2
|
||||
set_image "$current"
|
||||
exit 1
|
||||
fi
|
||||
podman image prune -af >/dev/null
|
||||
- path: /etc/sysconfig/nftables.conf
|
||||
mode: 0600
|
||||
overwrite: true
|
||||
@@ -91,7 +193,7 @@ storage:
|
||||
meta l4proto { icmp, ipv6-icmp } accept
|
||||
udp sport 67 udp dport 68 accept
|
||||
ip6 saddr fe80::/10 udp sport 547 udp dport 546 accept
|
||||
tcp dport { 22, 80, 443, 5001, 5002 } accept
|
||||
tcp dport { 22, 80, 443, 5001, 5002, 20000-20099 } accept # sish ports: see port-bind-range
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,4 +216,27 @@ systemd:
|
||||
WantedBy=multi-user.target
|
||||
- name: nftables.service
|
||||
enabled: true
|
||||
- name: sish-update.service
|
||||
contents: |
|
||||
[Unit]
|
||||
Description=Update sish within its major version
|
||||
Wants=network-online.target
|
||||
After=network-online.target sish.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/local/bin/sish-update
|
||||
- name: sish-update.timer
|
||||
enabled: true
|
||||
contents: |
|
||||
[Unit]
|
||||
Description=Daily sish update check
|
||||
|
||||
[Timer]
|
||||
OnCalendar=*-*-* 05:00:00 UTC
|
||||
RandomizedDelaySec=30m
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
|
||||
|
||||
Reference in New Issue
Block a user