上一篇 下一篇 分享链接 返回 返回顶部

为美国服务器加固SSH访问,如何配置密钥认证与来源IP限制?

发布人:Minchunlin 发布时间:1 天前 阅读量:21
为美国服务器加固SSH访问,如何配置密钥认证与来源IP限制?

美国服务器的 SSH 加固,建议采用“密钥认证 + 来源 IP 白名单 + 主机防火墙”三层限制,并在确认新连接成功后再关闭密码登录和 root 直接登录。仅修改 SSH 端口只能减少自动化扫描,不能替代认证和来源控制。

以下步骤以采用 systemd 的 Linux 美国服务器、OpenSSH 服务为例,适用于常见的 Ubuntu、Debian 和 RHEL 系发行版。执行前需要准备:

  • 一个已经可以登录服务器的管理会话,最好同时保留云平台控制台或带外终端。
  • 一个非 root 管理账号,例如 opsadmin,并确认该账号可以正常使用 sudo。
  • 管理员当前实际的公网出口 IP,例如文中的 203.0.113.10。这是服务器日志中看到的来源地址,不一定是办公电脑的内网地址。
  • 确认服务器上使用的是 ssh 还是 sshd 服务名,并确认当前 SSH 监听端口。

先查看现状,不要在不了解当前配置的情况下直接覆盖文件:

sudo ss -lntp | grep -E ':(22|2222)\b'
sudo systemctl status ssh --no-pager 2>/dev/null || sudo systemctl status sshd --no-pager
sudo grep -RInE '^\s*(Port|AllowUsers|AllowGroups|PasswordAuthentication|PubkeyAuthentication|PermitRootLogin|AuthenticationMethods)' \
  /etc/ssh/sshd_config /etc/ssh/sshd_config.d 2>/dev/null

先配置并验证密钥认证

在管理端生成专用密钥

密钥应当在管理员自己的电脑或受控跳板机上生成,私钥不要上传到美国服务器,也不要通过聊天工具传输。

ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_us_server -C "opsadmin-us-server"

如果客户端或服务器上的 OpenSSH 版本过旧,不支持 Ed25519,再根据兼容性要求选择 RSA 密钥。生成后应确认权限:

chmod 600 ~/.ssh/id_ed25519_us_server
chmod 644 ~/.ssh/id_ed25519_us_server.pub

查看公钥内容:

cat ~/.ssh/id_ed25519_us_server.pub

复制输出的完整单行内容,包括开头的 ssh-ed25519 和末尾的注释。私钥文件 id_ed25519_us_server 不应出现在服务器上。

将公钥放入目标账号

先在服务器确认目标账号的家目录:

getent passwd opsadmin

下面命令会读取该账号的家目录,并创建正确权限的 .ssh 目录:

HOME_DIR=$(getent passwd opsadmin | cut -d: -f6)

sudo install -d -m 700 -o opsadmin -g opsadmin "$HOME_DIR/.ssh"
sudoedit "$HOME_DIR/.ssh/authorized_keys"
sudo chown opsadmin:opsadmin "$HOME_DIR/.ssh/authorized_keys"
sudo chmod 600 "$HOME_DIR/.ssh/authorized_keys"

将刚才复制的公钥粘贴为 authorized_keys 中的一整行。不要把公钥断行,也不要误粘贴私钥。

在仍保持当前 SSH 会话的情况下,先从管理端测试密钥登录:

ssh -o IdentitiesOnly=yes \
    -i ~/.ssh/id_ed25519_us_server \
    -p 22 \
    opsadmin@SERVER_IP

将 SERVER_IP 替换为服务器地址。如果当前 SSH 端口不是 22,应使用实际端口。只有新终端能够通过密钥登录,并且以下命令能够正常执行,才继续关闭密码登录:

id
sudo -n true

sudo -n true 如果提示需要密码,不一定表示 SSH 配置失败,而是说明当前 sudo 策略要求输入本地 sudo 密码。此时应确认管理员确实知道该密码,并在关闭 SSH 密码认证后仍能完成 sudo 操作。

限制 SSH 的来源 IP

来源限制可以放在两个位置:

限制位置作用适用场景
sshd_config 的 AllowUsers按用户和来源地址限制 SSH 登录统一限制某个账号或多个账号
authorized_keys 的 from=只限制某一把公钥的来源地址同一账号有多把密钥,需要分别控制

实际加固时可以同时使用。这样即使某个账号配置错误,或者某把公钥被复制到其他地方,也仍有另一层来源限制。

在 SSH 服务端限制用户和地址

先备份正在编辑的配置文件:

sudo cp -a /etc/ssh/sshd_config \
  "/etc/ssh/sshd_config.bak.$(date +%F-%H%M%S)"

如果系统存在 /etc/ssh/sshd_config.d/,可以编辑其中的独立配置文件;如果没有该目录,直接编辑 /etc/ssh/sshd_config。先确认主配置是否加载了该目录:

sudo grep -nE '^\s*Include\s+/etc/ssh/sshd_config.d/' /etc/ssh/sshd_config

编辑配置时,至少确认以下内容。示例中的账号和地址必须替换为实际值:

PubkeyAuthentication yes
PasswordAuthentication no
PermitRootLogin no
PermitEmptyPasswords no
MaxAuthTries 3
AllowUsers opsadmin@203.0.113.10

AllowUsers 的含义是:只允许列出的账号和来源组合登录。若有多个固定办公出口,可以写在同一行:

AllowUsers opsadmin@203.0.113.10 opsadmin@198.51.100.0/24

使用 /24 之前必须确认该网段确实属于受控出口,否则白名单范围会大于预期。服务器实际看到的是公网出口地址;如果管理员通过 NAT、VPN 或跳板机访问,应该填写这些设备的出口 IP,而不是管理员电脑的私有地址。

如果使用了多个账号,必须把每一个仍需 SSH 登录的账号列入 AllowUsers。配置该参数后,未列出的账号会被拒绝,包括可能仍在使用的运维账号。

对单把公钥增加 from= 限制

在目标账号的 authorized_keys 中,可以将原来的公钥行改为:

from="203.0.113.10/32" ssh-ed25519 AAAA... opsadmin-us-server

from= 只对这一行公钥生效。如果同一账号有多把密钥,每一行都应根据实际用途设置来源范围。例如,临时应急密钥不应默认复制办公网络的宽范围白名单。

来源限制配置完成后,不要立即关闭当前会话。先从允许的地址新开一个终端测试:

ssh -o IdentitiesOnly=yes \
    -i ~/.ssh/id_ed25519_us_server \
    -p 22 \
    opsadmin@SERVER_IP

如果测试客户端不在白名单内,预期结果应为登录被拒绝。不要通过伪造来源地址测试,应使用实际的受控网络或跳板机验证。

让 SSH 只接受密钥

如果服务器没有使用双因素认证或其他依赖键盘交互的 PAM 认证,可以进一步明确只允许公钥认证:

PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
AuthenticationMethods publickey

不同 OpenSSH 版本对键盘交互配置项的名称可能不同。修改前可以查看有效配置:

sudo sshd -T | grep -Ei 'pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|challengeresponseauthentication|authenticationmethods'

如果服务器启用了基于 PAM 的多因素认证,不要直接设置 KbdInteractiveAuthentication no,否则可能连第二因素验证也被关闭。此类环境通常需要根据现有认证模块配置类似下面的组合:

AuthenticationMethods publickey,keyboard-interactive:pam

但该配置只有在服务器已经正确配置 PAM 多因素认证时才适用。修改前应确认认证流程,并用第二个终端完成测试。不能仅凭配置文件中的一行内容判断多因素认证是否真正生效。

配置完成后,使用密钥登录,再测试禁用公钥认证的连接:

ssh -o PubkeyAuthentication=no \
    -o PreferredAuthentications=password \
    -o NumberOfPasswordPrompts=1 \
    -p 22 \
    opsadmin@SERVER_IP

如果密码认证已经关闭,预期结果应为认证失败。若该命令仍能通过其他认证方式登录,应检查 KbdInteractiveAuthentication、PAM 和 AuthenticationMethods 的实际配置。

配置主机防火墙

SSH 服务自身的来源限制不能替代主机防火墙。防火墙可以在连接进入 SSH 进程前丢弃不符合条件的流量,减少无效认证请求。

先确认当前使用的是哪一种防火墙,不要同时用多个工具管理同一套规则:

sudo ufw status verbose 2>/dev/null
sudo firewall-cmd --state 2>/dev/null

使用 UFW 的系统

以下示例只允许 203.0.113.10 访问 22/TCP:

sudo ufw allow from 203.0.113.10 to any port 22 proto tcp
sudo ufw status numbered

如果要改用 2222 端口,则应先添加新端口规则:

sudo ufw allow from 203.0.113.10 to any port 2222 proto tcp
sudo ufw reload

确认新端口可以登录后,再检查是否仍有过宽的规则,例如允许所有来源访问 22/tcp。只有确认规则编号和影响范围后,才删除对应的宽泛规则:

sudo ufw status numbered
sudo ufw delete allow 22/tcp

不要直接执行 ufw reset,它可能删除服务器上其他业务的防火墙规则。

使用 firewalld 的系统

先查看当前规则:

sudo firewall-cmd --list-all

添加只允许指定 IPv4 地址访问 SSH 的永久规则:

sudo firewall-cmd --permanent \
  --add-rich-rule='rule family="ipv4" source address="203.0.113.10/32" port port="22" protocol="tcp" accept'

sudo firewall-cmd --reload
sudo firewall-cmd --list-rich-rules

如果服务器同时使用 IPv6,必须单独评估 IPv6 管理地址,并添加相应的 IPv6 规则;不能因为 IPv4 已经限制,就认为 IPv6 也受到限制。确认新规则有效后,再移除可能存在的对所有来源开放的 ssh 服务规则。删除时应使用与现有规则完全一致的规则内容,避免误删其他业务规则。

如果美国服务器还配置了云平台侧的安全组或边界防火墙,也应同步检查入站规则。主机防火墙、云侧规则和 sshd 白名单中,只要有一层不允许目标来源,连接就无法建立。

是否需要修改 SSH 端口

修改端口不是必选项。它可以降低低质量扫描的噪声,但不能防止针对性探测,也不能替代密钥和来源 IP 限制。

如果确实要改端口,应先在防火墙和云侧规则中放行新端口,再修改 SSH 配置。例如临时改为 2222:

Port 2222

不要在没有验证前删除旧端口。可以短时间同时监听旧端口和新端口,确认新端口登录成功后,再移除旧端口配置和对应防火墙规则。修改后检查实际监听状态:

sudo sshd -t
sudo ss -lntp | grep -E ':(22|2222)\b'

客户端使用新端口验证:

ssh -o IdentitiesOnly=yes \
    -i ~/.ssh/id_ed25519_us_server \
    -p 2222 \
    opsadmin@SERVER_IP

校验配置并平滑加载

任何 SSH 配置变更都应先做语法检查。语法检查失败时,不要重载服务:

sudo sshd -t

查看生效配置时,不能只看编辑过的文件,因为 Include、发行版默认值和 Match 区块都可能影响最终结果:

sudo sshd -T | grep -Ei \
  '^(port|pubkeyauthentication|passwordauthentication|permitrootlogin|allowusers|authenticationmethods|x11forwarding|allowtcpforwarding) '

还可以针对指定用户和来源地址查看条件配置:

sudo sshd -T \
  -C user=opsadmin,addr=203.0.113.10,laddr=SERVER_IP,lport=22 \
  | grep -Ei '^(port|pubkeyauthentication|passwordauthentication|permitrootlogin|allowusers|authenticationmethods) '

确认无误后再重载服务:

# Ubuntu、Debian 常见服务名
sudo systemctl reload ssh

# RHEL 系常见服务名
sudo systemctl reload sshd

如果不确定服务名,可以先用 systemctl status ssh 和 systemctl status sshd 判断。重载后不要关闭原来的管理会话,使用第二个终端完成新连接验证。

失败时按现象排查

排查应从网络层逐步进入认证层,避免一开始反复修改密钥文件。

连接超时

先检查:

sudo ss -lntp
sudo ufw status verbose 2>/dev/null
sudo firewall-cmd --list-all 2>/dev/null

超时通常意味着端口没有被正确放行,或者云侧防火墙、主机防火墙、IPv4/IPv6 路径中存在拦截。此时不要先修改 authorized_keys。

连接被拒绝

这通常说明目标地址可达,但该端口没有 SSH 服务监听,或者端口配置与客户端使用的不一致。检查 ss -lntp 的监听端口,以及服务状态和最近日志:

sudo journalctl -u ssh -n 50 --no-pager 2>/dev/null
sudo journalctl -u sshd -n 50 --no-pager 2>/dev/null

提示 Permission denied (publickey)

按以下顺序检查:

sudo sshd -T | grep -Ei 'pubkeyauthentication|allowusers|authenticationmethods'
getent passwd opsadmin

然后确认:

  • 客户端使用的是正确的私钥,且使用了 IdentitiesOnly=yes。
  • authorized_keys 中的公钥没有断行。
  • .ssh 目录权限通常为 700,authorized_keys 通常为 600。
  • 文件和目录归属属于 opsadmin。
  • from= 中的地址是服务器实际看到的公网来源地址。
  • AllowUsers 中包含目标账号和当前来源地址。
  • 服务器日志中的拒绝原因与客户端实际 IP 一致。

查看登录日志:

sudo journalctl --since "10 minutes ago" -u ssh --no-pager 2>/dev/null
sudo journalctl --since "10 minutes ago" -u sshd --no-pager 2>/dev/null

需要临时回滚

回滚前保留当前连接,并优先使用云控制台或带外终端。先恢复备份的主配置,或将新增的独立配置文件移出加载目录;不要直接清空整个 /etc/ssh 配置目录:

sudo cp -a /etc/ssh/sshd_config.bak.YYYY-MM-DD-HHMMSS /etc/ssh/sshd_config
sudo sshd -t
sudo systemctl reload sshd

上面的备份文件名必须替换为实际存在的文件。若使用的是 ssh 服务,则将最后一条命令改为:

sudo systemctl reload ssh

如果问题来自防火墙,应只撤销本次新增的精确规则,不要执行清空规则的命令。回滚后先恢复可控登录,再重新分阶段添加密钥、来源限制和密码禁用配置。

最小权限、补丁和审计不能遗漏

确认密钥登录稳定后,建议使用个人账号而不是多人共用账号,并通过 sudo 给予完成工作所需的权限。删除离职人员或旧设备对应的公钥前,先确认没有其他应急入口;新增替代密钥并验证成功后,再移除旧密钥。

如果服务器不需要图形转发或 SSH 隧道,可以在充分评估业务影响后增加:

X11Forwarding no
AllowTcpForwarding no

这两项可能影响远程调试、端口转发和部署工具,不能不经确认直接启用。涉及数据库、内网服务或发布流水线时,应先列出依赖关系,再决定是否关闭。

系统和 OpenSSH 需要保持在发行版仍提供安全更新的版本。升级前应备份 SSH 配置、确认控制台可用,并安排维护窗口:

# Debian、Ubuntu 示例
sudo apt update
sudo apt install --only-upgrade openssh-server

# RHEL 系示例
sudo dnf upgrade openssh-server

升级后重新执行 sshd -t,并检查端口、认证和来源限制是否仍符合预期。不要把一次升级命令当作永久安全保证,补丁策略还应覆盖系统内核及其他对外服务。

最后通过日志确认配置确实生效:

sudo journalctl -u ssh --since "today" --no-pager 2>/dev/null
sudo journalctl -u sshd --since "today" --no-pager 2>/dev/null
last -i

最容易遗漏的是 IPv6、NAT 后的真实出口 IP、仍然存在的宽泛防火墙规则,以及 AllowUsers 无意中排除其他运维账号。每次修改后都应分别验证“允许来源可以用密钥登录”“不允许来源无法连接或认证”“密码不能单独登录”,并保留经过验证的回滚路径。

目录结构
全文