Files
socktop-webterm/kubernetes/03-deployment.yaml
T
jasonwitty 5637dea10b
Build and Deploy to K3s / test (push) Successful in 1m31s
Build and Deploy to K3s / lint (push) Successful in 59s
Build and Deploy to K3s / build-and-push (push) Successful in 5m40s
Build and Deploy to K3s / deploy (push) Successful in 1m9s
Gate image builds on socktop CLI compatibility; fix agent probe; caps for entrypoint
- CI now builds the image locally on the (arm64) runner and runs
  scripts/verify-image-socktop-flags.sh before pushing: every --flag the
  restricted/session shells pass must be documented by the socktop
  binary actually installed in the image. Catches the 0.3.9 failure
  class (cached apt layer shipping a pre-flag socktop) at build time.
- Manifest adds CHOWN/DAC_OVERRIDE/FOWNER alongside SETUID/SETGID:
  with ALL dropped, uid 0 has no implicit file privilege and
  prepare_demo_home crash-looped on the demo-owned 700 home dir.
  Sessions still run with zero capabilities via setpriv.
- Agent liveness probe uses /proc instead of kill -0: without CAP_KILL
  even root gets EPERM signalling the socktop-user agent, so the old
  check false-alarmed in the pod logs.
- 0.3.11

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 09:46:27 -07:00

208 lines
7.1 KiB
YAML

apiVersion: apps/v1
kind: Deployment
metadata:
name: socktop-webterm
labels:
app: socktop-webterm
spec:
replicas: 3
selector:
matchLabels:
app: socktop-webterm
template:
metadata:
labels:
app: socktop-webterm
spec:
# Use standard pod networking
hostNetwork: false
dnsPolicy: ClusterFirst
# Security context for the pod
securityContext:
runAsUser: 100
runAsGroup: 101
fsGroup: 101
# Init container to set up configuration
initContainers:
- name: init-config
image: gt.wittyoneoff.com/jason/socktop-webterm:0.2.2
imagePullPolicy: Always
command: ["/bin/bash", "-c"]
args:
- |
set -e
echo "Setting up configuration directories..."
mkdir -p /var/lib/socktop/.config/socktop/certs
mkdir -p /var/lib/socktop/.config/alacritty
if [ -f "/home/socktop/.config/socktop/profiles.json" ]; then
cp /home/socktop/.config/socktop/profiles.json /var/lib/socktop/.config/socktop/profiles.json
echo "Copied profiles.json"
fi
if [ -f "/home/socktop/.config/alacritty/alacritty.toml" ]; then
cp /home/socktop/.config/alacritty/alacritty.toml /var/lib/socktop/.config/alacritty/alacritty.toml
echo "Copied alacritty.toml"
fi
if [ -f "/home/socktop/.config/alacritty/catppuccin-frappe.toml" ]; then
cp /home/socktop/.config/alacritty/catppuccin-frappe.toml /var/lib/socktop/.config/alacritty/catppuccin-frappe.toml
echo "Copied catppuccin-frappe.toml"
fi
if [ -d "/home/socktop/.config/socktop/certs" ]; then
cp /home/socktop/.config/socktop/certs/*.pem /var/lib/socktop/.config/socktop/certs/ 2>/dev/null || true
echo "Copied certificates"
fi
# Fix paths in profiles.json
if [ -f "/var/lib/socktop/.config/socktop/profiles.json" ]; then
sed -i 's|/home/socktop/.config/socktop/rpi-|/var/lib/socktop/.config/socktop/certs/rpi-|g' /var/lib/socktop/.config/socktop/profiles.json
echo "Updated certificate paths"
fi
echo "Configuration setup complete"
volumeMounts:
- name: config
mountPath: /home/socktop/.config/socktop/profiles.json
subPath: profiles.json
- name: config
mountPath: /home/socktop/.config/alacritty/alacritty.toml
subPath: alacritty.toml
- name: config
mountPath: /home/socktop/.config/alacritty/catppuccin-frappe.toml
subPath: catppuccin-frappe.toml
- name: certs
mountPath: /home/socktop/.config/socktop/certs
readOnly: true
- name: socktop-home
mountPath: /var/lib/socktop
securityContext:
runAsUser: 100
runAsGroup: 101
containers:
- name: webterm
image: gt.wittyoneoff.com/jason/socktop-webterm:0.3.11
imagePullPolicy: Always
command: ["/docker-entrypoint.sh"]
args:
[
"webterm-server",
"--host",
"0.0.0.0",
"--port",
"8082",
"--command",
"/usr/local/bin/session-shell.sh",
]
ports:
- name: http
containerPort: 8082
protocol: TCP
- name: agent
containerPort: 3001
protocol: TCP
env:
- name: TERM
value: "xterm-256color"
- name: TZ
value: "America/New_York"
- name: RUST_LOG
value: "info"
# Disable socktop's local process-kill feature for every socktop
# launched anywhere under this pod, regardless of command line.
# The restricted shell also passes --no-kill, but this is the layer
# a visitor cannot route around (no way to unset env from the
# restricted shell).
- name: SOCKTOP_NO_KILL
value: "1"
resources:
limits:
cpu: "2000m"
memory: "1Gi"
requests:
cpu: "500m"
memory: "256Mi"
livenessProbe:
httpGet:
path: /
port: 8082
initialDelaySeconds: 10
periodSeconds: 30
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /
port: 8082
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
volumeMounts:
- name: config
mountPath: /home/socktop/.config/socktop/profiles.json
subPath: profiles.json
- name: config
mountPath: /home/socktop/.config/alacritty/alacritty.toml
subPath: alacritty.toml
- name: config
mountPath: /home/socktop/.config/alacritty/catppuccin-frappe.toml
subPath: catppuccin-frappe.toml
- name: certs
mountPath: /home/socktop/.config/socktop/certs
readOnly: true
- name: socktop-home
mountPath: /var/lib/socktop
# webterm-server runs as in-container root holding ONLY
# CAP_SETUID/CAP_SETGID (everything else dropped, no privilege
# escalation), so it can drop each websocket session to the
# unprivileged `demo` user via session-shell.sh. The kernel then
# refuses any signal a session aims at the server, the agent
# (running as `socktop`), or another session's UID — the kill
# feature's UI gating stops being the only line of defense.
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
add:
- SETUID
- SETGID
# prepare_demo_home (entrypoint.sh) writes into and re-owns
# /home/demo, which the image ships as demo-owned 700. With
# ALL dropped, uid 0 has no implicit file privilege, so the
# three file caps must come back or the entrypoint crashes on
# mkdir/chown/chmod. Sessions still get zero caps — session-
# shell.sh drops them all via setpriv --inh-caps -all.
- CHOWN
- DAC_OVERRIDE
- FOWNER
readOnlyRootFilesystem: false
runAsUser: 0
runAsGroup: 0
volumes:
- name: config
configMap:
name: socktop-webterm-config
- name: certs
secret:
secretName: socktop-webterm-certs
optional: true
- name: socktop-home
emptyDir: {}
restartPolicy: Always