serterm: Deploy serial terminal server
The serial terminal server ("serterm") is a collection of scripts that automate launching multiple `picocom` processes, one per USB-serial adapter connected to the system. Each `picocom` process has its own window in a `tmux` session, which is accessible via SSH on a dedicated port (20022). Clients connecting to that SSH server will be automatically attached to the `tmux` session, allowing them to access the serial terminal server quickly and easily. The SSH server only allows public-key authentication, so the authorized keys have to be pre-configured. In addition to automatically launching `picocom` windows for each serial port when the terminal server starts, ports that are added (hot-plugged) while the server is running will have windows created for them automatically, by way of a udev rule. Each `picocom` process is configured to log communications with its respective serial port. This may be useful, for example, to find diagnostic messages that may not be captured by the `tmux` scrollback buffer.master
parent
9779ac795d
commit
d989994f25
|
@ -0,0 +1,9 @@
|
|||
package schema
|
||||
|
||||
#SerTermSsh: {
|
||||
authorized_keys: [...string]
|
||||
}
|
||||
|
||||
#SerTerm: {
|
||||
ssh: #SerTermSsh
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package serterm
|
||||
|
||||
import "du5t1n.me/cfg/base/schema/instructions"
|
||||
|
||||
templates: [...instructions.#RenderInstruction] & [
|
||||
{
|
||||
template: "serterm/authorized_keys"
|
||||
dest: "/etc/serterm/authorized_keys"
|
||||
hooks: {
|
||||
changed: [
|
||||
{run: "systemctl restart serial-terminal-server"},
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
template: "serterm/95-serial-terminal.rules"
|
||||
dest: "/etc/udev/rules.d/95-serial-terminal.rules"
|
||||
hooks: {
|
||||
changed: [{run: "udevadm control --reload"}]
|
||||
}
|
||||
},
|
||||
{
|
||||
template: "serterm/serial-terminal-server.container"
|
||||
dest: "/etc/containers/systemd/serial-terminal-server.container"
|
||||
hooks: {
|
||||
changed: [
|
||||
{run: "systemctl daemon-reload", immediate: true},
|
||||
{run: "systemctl restart serial-terminal-server"},
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
template: "serterm/serial-terminal-server-window@.service"
|
||||
dest: "/etc/systemd/system/serial-terminal-server-window@.service"
|
||||
hooks: {
|
||||
changed: [
|
||||
{run: "systemctl daemon-reload", immediate: true},
|
||||
]
|
||||
}
|
||||
},
|
||||
]
|
|
@ -0,0 +1,10 @@
|
|||
package prod
|
||||
|
||||
import "du5t1n.me/cfg/app/serterm/schema"
|
||||
|
||||
serterm: schema.#SerTerm
|
||||
|
||||
serterm: ssh: authorized_keys: [
|
||||
"sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAINZCN2cxMDwedJ1Ke23Z3CZRcOYjqW8fFqsooRus7RK0AAAABHNzaDo= dustin@rosalina.pyrocufflink.blue",
|
||||
"sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIAB6xTCSNz+AcQCWcyVKs84tThXN4wpLgCo2Lc48L6EsAAAABHNzaDo= dustin@luma.pyrocufflink.blue",
|
||||
]
|
|
@ -8,3 +8,5 @@ ssh: prod.ssh
|
|||
sudo: prod.sudo
|
||||
|
||||
promtail: prod.#promtail
|
||||
|
||||
serterm: prod.serterm
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"du5t1n.me/cfg/app/collectd"
|
||||
"du5t1n.me/cfg/app/promtail"
|
||||
"du5t1n.me/cfg/app/serterm"
|
||||
"du5t1n.me/cfg/env/prod"
|
||||
)
|
||||
|
||||
|
@ -12,4 +13,5 @@ render: list.Concat([
|
|||
prod.templates,
|
||||
collectd.templates,
|
||||
promtail.templates,
|
||||
serterm.templates,
|
||||
])
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# udev worker process does not have permissions/capabilities to run
|
||||
# `podman exec` directly, so a systemd unit is necessary
|
||||
ACTION=="add", SUBSYSTEM=="tty", SUBSYSTEMS=="usb-serial", TAG+="systemd", ENV{SYSTEMD_WANTS}+="serial-terminal-server-window@%k.service"
|
|
@ -0,0 +1,3 @@
|
|||
{% for key in serterm.ssh.authorized_keys -%}
|
||||
{{ key }}
|
||||
{% endfor -%}
|
|
@ -0,0 +1,7 @@
|
|||
[Unit]
|
||||
Description=Add serial terminal window for %I
|
||||
After=serial-terminal-server.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/podman exec serial-terminal-server add-window /dev/%I
|
|
@ -0,0 +1,30 @@
|
|||
[Unit]
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Container]
|
||||
ContainerName=serial-terminal-server
|
||||
Image=git.pyrocufflink.net/containerimages/serial-terminal-server
|
||||
Pull=newer
|
||||
ReadOnly=true
|
||||
VolatileTmp=true
|
||||
Volume=serial-logs:/var/log/serial:rw,z,U
|
||||
Volume=serial-ssh:/etc/ssh:rw,z,U
|
||||
Volume=/dev:/dev:rw
|
||||
Volume=/etc/serterm/authorized_keys:/run/serial/.ssh/authorized_keys:ro,z,U
|
||||
PublishPort=20022:20022
|
||||
RunInit=true
|
||||
# SELinux does not allow container_t access to devpts_t (for tmux)
|
||||
SecurityLabelDisable=true
|
||||
PodmanArgs=--device-cgroup-rule='c 188:* rw'
|
||||
# This must be the GID of the "dialout" group on the host
|
||||
# Using the group name would resolve the GID inside the container,
|
||||
# which would not give the correct permissions.
|
||||
PodmanArgs=--group-add=18
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
RestartSec=2s
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
Loading…
Reference in New Issue