2026 年维护说明:
Permission denied (publickey)是认证结果,不是根因诊断。本手册从只读取证开始,区分客户端、网络和服务器端原因,并在离线磁盘修复前优先使用 AWS 支持的恢复路径。仅可用于你获授权管理的实例。
Table of Contents
安全边界与恢复门槛
- 变更前记录实例 ID、区域、可用区、AMI ID、预期系统用户、密钥对名称、当前地址、根卷 ID、块设备映射、加密/KMS 状态和
DeleteOnTermination值。 - 建立维护窗口并确定回滚负责人。任何离线写入前都要为 EBS 根卷创建快照;只有弄清恢复路径和 KMS 访问权限后,快照才算可用备份。
- 不要把私钥、口令、完整
authorized_keys、会话令牌或未经脱敏的ssh -vvv日志粘贴到工单或聊天中。不要关闭主机密钥校验。 - 每次只做一个边界明确的改动,用第二个 SSH 会话验证,并在无需回滚前保持恢复通道开启。
- 如果目标实例、账户、区域、卷、文件系统、预期用户、密钥指纹或 KMS 权限存在疑问,立即停止。
这条错误能证明什么,不能证明什么
Permission denied (publickey) 通常表示 TCP 已连接到 SSH 服务,但服务端没有为该用户接受客户端提供的任何公钥。超时、DNS 失败、Connection refused、主机密钥验证失败或 EC2 状态检查失败属于其他分支。在分支明确前,不要轮换密钥或编辑服务器文件。
先在不接触秘密的情况下记录 AWS 端身份:
aws ec2 describe-instances
--instance-ids i-REPLACE_WITH_INSTANCE_ID
--query 'Reservations[0].Instances[0].{State:State.Name,ImageId:ImageId,KeyName:KeyName,AZ:Placement.AvailabilityZone,PublicIp:PublicIpAddress,PrivateIp:PrivateIpAddress,SubnetId:SubnetId,VpcId:VpcId,SecurityGroups:SecurityGroups[*].GroupId,RootDevice:RootDeviceName}'
--output yaml
EC2 KeyName 只记录启动时选择的密钥,不能证明当前 authorized_keys 未被更改。镜像、配置管理、user-data 脚本或管理员都可能在之后修改它。
1. 在改动 AWS 前核对客户端身份
官方 Ubuntu AMI 的初始用户通常是 ubuntu;其他 AMI 或后建账户可能不同。应核对 AMI 和预期账户,不要逐个猜用户名。确认 -i 指向私钥而不是 .pub 文件,并按 AWS 要求限制本地私钥权限:
chmod 400 /secure/path/to/private-key.pem
ssh-keygen -lf /secure/path/to/private-key.pem
ssh-keygen -y -f /secure/path/to/private-key.pem | ssh-keygen -lf -
最后一条命令只在内存中导出公钥部分并打印指纹,不会暴露私钥。通过已经可信的恢复通道,把该指纹与目标用户预期授权行的指纹比较:
sudo -u ubuntu ssh-keygen -lf /home/ubuntu/.ssh/authorized_keys
算法名称相同并不够,指纹必须与某一条授权记录完全匹配。AWS 密钥对的指纹算法因来源和算法而异;与 EC2 控制台比较时应使用 AWS 官方指纹流程。如果私钥已经丢失,EC2 不能再次下载它;应转入受支持的恢复路径,不要自行拼凑替代身份。
2. 核对服务器主机密钥
主机密钥用于验证服务器,与用于验证你的用户密钥不同。通过可信 AWS 控制平面获取实例指纹,并与 SSH 提示比较:
aws ec2 get-console-output
--instance-id i-REPLACE_WITH_INSTANCE_ID
--query Output
--output text
在系统日志中查找 BEGIN SSH HOST KEY FINGERPRINTS。控制台输出可能含主机名、地址、启动消息或 user-data 输出,共享前必须脱敏。如果主机密钥意外变化,应停止操作:确认 DNS/IP 仍指向该实例,并调查实例是否被替换或重建。不要通过关闭严格主机密钥检查或丢弃 known-hosts 记录来绕过警告。
3. 收集最小化详细日志
强制使用预期身份,避免 ssh-agent 中多个密钥掩盖结果:
ssh -vvv
-o IdentitiesOnly=yes
-i /secure/path/to/private-key.pem
ubuntu@REPLACE_WITH_VERIFIED_HOSTNAME
只在本地解读日志:
| 证据 | 可能分支 |
|---|---|
| 在 SSH 标识交换前无路由、超时或拒绝 | 地址、路由、安全组、NACL、本地/主机防火墙或 sshd 可用性 |
| 主机密钥不匹配 | 错误端点、重建主机、过期可信记录或潜在拦截;先核验再继续 |
| 从未提供预期密钥 | 错误的 -i、密钥不可读/不受支持、SSH 配置或 agent 选择 |
| 提供预期密钥但被拒绝 | 系统用户错误、授权密钥缺失/不匹配、所有权/模式、有效 sshd 策略或外部密钥命令 |
详细日志和指纹输出可能暴露用户名、本地路径、IP、主机和公钥指纹、密钥注释、代理命令与配置。请脱敏这些字段,绝不要包含私钥材料或口令。
4. 独立证明网络路径
先确认实例为 running,系统和实例状态检查都健康。然后检查真实路径,不要为了测试而放宽它:
aws ec2 describe-instance-status
--instance-ids i-REPLACE_WITH_INSTANCE_ID
--include-all-instances
aws ec2 describe-security-groups
--group-ids sg-REPLACE_WITH_GROUP_ID
aws ec2 describe-network-acls
--filters Name=association.subnet-id,Values=subnet-REPLACE_WITH_SUBNET_ID
aws ec2 describe-route-tables
--filters Name=association.subnet-id,Values=subnet-REPLACE_WITH_SUBNET_ID
检查目标地址、子网路由、互联网网关/NAT/VPN/堡垒机或 EC2 Instance Connect Endpoint 路径、安全组来源、NACL 返回流量、企业/本地出口和主机防火墙。SSH 入站只应允许必要来源或 AWS 托管前缀列表;不要把 22 端口对全世界开放来诊断。VPC 路径健康不能证明 sshd 正在监听,而公钥被拒通常说明网络路径已经可用。
5. 优先使用 AWS 支持的恢复通道
选择前置条件已经具备的第一条路径。不要为了建立恢复通道而削弱 SSH。
| 路径 | 适用条件 | 重要门槛 |
|---|---|---|
| EC2 Instance Connect | AMI/软件包、IAM 权限、用户名和网络路径均受支持 | 仍依赖实例端服务/配置以及对应 SSH 路径或端点 |
| Systems Manager Session Manager | 实例已经是托管节点,具备 SSM Agent、合适的实例配置文件和服务连通性 | 不要临时附加宽泛 IAM 权限;遵循组织的 Session Manager 访问策略 |
| EC2 Serial Console | 账户/区域、实例类型、IAM 和系统登录前置条件满足 | 它绕过 VPC 数据路径,但 Linux 交互排障通常需要预先配置的密码型系统用户 |
AWSSupport-TroubleshootSSH | 具有 Systems Manager Automation 权限,并希望使用 AWS EC2Rescue 检查 | 从默认只读的 CheckAll 开始;在 FixAll 或离线修复前审查范围 |
通过可信路径进入后,先收集服务器端证据再修改:
id ubuntu
namei -l /home/ubuntu/.ssh/authorized_keys
stat -c '%n owner=%U:%G uid=%u gid=%g mode=%a type=%F'
/home/ubuntu
/home/ubuntu/.ssh
/home/ubuntu/.ssh/authorized_keys
sudo -u ubuntu ssh-keygen -lf /home/ubuntu/.ssh/authorized_keys
sudo sshd -t
sudo sshd -T
-C user=ubuntu,host=REPLACE_WITH_INSTANCE_HOSTNAME,addr=REPLACE_WITH_CLIENT_IP
| grep -E '^(pubkeyauthentication|authorizedkeysfile|authorizedkeyscommand|strictmodes|allowusers|denyusers|allowgroups|denygroups) '
sudo systemctl status ssh --no-pager
同时检查与本次尝试相关、经过脱敏的 journalctl -u ssh 记录。有效策略可能来自 sshd_config、包含的片段、Match 块或 EC2 Instance Connect 之类的 AuthorizedKeysCommand;不要假设只有一个文件生效。
6. 执行一次边界明确的权限修复
当 home、.ssh 或 authorized_keys 可被其他用户修改时,OpenSSH StrictModes 会拒绝密钥认证。所有者必须是预期账户。前面的 namei 和 stat 输出是基线;如果已经安装 getfacl,也记录 ACL。对于使用以下路径的常规 Ubuntu 账户,只修复这三个对象;绝不要对整个 home 树递归执行 chmod 或 chown:
sudo getfacl -p
/home/ubuntu
/home/ubuntu/.ssh
/home/ubuntu/.ssh/authorized_keys
sudo chown ubuntu:ubuntu /home/ubuntu
sudo chmod go-w /home/ubuntu
sudo chown ubuntu:ubuntu
/home/ubuntu/.ssh
/home/ubuntu/.ssh/authorized_keys
sudo chmod 700 /home/ubuntu/.ssh
sudo chmod 600 /home/ubuntu/.ssh/authorized_keys
这些是常用的限制性模式,不是适用于所有部署的通用指令。如果有效 AuthorizedKeysFile、账户数据库、ACL/SELinux/AppArmor 策略、NFS 身份映射或镜像布局不同,应停止并按对应文档处理。如果缺少正确的公钥指纹,应把它作为受控密钥替换:保留当前文件、批准新公钥指纹、按 AWS 官方新增/替换密钥流程操作,并在移除任何旧记录前测试新密钥。
保持恢复会话开启,从第二个终端验证:
sudo sshd -t
sudo systemctl is-active ssh
ssh -o IdentitiesOnly=yes
-i /secure/path/to/private-key.pem
ubuntu@REPLACE_WITH_VERIFIED_HOSTNAME
如果失败,对照已记录的所有者/模式/ACL,只恢复改过的对象。仅修改文件元数据时无需重载或重启 ssh。如果修改了 SSH 配置,应先以 sshd -t 验证,再受控重载并保留恢复通道。
7. 根卷救援是最后的维护路径
仅在根卷由 EBS 支持且在线恢复路径都不可用时进行离线修复。停止前记录停机批准、依赖服务、Auto Scaling 行为、公网地址行为、所有卷映射、DeleteOnTermination 和任何 instance-store 数据。AWS 说明 stop/start 可能改变非 Elastic IP 的公网 IPv4,并会清除 instance-store 数据。为根卷创建快照,并确认辅助实例位于同一可用区且有权限使用该卷的 KMS 密钥。
原实例停止并安全分离根 EBS 卷后,将它作为数据卷附加到受控辅助实例。不要猜 /dev/sda2:Nitro 实例可能以会变化的 NVMe 名称枚举 EBS 设备。把 EC2 卷 ID 与设备序列号对应,并以只读方式识别文件系统和分区:
lsblk -o NAME,SERIAL,SIZE,FSTYPE,UUID,MOUNTPOINTS
sudo blkid
sudo file -s /dev/REPLACE_WITH_VERIFIED_DEVICE
不要运行 mkfs、自动修复或强制文件系统检查。只有在控制台卷 ID、NVMe 序列号、分区表、文件系统和预期根目录内容一致后,才设置 RESCUE_PARTITION。首先只读挂载:
RESCUE_ROOT='/mnt/ec2-root'
RESCUE_PARTITION='/dev/REPLACE_WITH_VERIFIED_ROOT_PARTITION'
sudo install -d -m 700 "$RESCUE_ROOT"
sudo mount -o ro "$RESCUE_PARTITION" "$RESCUE_ROOT"
findmnt "$RESCUE_ROOT"
sudo test -f "$RESCUE_ROOT/etc/os-release"
sudo test -d "$RESCUE_ROOT/home/ubuntu/.ssh"
应从离线系统自身的账户数据库解析所有权,而不是使用辅助机的 ubuntu 账户;写入前记录元数据:
TARGET_USER='ubuntu'
TARGET_UID="$(awk -F: -v u="$TARGET_USER" '$1==u {print $3}' "$RESCUE_ROOT/etc/passwd")"
TARGET_GID="$(awk -F: -v u="$TARGET_USER" '$1==u {print $4}' "$RESCUE_ROOT/etc/passwd")"
printf 'target uid=%s gid=%sn' "$TARGET_UID" "$TARGET_GID"
sudo stat -c '%n uid=%u gid=%g mode=%a type=%F'
"$RESCUE_ROOT/home/$TARGET_USER"
"$RESCUE_ROOT/home/$TARGET_USER/.ssh"
"$RESCUE_ROOT/home/$TARGET_USER/.ssh/authorized_keys"
sudo ssh-keygen -lf "$RESCUE_ROOT/home/$TARGET_USER/.ssh/authorized_keys"
如果预期用户、UID/GID、指纹或路径不匹配,不要重新读写挂载,直接升级处理。如果全部匹配且已经证明元数据是根因,才批准以下一次边界明确的写入:
sudo mount -o remount,rw "$RESCUE_ROOT"
sudo chown "$TARGET_UID:$TARGET_GID" "$RESCUE_ROOT/home/$TARGET_USER"
sudo chmod go-w "$RESCUE_ROOT/home/$TARGET_USER"
sudo chown "$TARGET_UID:$TARGET_GID"
"$RESCUE_ROOT/home/$TARGET_USER/.ssh"
"$RESCUE_ROOT/home/$TARGET_USER/.ssh/authorized_keys"
sudo chmod 700 "$RESCUE_ROOT/home/$TARGET_USER/.ssh"
sudo chmod 600 "$RESCUE_ROOT/home/$TARGET_USER/.ssh/authorized_keys"
sync
sudo mount -o remount,ro "$RESCUE_ROOT"
验证最终数字所有者、模式、指纹和挂载状态。干净卸载,从辅助机分离,并按维护前记录的原始块设备映射重新附加到原实例。启动前确认卷状态和附加关系。直到状态检查、主机指纹、SSH 登录、应用健康和监控都通过前,保留快照和元数据记录;回滚是按相同变更控制再次停止,并恢复已知良好的卷/快照。
遇到以下情况应停止并升级处理
- 错误分支发生变化、无法独立验证主机指纹,或预期的私钥/公钥指纹不匹配;
- 实例不是 EBS 根卷、instance-store 数据有风险,或目标/根设备不明确;
- 无法用批准的 KMS 权限附加加密卷;
- 怀疑文件系统损坏、根卷出现意外挂载,或写入会超出批准的账户路径;
- 托管策略、集中身份、配置管理或 Auto Scaling 会覆盖修复。
官方资料
- AWS:排查 EC2 Linux 连接错误
- AWS:常规连接前置条件与实例主机指纹
- AWS:验证 EC2 密钥对指纹
- AWS:EC2 Instance Connect 前置条件
- AWS:使用 EC2 Instance Connect 连接
- AWS:使用 Systems Manager Session Manager 连接
- AWS:配置 EC2 Serial Console 访问
- AWS:`AWSSupport-TroubleshootSSH`
- AWS:停止和启动 EC2 实例
- AWS:附加和分离 EBS 卷
- AWS:将 EBS 卷映射到 NVMe 设备名
- AWS:EBS 加密与 KMS 行为
- OpenSSH:`sshd` 授权密钥所有权和模式
- Ubuntu Server:OpenSSH 服务与密钥认证
2017 年原文档案(非现行操作说明)
以下完整保留 source_export 的可见正文,仅规范行尾空白。其中一个不安全的递归权限命令被窄化替换为 [REDACTED: unsafe recursive chmod command],其他文字和命令均未改动。档案含猜测的设备名和宽泛权限建议,不可作为当前操作手册。
N.B. There are dozens of reasons to lead to this problem, for example, wrong permission of your pem file, incorrect username(e.g., ec2-user, ubuntu),wrong spelling in your command, etc..
The reason which causes my problem, if I am right, is that I run command `[REDACTED: unsafe recursive chmod command]` under the wrong directory, namely, my home folder.
The solution is just setting your home folder permissions back.
1. Stop your problematic instance.
2. Create a new instance and stop the new problem-free instance.
3. The newly created instance should be in the same `Availability Zone` like ‘us-west-2c’ which can be set on the ‘Network’ step under which the menu is ‘Subnet’.
4. Detach your ‘ebs volume’ from the problematic instances and attach it on your new problem-free instance.
5. Your need input your instance id as well as the mount point which looks like ‘/dev/sda2’.
6. Start your new instance and mount the second drive that you just attached.
[ubuntu ~]$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
xvdf 202:80 0 100G 0 disk
xvda1 202:1 0 8G 0 disk /
[ubuntu ~]$ sudo mount /dev/xvdf/ /mnt
8. Change directory to your mounted point and restore the permission of your home directory with permission 755.
[ubuntu ~]$ cd /mnt/home/
[ubuntu ~]$ chmod 755 yourusername
9. Stop your new instance and detach the volume owned by the problematic instance.
10. Reattach the just detached volume to the default problematic instance.
