Ubuntu 22.04 ARM64 云镜像开启 root 密钥登录(保留 ubuntu 密钥登录,禁止密码登录)

原文出处:实操踩坑记录・适用 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 密钥认证本身是成功的,但登录后立即被强制退出

三、核心排查思路

先讲结论,避免大家走弯路。整件事分成两个层面:

  1. sshd 服务层:是否允许 root 登录、是否允许密钥认证 ------ 通过配置文件控制
  2. 公钥层(关键坑点) :/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:验证

  1. 确认 root 公钥文件已经只剩纯净公钥行:

    bash 复制代码
    cat /root/.ssh/authorized_keys
  2. 新开一个 MobaXterm 窗口测试 root 密钥登录:

    bash 复制代码
    ssh root@你的实例IP
  3. 再测试 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 镜像上的表现差异。

相关推荐
ly76891 小时前
性能剖析与压测方法论:JMH、async-profiler 与分层瓶颈定位的可复现实验
服务器·前端·数据库·压测·jmh·性能剖析·async-profiler
OxYGC1 小时前
[工程] Redis 配置文件redis.conf全解析
数据库·redis·bootstrap
YuanDaima20481 小时前
系统架构与数据库理论基础:PostgreSQL 与 pgvector
数据库·人工智能·docker·postgresql·系统架构·产品经理
skywalk81631 小时前
FreeBSD仿真环境里的Ubuntu linux系统,安装软件的时候不支持snap怎么办?
linux·运维·ubuntu·系统·freebsd
2601_957084844 小时前
2026年生产型服装供应链SCM系统丨水洗参数、产能与验收节点架构
数据库·scm·服装供应链系统·服装scm·服装供应链
IvorySQL10 小时前
PostgreSQL 日报|恢复期 COPY TO 未日志表修复(10 月 21 日)
数据库·postgresql·区块链
贝猫说python11 小时前
大模型比赛2.3智能体开发(工具调用智能问答助手)
数据库·oracle
Cry丶11 小时前
ubuntu安装vsftpd
服务器·网络·ubuntu
许彰午12 小时前
28-ORA-01110数据文件读取错误
数据库·oracle