Skip to content

Commit eab1085

Browse files
committed
ops/service: systemd-ssh-generator
Introducing vsock -- lots of LLMs get hallucination about this :-)
1 parent 51816f7 commit eab1085

3 files changed

Lines changed: 72 additions & 0 deletions

File tree

docs/dev/ssh.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,15 @@ sftp -P 2233 username@remotehost
419419

420420
sshd 接受 SIGHUP 信号作为重新载入配置文件的方式。`sshd -t` 命令可以检查配置文件的语法是否正确,这也是大多数发行版提供的 `ssh.service` 中指定的 `ExecStartPre=` 命令和第一条 `ExecReload=` 命令,即在尝试启动和重新加载服务前先检查配置文件的语法。
421421

422+
!!! note "systemd 与 sshd"
423+
424+
在使用 systemd 的较新的系统下,服务端可能会有以下变化:
425+
426+
- 默认使用 `ssh.socket` 而不是 `ssh.service` 对外提供服务。
427+
- `systemd-ssh-generator` 会在 Unix socket 和 vsock 上开启额外的端口。
428+
429+
其中的一些设置可能会以非预期的方式影响系统的安全性,阅读[服务与日志管理](../ops/service.md#socket)的相关内容以了解更多相关信息。
430+
422431
### authorized_keys 文件 {#authorized-keys}
423432

424433
`~/.ssh/authorized_keys` 文件是 SSH 服务端用于验证客户端公钥的文件,每行一个公钥,空行或者以 `#` 开头的行会被当作注释忽略。

docs/ops/service.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,30 @@ WantedBy=multi-user.target
118118

119119
对于定时器,`[Timer]` 部分的字段可以在 [`systemd.timer(5)`][systemd.timer.5] 中找到。
120120

121+
!!! note "Generator"
122+
123+
或许你会注意到,有一些 unit 文件存储在 `/run/systemd/generator/` 下:
124+
125+
```console
126+
$ systemctl status home.mount
127+
● home.mount - /home
128+
Loaded: loaded (/etc/fstab; generated)
129+
Active: active (mounted) since Mon 2026-04-06 09:27:46 UTC; 1 day 8h ago
130+
Invocation: 513aed29e7f049babe06455dbbc90087
131+
Where: /home
132+
What: /dev/vda1
133+
Docs: man:fstab(5)
134+
man:systemd-fstab-generator(8)
135+
Tasks: 0 (limit: 2318)
136+
Memory: 84K (peak: 1.7M)
137+
CPU: 4ms
138+
CGroup: /system.slice/home.mount
139+
$ ls /run/systemd/generator/home.mount
140+
/run/systemd/generator/home.mount
141+
```
142+
143+
这些临时生成出来的 unit 是由 [systemd.generator.5][systemd.generator.5] 生成的。Generator 程序(大部分都在 `/usr/lib/systemd/system-generators/`)会在系统启动最开始,以及重新加载配置的时候执行,生成对应的 unit。
144+
121145
#### 顺序与依赖 {#unit-dependency}
122146

123147
相比于 SysVinit(完全顺序启动)和 upstart(基于 event 触发的方式有限的并行),systemd 的每个 unit 都明确指定了依赖关系,分析依赖关系后 systemd 就可以最大化并行启动服务,这样可以大大缩短启动时间。
@@ -339,6 +363,8 @@ notify 和 dbus
339363

340364
Socket activation 帮助实现了服务的惰性加载,可以在不必要的情况下减小资源占用,并且提升系统启动速度。例如对 Docker,`docker.service` 如果 enable,它可能会在系统启动的关键路径上面占用几秒的时间,而如果不 enable `docker.service`,改为 enable `docker.socket`,那么就能够减小启动时间,让对应服务延迟到首次使用时开启。同时,socket activation 机制允许 systemd 预先绑定低权限用户无法绑定的低端口(小于 1024),然后在有用户访问时把 socket 交给低权限的服务进程。
341365

366+
当然,对 SSH,如果你想继续使用 `ssh.socket` 并且修改端口的话,就需要 `systemctl edit ssh.socket`,而不是编辑 sshd 配置了。
367+
342368
!!! note "应用是如何获取到自己的 socket 的?"
343369

344370
Systemd 提供了两种方法:应用可以用 libsystemd 的 [sd_listen_fds(3)][sd_listen_fds.3] 函数获取到 socket 对应的文件描述符,然后直接 `accept` 或者 `recv`(根据 `Accept` 选项的不同)。
@@ -353,6 +379,40 @@ Socket activation 帮助实现了服务的惰性加载,可以在不必要的
353379

354380
如果无法切换到 `Accept=no`,那么可能需要增大最大连接数,或者利用 [fail2ban](./security.md#public-service-and-login) 与[防火墙](./network/firewall.md)等方式来阻止恶意的扫描影响正常服务。
355381

382+
!!! note "systemd-ssh-generator"
383+
384+
可能出乎人意料的是,systemd 默认除了对外的 TCP 22 端口以外,还会额外 bind:
385+
386+
- `/run/ssh-unix-local/socket`
387+
- 如果是容器里面的 systemd,且 `/run/host/unix-export/` 可以写入,那么会 bind `/run/host/unix-export/ssh`,用来让 host 能 ssh 进入容器。
388+
- 如果是虚拟机,会在 `AF_VSOCK` 的 22 端口也 bind 一份。`AF_VSOCK` 是一种 VM 与 host 交互的特殊 socket,相比传统的 `IP:port`,vsock 使用 `CID:port`,其中 CID 是虚拟机管理器设置的上下文 ID,对虚拟机一般从 3 开始。
389+
390+
这些操作是 [systemd-ssh-generator.8][systemd-ssh-generator.8] 完成的。相关的引入原因可以参考 [Lennart Poettering 的 mastodon](https://mastodon.social/@pid_eins/112411218075942131)。
391+
392+
需要特别注意的是,**[命名空间机制](./virtualization/container.md#namespace)在 Linux 的 7.0 内核之前,无法隔离 `AF_VSOCK`**。这也就意味着,如果没有设置其他的保护措施,所有虚拟机里开启的容器都可以访问到虚拟机的 SSH,同时因为有虚拟机的主机上也有 vsock 的另一端,因此主机里的容器也可以访问虚拟机的 SSH。如果虚拟机上的用户采用了弱密码,并且 SSH 允许密码登录(或者其他脆弱的场景下),恶意程序就可能会从虚拟机或者主机里的容器逃逸到虚拟机中。不过好消息是,不少容器运行时都使用 seccomp 阻止了容器内部对 vsock 的访问(例如 [moby](https://github.com/moby/moby/pull/44562))。
393+
394+
可以使用以下命令检查机器上有没有在 vsock 上监听的服务:
395+
396+
```console
397+
$ ss --vsock --all
398+
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
399+
v_str LISTEN 0 0 *:22 *:*
400+
```
401+
402+
不过从另一方面来说,这也给管理虚拟机带来了方便。Systemd 提供了 [systemd-ssh-proxy.1][systemd-ssh-proxy.1] 工具,用来作为 [`ProxyCommand`](../dev/ssh.md#proxy) 方便连接由 Unix socket 和 `AF_VSOCK` 暴露的 SSH 服务。Debian 的 `systemd` 包会写入 `/etc/ssh/ssh_config.d/20-systemd-ssh-proxy.conf`,允许直接使用 `.host` 或 `machine/.host` 连接到本机的 SSH,使用 `unix/*`、`vsock/*`、`machine/*` 连接到 Unix socket、`AF_VSOCK` 和使用 systemd-machined(systemd 的虚拟机和容器管理器)管理的虚拟机。于是可以这样连接到启用了 vsock 功能的虚拟机上:
403+
404+
```shell
405+
# 可以 open /dev/vsock 后使用 ioctl IOCTL_VM_SOCKETS_GET_LOCAL_CID 获取虚拟机自己的 CID
406+
# 详情可阅读手册 vsock.7
407+
ssh user@vsock/3
408+
```
409+
410+
当然也可以用 `socat` 来做:
411+
412+
```shell
413+
ssh -o ProxyCommand="socat - VSOCK-CONNECT:3:22" taoky@anythingyoulike
414+
```
415+
356416
### 定时任务 {#timers}
357417

358418
Systemd 提供了 timer 类型的 unit,用于定时执行任务。一个 timer unit 通常会对应一个 service unit,即在指定的时间点或者时间间隔触发 service 的启动。

includes/man.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
[scrun.1]: https://slurm.schedmd.com/scrun.html
1919
[ssh-keygen.1]: https://man7.org/linux/man-pages/man1/ssh-keygen.1.html
2020
[systemd-run.1]: https://www.freedesktop.org/software/systemd/man/latest/systemd-run.html
21+
[systemd-ssh-proxy.1]: https://www.freedesktop.org/software/systemd/man/latest/systemd-ssh-proxy.html
2122
[tigervncserver.1]: https://manpages.debian.org/unstable/tigervnc-standalone-server/tigervncserver.1.en.html
2223
[vncconfig.1]: https://linux.die.net/man/1/vncconfig
2324
[xserver.1]: https://linux.die.net/man/1/xserver
@@ -68,6 +69,7 @@
6869
[systemd.exec.5]: https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html
6970
[systemd.exec.5#Environment]: https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#Environment
7071
[systemd.exec.5#Sandboxing]: https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#Sandboxing
72+
[systemd.generator.5]: https://www.freedesktop.org/software/systemd/man/latest/systemd.generator
7173
[systemd.kill.5]: https://www.freedesktop.org/software/systemd/man/latest/systemd.kill.html
7274
[systemd.resource-control.5]: https://www.freedesktop.org/software/systemd/man/latest/systemd.resource-control.html
7375
[systemd.service.5]: https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html
@@ -114,6 +116,7 @@ Do not link to a "generic" man page for these commands -->
114116
[slurmrestd.8]: https://slurm.schedmd.com/slurmrestd.html
115117
<!-- end slurm daemons -->
116118
[systemd-logind.8]: https://www.freedesktop.org/software/systemd/man/latest/systemd-logind.html
119+
[systemd-ssh-generator.8]: https://www.freedesktop.org/software/systemd/man/latest/systemd-ssh-generator.html
117120
[useradd.8]: https://manpages.debian.org/stable/passwd/useradd.8.en.html
118121
[userdel.8]: https://manpages.debian.org/stable/passwd/userdel.8.en.html
119122
[xfs_growfs.8]: https://linux.die.net/man/8/xfs_growfs

0 commit comments

Comments
 (0)