原文出处:实操踩坑记录・适用 Ubuntu 22.04 ARM64 云镜像(cloud-init 初始化的各家云厂商镜像通用)
难度:★★☆ | 全程 root 下执行,操作前请保留当前 SSH 会话,防止锁死
一、问题背景与现象
云厂商的 Ubuntu 22.04 ARM64 镜像(cloud-init 初始化的镜像)默认只允许 ubuntu 用户密钥登录,root 无法直接登录。我们期望的效果是:
| 用户 | 期望行为 |
|---|---|
ubuntu |
保持原有密钥登录,不受影响 |
root |
允许密钥登录 |
| 所有用户 | 禁止密码登录 |
当直接用 root 连接时,会看到这样的提示并断开:
Please login as the user "ubuntu" rather than the user "root".
很多人以为是 sshd 配置没改,实际上这是一个隐蔽的云镜像坑点,真正的元凶在公钥文件里(下文详述)。
二、环境信息
- 系统:Ubuntu 22.04 ARM64(cloud-init 云镜像)
- SSH 客户端:MobaXterm v26.2
- 现象:root 密钥认证本身是成功的,但登录后立即被强制退出
三、核心排查思路
先讲结论,避免大家走弯路。整件事分成两个层面:
- sshd 服务层:是否允许 root 登录、是否允许密钥认证 ------ 通过配置文件控制
- 公钥层(关键坑点) :
/root/.ssh/authorized_keys里存在一行带command="..."前缀的公钥 ------ 即使 sshd 放行,这条命令也会在你认证成功后把提示打出来然后退出
很多人卡住,就是因为只改了 sshd 配置,却忽略了公钥里那行 command 拦截。
四、操作步骤
全程 root 执行,一条一条来,不要一次性粘贴多行(避免 shell 串行解析混乱)。
步骤 1:创建 SSH 附加配置文件,放开 root 仅密钥登录
Ubuntu 的 sshd_config 会按字典序加载 /etc/ssh/sshd_config.d/*.conf,数字大的优先级高。我们用 99-root-key.conf 覆盖默认行为:
bash
cat > /etc/ssh/sshd_config.d/99-root-key.conf <<'EOF'
PermitRootLogin prohibit-password
PubkeyAuthentication yes
PasswordAuthentication no
EOF
配置说明:
| 配置项 | 作用 |
|---|---|
PermitRootLogin prohibit-password |
允许 root 登录,但仅限密钥,拒绝密码 |
PubkeyAuthentication yes |
开启公钥认证 |
PasswordAuthentication no |
全局关闭所有用户的 SSH 密码登录 |
prohibit-password与without-password等价,只是写法更语义化,推荐使用。
步骤 2:创建 root 的 .ssh 目录并设置严格权限
权限不对会直接导致登录失败(OpenSSH 校验非常严格):
bash
mkdir -p /root/.ssh
chmod 700 /root/.ssh
touch /root/.ssh/authorized_keys
步骤 3:复用 ubuntu 用户的公钥,写入 root 授权文件
bash
cat /home/ubuntu/.ssh/authorized_keys >> /root/.ssh/authorized_keys
这一步执行后,
authorized_keys里通常会有多行公钥,其中可能包含 cloud-init 写入的带command=前缀的拦截行。下一步统一清理。
步骤 4:清理所有带 command 前缀的拦截行(⚠️ 核心坑点)
先查看当前文件结构,确认有哪些行:
bash
cat /root/.ssh/authorized_keys
cloud-init 注入的拦截行长这样(元凶):
no-port-forwarding,no-agent-forwarding,no-X11-forwarding,command="echo 'Please login as the user \"ubuntu\" rather than the user \"root\".';echo;sleep 10;exit 142" ssh-rsa AAAA...你的公钥
它利用 OpenSSH 公钥的 command="..." 特性:只要用这行公钥登录 root,就强制执行引号里的命令并退出,根本不会进入 shell。
处理原则:删除所有带 command= 前缀的行,保留所有纯净公钥行。 不要用 sed -n '2p' 这种"取第二行"的写法------如果文件只有一行拦截行、没有第二行,会得到空文件,直接锁死 root。
正确的清理命令(删除所有含 command= 的行,对任意行数都安全):
bash
sed -i '/command="/d' /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys
执行后再次确认:
bash
cat /root/.ssh/authorized_keys
期望输出:只剩下以 ssh-rsa / ssh-ed25519 开头、前面没有 command= 前缀的纯净公钥行。
步骤 5:校验配置语法并重启 ssh 服务
bash
sshd -t && systemctl restart ssh
sshd -t先做语法检查,只有通过才执行systemctl restart ssh,不会因错误配置导致服务崩溃,当前已连接会话不会中断。
步骤 6:验证
-
确认 root 公钥文件已经只剩纯净公钥行:
bashcat /root/.ssh/authorized_keys -
新开一个 MobaXterm 窗口测试 root 密钥登录:
bashssh root@你的实例IP -
再测试 ubuntu 用户密钥登录,确认原有登录未被破坏。
五、验证的实际输出
配置生效后,用 sshd -T 可以确认当前 root 的实际策略:
bash
sshd -T | grep -i permitrootlogin
# 输出:
# permitrootlogin without-password
without-password(即 prohibit-password)表示 root 已允许密钥登录、禁止密码登录,配置正确生效。
六、一键脚本版(完整流程)
bash
# 1. 写 SSH 配置
cat > /etc/ssh/sshd_config.d/99-root-key.conf <<'EOF'
PermitRootLogin prohibit-password
PubkeyAuthentication yes
PasswordAuthentication no
EOF
# 2. 创建目录 + 权限
mkdir -p /root/.ssh
chmod 700 /root/.ssh
touch /root/.ssh/authorized_keys
# 3. 复用 ubuntu 公钥
cat /home/ubuntu/.ssh/authorized_keys >> /root/.ssh/authorized_keys
# 4. 删除所有 command 拦截行,只保留纯净公钥
sed -i '/command="/d' /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys
# 5. 校验 + 重启
sshd -t && systemctl restart ssh
脚本用
/command="/d删除所有含command=前缀的行,不会清空文件,比"取第二行"的方式安全得多。
七、回滚方案
如果配置后出现登录异常,请在仍保持连接的 root 会话 中执行以下命令恢复到可登录的状态:
bash
# 1. 删除新增的 SSH 配置文件(恢复 sshd 默认策略)
rm -f /etc/ssh/sshd_config.d/99-root-key.conf
# 2. 确保 authorized_keys 只保留纯净公钥行(删除 command 拦截行)
sed -i '/command="/d' /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys
# 3. 校验并重启
sshd -t && systemctl restart ssh
注意:不要把带
command=的拦截行恢复回去 ------那正是导致 root 无法登录的原因。回滚的目标是"让 root 能正常密钥登录",所以保持authorized_keys纯净即可。
八、常见问题 FAQ
Q1:为什么改了 sshd 配置还是提示 "Please login as the user ubuntu..."?
A:因为拦截在公钥层 ,不在 sshd 配置层。是 /root/.ssh/authorized_keys 里带 command="..." 前缀的那行公钥强制拦截。按步骤 4 清理即可。
Q2:permitrootlogin without-password 和 prohibit-password 有区别吗?
A:没有,二者等价,是同一个值的两种写法。prohibit-password 更语义化,推荐。
Q3:会不会把系统搞挂 / 锁死?
A:只要(1)用独立的 sshd_config.d 文件而不动主配置;(2)sshd -t 校验通过再重启;(3)不关闭当前会话、新开窗口测试 ------ 几乎不会锁死。出问题用回滚方案即可。
Q4:我只想禁止 root 密码登录,普通用户还能密码登录,怎么配?
A:去掉配置文件里的 PasswordAuthentication no 这一行,保留:
PermitRootLogin prohibit-password
PubkeyAuthentication yes
九、总结
| 关键点 | 说明 |
|---|---|
| sshd 配置 | 用 sshd_config.d/99-root-key.conf 附加文件,PermitRootLogin prohibit-password 放行 root 密钥登录 |
| 密码登录 | PasswordAuthentication no 全局关闭 |
| 最大的坑 | authorized_keys 里的 command="..." 拦截行,需统一删除,只留纯净公钥 |
| 安全兜底 | 保留当前会话、sshd -t 校验、新开窗口测试、准备好回滚命令 |
云镜像默认把 root 登录"锁"起来是安全的默认策略,如果你确实需要 root 直连,务必坚持仅密钥登录、禁止密码登录 ,不要把 PermitRootLogin 改成 yes(那会同时开放密码登录,公网环境风险极高)。
本文为实操踩坑记录,如对你有帮助欢迎点赞收藏,也欢迎在评论区交流你在其他云厂商 Ubuntu 镜像上的表现差异。