AI Infra 训练营
总览
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
HiHuo 主站
GitHub
总览
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
HiHuo 主站
GitHub

sshd —— SSH 服务端守护进程与硬化

一句话定义

sshd 是 OpenSSH 的服务端守护进程,监听端口(默认 22)、接受客户端连接、做认证、建立加密会话。本地用 ssh 是客户端,对端机器上必须有 sshd 在跑才能接你。

典型场景

  • Day0 装机:新机器有默认 sshd 但默认禁了公钥认证(IDC 模板"特色"),要改 sshd_config 并 reload
  • Day0 §2.3:key 验证可用后,关掉密码登录、关掉 root 密码、关掉 keyboard-interactive
  • 每次改完 sshd 配置:sshd -t 必跑,否则把自己锁外面
  • 排错"为什么 key 都对了还是连不上":90% 是远端 sshd 配置问题

守护进程的基本管理

启停 / 状态

systemctl status sshd          # CentOS / RHEL / Ubuntu 22+ 推荐
systemctl status ssh           # Debian / 老版 Ubuntu 可能叫 ssh

systemctl restart sshd         # 重启(断开所有现有连接 —— 危险)
systemctl reload sshd          # 重读配置不断连接(推荐用这个)
systemctl enable sshd          # 开机自启

服务名是 sshd 还是 ssh:Ubuntu 22.04+ 是 sshd,老 Debian 是 ssh。不确定就 systemctl list-unit-files | grep -i ssh 看一下。

看监听状态

ss -lntp | grep sshd
# LISTEN 0  128  0.0.0.0:22  0.0.0.0:*  users:(("sshd",pid=1234,fd=3))
# LISTEN 0  128  [::]:22     [::]:*     users:(("sshd",pid=1234,fd=4))

注意:sshd 同时监听 IPv4 (0.0.0.0:22) 和 IPv6 ([::]:22),这是默认行为。


配置文件结构

OpenSSH 服务端配置在 两个位置:

/etc/ssh/sshd_config                 ← 主配置(包级别)
/etc/ssh/sshd_config.d/*.conf        ← 分片 override(Ubuntu 22+ 引入)

sshd_config.d/*.conf 的 override 机制(重点)

主文件 sshd_config 末尾通常有:

Include /etc/ssh/sshd_config.d/*.conf

OpenSSH 读完主文件后,把 sshd_config.d/ 下所有 .conf 文件按字母序追加到配置流里。然后按"先到先得"原则生效。

陷阱:

# 你改了主配置
vim /etc/ssh/sshd_config
# 把 PasswordAuthentication 改成 no
systemctl reload sshd

# 但密码登录依然能用,什么鬼?
sshd -T | grep -i password
# passwordauthentication yes    ← 还是 yes!

原因:/etc/ssh/sshd_config.d/50-cloud-init.conf 这种文件里写了 PasswordAuthentication yes,override 了你的修改。

很多 IDC 的 Ubuntu 模板都会自动生成这种 cloud-init / vendor 的分片配置,你看主文件以为改成功了,实际不生效。

正确改法

两边都要改:

# 1. 改主配置
sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config

# 2. 同时改所有分片
for f in /etc/ssh/sshd_config.d/*.conf; do
  [ -f "$f" ] && grep -q PasswordAuthentication "$f" && \
    sed -i 's/^PasswordAuthentication.*/PasswordAuthentication no/' "$f"
done

# 3. 验语法
sshd -t

# 4. reload
systemctl reload sshd

用 sshd -T 看实际生效的配置

这是排查 sshd 问题的第一个该跑的命令。

sshd -T | grep -i pubkey
# pubkeyauthentication yes

sshd -T | grep -i password
# passwordauthentication no

sshd -T | grep -i permitrootlogin
# permitrootlogin prohibit-password

sshd -T 模拟启动一次、把所有最终生效的配置(包括 Include 文件、Match 块、默认值)合并打印出来。不需要重启就能看实际生效情况。

别去 grep 配置文件!文件里可能写了 #PubkeyAuthentication yes(被注释)、可能在 sshd_config.d 里被 override、可能 OpenSSH 默认值就是你想要的(根本不用配)。sshd -T 是唯一可靠的事实来源。


用 sshd -t 验证配置语法

sshd -t
echo $?     # 0 表示语法正确

改完 sshd_config 一定先跑 sshd -t,再 reload。否则配错一个字,reload 之后 sshd 启动失败、SSH 服务彻底没了、现有连接断了你也连不回来 —— 物理 console 救援都未必有。

良好习惯:

sshd -t && systemctl reload sshd

&& 让 reload 只在 sshd -t 通过时才执行。


关键字段速查

字段默认训练营推荐说明
Port2222 / 改非默认改非默认端口能减少 90% 的暴力扫描,但不是安全的根本对策
ListenAddress0.0.0.0 ::默认只想监听内网网卡时指定 IP
Protocol22OpenSSH 7 已废 Protocol 1,不用管
PermitRootLoginprohibit-passwordprohibit-password允许 root 用 key 登录,但禁止密码
PasswordAuthenticationyesno(key 验通后)防止暴力破解
KbdInteractiveAuthenticationyesno(key 验通后)同上,挡 PAM 那条路
PubkeyAuthenticationyesyes允许公钥登录
AuthorizedKeysFile.ssh/authorized_keys默认公钥存放路径
MaxAuthTries63失败次数上限,调小挡爆破
MaxSessions1010单个 ssh 连接里能开几个 session
ClientAliveInterval060多久没消息就发探测包(防 idle 断流,也防长挂连接耗资源)
ClientAliveCountMax33探测失败几次后断
AllowUsers / AllowGroups不限视情况白名单
DenyUsers / DenyGroups不限视情况黑名单
X11Forwardingyes (Ubuntu)no不用就关
AllowTcpForwardingyesyesK8s port-forward / 跳板必需
GatewayPortsnono是否允许 -R 转发监听 0.0.0.0

训练营硬化套餐(Day0 §2.3)

ssh root@$ip "
  sed -i \
    -e 's/^#*PasswordAuthentication.*/PasswordAuthentication no/' \
    -e 's/^#*PermitRootLogin.*/PermitRootLogin prohibit-password/' \
    -e 's/^#*KbdInteractiveAuthentication.*/KbdInteractiveAuthentication no/' \
    -e 's/^#*PubkeyAuthentication.*/PubkeyAuthentication yes/' \
    /etc/ssh/sshd_config

  for f in /etc/ssh/sshd_config.d/*.conf; do
    [ -f \"\$f\" ] && sed -i \
      -e 's/^PasswordAuthentication.*/PasswordAuthentication no/' \
      -e 's/^PubkeyAuthentication.*/PubkeyAuthentication yes/' \"\$f\"
  done

  sshd -t && systemctl reload sshd
"

为什么这套组合:

改动防住什么
PasswordAuthentication no全网爆破密码(每天几千次自动扫描)
KbdInteractiveAuthentication noPAM 的"另一条密码路"(不少教程只关了 PasswordAuthentication,结果 KbdInteractive 是个后门)
PermitRootLogin prohibit-passwordroot 用密码登录(用 key 登可以 —— 适合自动化)
PubkeyAuthentication yes反过来确保 key 认证是开的(很多 IDC 默认关)

更严格的话 PermitRootLogin no —— 彻底禁 root 直接登,强制走普通用户 + sudo。但训练营场景多是单人玩、用 root 直接干活更省事,prohibit-password 已经够。


「PubkeyAuthentication no」这个真实踩坑

某些 IDC(特别是国内小厂)的 Ubuntu 模板,默认禁了 PubkeyAuthentication,只让密码登录(方便他们 console 重置密码)。

症状:

  • 公钥已经写进 ~/.ssh/authorized_keys
  • 权限都对(700 / 600)
  • ssh -v 显示 key 正常 offer
  • 远端依然 Permission denied (publickey)

排查(先连上去 —— 还能用密码登):

ssh root@$ip 'sshd -T | grep -i pubkey'
# pubkeyauthentication no    ← 根因

修复:

sed -i 's/^#*PubkeyAuthentication.*/PubkeyAuthentication yes/' /etc/ssh/sshd_config
for f in /etc/ssh/sshd_config.d/*.conf; do
  [ -f "$f" ] && grep -q PubkeyAuthentication "$f" && \
    sed -i 's/^PubkeyAuthentication.*/PubkeyAuthentication yes/' "$f"
done
sshd -t && systemctl reload sshd

教训:任何时候 sshd 表现不符合预期,第一时间 sshd -T 看实际生效,不要去 cat 配置文件猜。


reload vs restart 的区别

操作影响用途
reload sshd重读配置,不断现有连接改配置后用这个(90% 场景)
restart sshd重启进程,所有现有连接断开sshd 进程本身卡死、或者需要清空状态

注意:reload 不是万能的 —— 有些选项(监听端口、密码学算法选择)改了之后只有 restart 才生效。

但 restart 之前要确认:

  1. 新配置 sshd -t 通过
  2. 你还有备用入口(物理 console、其它登录方式),万一 restart 之后启不起来能救

临时改端口、不影响现有登录

改了 Port 22 → Port 2222 之后:

sshd -t && systemctl restart sshd      # 必须 restart,reload 不会切端口

但是!restart 会断现有连接。安全做法:

# 在 sshd_config 里同时监听两个端口
Port 22
Port 2222

# restart 之后两个端口都通;新连接走 2222;老连接(22)继续;测试 2222 没问题之后再去掉 22 行

看实时连接 / 看日志

# 当前活跃的 ssh 会话
who                                # 谁登着
ss -tnp | grep :22                 # 端口 22 上的 established 连接

# sshd 日志(systemd-journald)
journalctl -u sshd -n 50           # 最近 50 行
journalctl -u sshd -f              # 跟随
journalctl -u sshd --since "10 min ago"

# 老式系统的话
tail -f /var/log/auth.log          # Debian/Ubuntu
tail -f /var/log/secure            # CentOS/RHEL

排查爆破:

journalctl -u sshd --since today | grep -i 'failed\|invalid'

进阶:Match 块(按条件应用不同配置)

# /etc/ssh/sshd_config

PasswordAuthentication no              # 全局禁密码

Match User backup
  PasswordAuthentication yes           # 但 backup 这个用户可以用密码(备份脚本用)
  ForceCommand /usr/local/bin/backup-only   # 而且强制只能跑这个命令

Match 让你按 user / group / host / address 等条件应用不同的配置。生产环境常用,训练营场景用不太到,知道有就行。


常见踩坑

坑 1:reload 之后配置没生效

90% 是 sshd_config.d/*.conf 里有 override。永远用 sshd -T 看实际生效,不要 grep 配置文件。

坑 2:把自己锁外面

改完配置 systemctl restart sshd 启动失败 → 现有 ssh 连接断 → 新连接也建不起来。

防御:

  1. 改配置前先开第二个 ssh 会话(windowed terminal 第二个 tab),保持登录,作为"救命通道"
  2. 必跑 sshd -t,语法对了再 reload/restart
  3. 用 reload 而不是 restart(reload 不断连接)
  4. 改完之后保留当前连接,开第三个 ssh 测试 —— 测通了再 logout 当前连接

坑 3:私钥/公钥都对,还是 Permission denied

可能性(从高到低):

  1. 远端 sshd 禁了 pubkey 认证(sshd -T | grep -i pubkey)
  2. 远端 ~/.ssh/authorized_keys 权限不对(必须 600 或 644)
  3. 远端 ~/.ssh 目录权限不对(必须 700)
  4. 远端用户的 home 目录权限不对(必须 755 或更严,不能是 777)—— OpenSSH 出于安全会拒
  5. SELinux 拒(getenforce 看;临时 setenforce 0 测试)
  6. AllowUsers / DenyUsers 规则把你过滤了
  7. authorized_keys 里的公钥是错的(不是当前 IdentityFile 对应的公钥)

排查命令组合:

ssh -v m1 2>&1 | grep -i 'offering\|accepted\|refused'
ssh m1 'sshd -T | grep -iE "pubkey|allowusers|denyusers"'   # 当然得先能登上去

坑 4:端口已经被占用,启动失败

Address already in use

通常是上一个 sshd 进程没退干净,或者有别的服务占了 22。

ss -lntp | grep :22         # 看谁占着
systemctl stop sshd
ss -lntp | grep :22         # 确认彻底停了
systemctl start sshd

坑 5:以为改了 sshd_config 立即生效

vim /etc/ssh/sshd_config       # 改完保存
# 然后什么也不做,等着新登录用新配置 —— 不会生效

必须 systemctl reload sshd(或 restart)才生效。OpenSSH 不会 watch 配置文件变化。

坑 6:用 SCP/SFTP 传文件出错

sftp> ls
Received message too long ...

通常是远端 /etc/profile 或 ~/.bashrc 里有 echo/printf 之类的输出,污染了 sftp 通道。

修复:把 ~/.bashrc 里 "只对交互 shell 有意义" 的输出包在条件里:

if [[ $- == *i* ]]; then
  echo "Welcome back"
fi

或者用 [[ -n "$PS1" ]] 判断。


关联命令

  • ssh —— 客户端
  • ssh-keygen —— 远端 host key 也是这个生成(ssh-keygen -A 重生成)
  • ssh-config —— 客户端配置
  • systemctl —— 启停 sshd 服务
  • journalctl —— 看 sshd 日志
在 GitHub 上编辑此页