首页 Linux教程Linux SSH 安全加固:密钥登录、权限和访问限制

Linux SSH 安全加固:密钥登录、权限和访问限制

运维派隶属马哥教育旗下专业运维社区,是国内成立最早的IT运维技术社区,欢迎关注公众号:yunweipai
领取学习更多免费Linux云计算、Python、Docker、K8s教程关注公众号:马哥linux运维

问题背景

SSH 是 Linux 服务器最常用的远程管理方式,也是攻击者最常攻击的入口。弱密码、暴力破解、未授权访问等安全问题频发,需要对 SSH 进行全面加固。

本文适用于以下角色:

  • 负责服务器安全的运维工程师
  • 需要加固 SSH 的系统管理员
  • 负责安全合规的安全工程师
  • 需要配置跳板机的 DevOps 工程师

SSH 安全的特点:

  • 默认配置不够安全
  • 是攻击者的首要目标
  • 需要多层防护
  • 需要平衡安全和易用性

适用场景

本文适用于以下场景:

  • 新服务器初始化时的 SSH 加固
  • 生产环境服务器的安全加固
  • 合规要求的 SSH 配置
  • 跳板机的 SSH 配置
  • 多用户环境的 SSH 权限管理
  • 防止暴力破解的 SSH 配置
  • 审计和日志管理

不适用于以下场景:

  • 桌面 Linux 的 SSH 配置(安全要求较低)
  • 开发测试环境(可以适当放松限制)
  • 容器内的 SSH(不推荐在容器内运行 SSH)

核心知识点

SSH 认证方式

密码认证

  • 优点:简单易用
  • 缺点:容易被暴力破解、容易泄露、难以管理

密钥认证

  • 优点:安全性高、难以破解、支持自动化
  • 缺点:密钥管理复杂、初次配置较繁琐

双因素认证(2FA)

  • 优点:安全性最高
  • 缺点:配置复杂、依赖第三方工具

SSH 密钥类型

RSA

  • 密钥长度:2048、4096 位
  • 安全性:高(4096 位)
  • 性能:一般
  • 兼容性:最好

ECDSA

  • 密钥长度:256、384、521 位
  • 安全性:高
  • 性能:好
  • 兼容性:好

Ed25519

  • 密钥长度:固定 256 位
  • 安全性:最高
  • 性能:最好
  • 兼容性:需要 OpenSSH 6.5+

推荐使用 Ed25519 或 RSA 4096 位。

SSH 配置文件

服务端配置

  • /etc/ssh/sshd_config:SSH 服务器配置
  • /etc/ssh/ssh_host_*_key:服务器密钥

客户端配置

  • ~/.ssh/config:用户级配置
  • /etc/ssh/ssh_config:系统级配置
  • ~/.ssh/authorized_keys:授权的公钥
  • ~/.ssh/known_hosts:已知主机指纹

SSH 攻击方式

暴力破解

  • 使用字典或常见密码尝试登录
  • 防御:禁用密码登录、使用 fail2ban、限制登录次数

中间人攻击

  • 伪装成服务器,窃取凭据
  • 防御:验证主机指纹、使用证书认证

密钥泄露

  • 密钥文件被窃取
  • 防御:密钥加密、权限控制、定期轮换

端口扫描

  • 扫描开放的 22 端口
  • 防御:修改默认端口、防火墙限制

整体加固思路

SSH 安全加固遵循纵深防御原则:

   网络层防护
    ↓
认证加固
    ↓
授权控制
    ↓
审计日志
    ↓
持续监控

加固步骤:

  1. 修改默认配置(端口、协议版本)
  2. 禁用密码登录,启用密钥认证
  3. 限制登录用户和来源 IP
  4. 配置密钥权限和管理
  5. 启用双因素认证(可选)
  6. 配置防火墙和 fail2ban
  7. 配置日志和审计
  8. 定期检查和更新

实战步骤

第一步:备份现有配置

目的:确保可以快速回滚。

   bash# 备份 SSH 服务器配置
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup_$(date +%Y%m%d_%H%M%S)

# 备份 SSH 客户端配置
cp /etc/ssh/ssh_config /etc/ssh/ssh_config.backup_$(date +%Y%m%d_%H%M%S)

# 备份用户 SSH 配置
cp ~/.ssh/config ~/.ssh/config.backup_$(date +%Y%m%d_%H%M%S)

# 备份 authorized_keys
cp ~/.ssh/authorized_keys ~/.ssh/authorized_keys.backup_$(date +%Y%m%d_%H%M%S)

风险提醒:

  • 修改 SSH 配置前必须备份
  • 保留至少一个可用的 SSH 连接(不要关闭当前会话)
  • 使用新会话测试配置,确认无误后再关闭旧会话

第二步:生成 SSH 密钥对

目的:为密钥登录准备密钥对。

2.1 生成 Ed25519 密钥(推荐)

   bash# 在客户端(本地机器)生成密钥
ssh-keygen -t ed25519 -C "your_email@example.com"

# 指定密钥文件名
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_server1 -C "server1_access"

# 为密钥设置密码(推荐)
# 生成过程中会提示输入密码,直接回车则不设置密码

预期输出:

   Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/user/.ssh/id_ed25519): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/user/.ssh/id_ed25519
Your public key has been saved in /home/user/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx your_email@example.com

2.2 生成 RSA 密钥(兼容性好)

   bash# 生成 4096 位 RSA 密钥
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

# 指定密钥文件名
ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa_server1 -C "server1_access"

2.3 查看生成的密钥

   bash# 查看私钥(不要泄露)
cat ~/.ssh/id_ed25519

# 查看公钥(可以公开)
cat ~/.ssh/id_ed25519.pub

# 查看密钥指纹
ssh-keygen -l -f ~/.ssh/id_ed25519.pub

# 查看所有密钥
ls -la ~/.ssh/

2.4 设置密钥权限

   bash# 私钥权限必须为 600(仅所有者可读写)
chmod 600 ~/.ssh/id_ed25519

# 公钥权限可以为 644
chmod 644 ~/.ssh/id_ed25519.pub

# .ssh 目录权限必须为 700
chmod 700 ~/.ssh/

判断逻辑:

  • 如果私钥权限不正确,SSH 会拒绝使用该密钥
  • 如果 .ssh 目录权限不正确,SSH 会忽略该目录下的配置

第三步:上传公钥到服务器

目的:将公钥添加到服务器的授权密钥列表。

3.1 使用 ssh-copy-id(推荐)

   bash# 上传公钥到服务器
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server-ip

# 指定端口
ssh-copy-id -i ~/.ssh/id_ed25519.pub -p 2222 user@server-ip

# 如果服务器禁用了密码登录,需要先临时启用
# 或使用其他方式上传公钥

预期输出:

   /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/user/.ssh/id_ed25519.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
user@server-ip's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'user@server-ip'"
and check to make sure that only the key(s) you wanted were added.

3.2 手动上传公钥

如果 ssh-copy-id 不可用,可以手动上传。

   bash# 方法 1:使用 scp 上传
scp ~/.ssh/id_ed25519.pub user@server-ip:/tmp/

# 在服务器上执行
ssh user@server-ip
mkdir -p ~/.ssh
chmod 700 ~/.ssh
cat /tmp/id_ed25519.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
rm /tmp/id_ed25519.pub

# 方法 2:直接复制粘贴
# 在客户端查看公钥
cat ~/.ssh/id_ed25519.pub

# 在服务器上执行
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... your_email@example.com" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

3.3 验证公钥是否上传成功

   bash# 在服务器上查看 authorized_keys
cat ~/.ssh/authorized_keys

# 尝试使用密钥登录
ssh -i ~/.ssh/id_ed25519 user@server-ip

# 如果成功登录且未提示输入密码,说明公钥配置成功

第四步:配置 SSH 服务器

目的:加固 SSH 服务器配置。

4.1 修改 SSH 配置文件

编辑 /etc/ssh/sshd_config

   bash# 备份配置
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup

# 编辑配置
vim /etc/ssh/sshd_config

推荐配置:

   sshd_config# 基础配置
Port 22222                              # 修改默认端口(可选,但建议修改)
AddressFamily inet                      # 仅使用 IPv4(如果不需要 IPv6)
ListenAddress 0.0.0.0                   # 监听所有 IP(或指定特定 IP)

# 协议和算法
Protocol 2                              # 仅使用 SSH 协议版本 2
HostKey /etc/ssh/ssh_host_ed25519_key  # 使用 Ed25519 主机密钥
HostKey /etc/ssh/ssh_host_rsa_key      # 使用 RSA 主机密钥

# 加密算法(仅使用强加密)
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256

# 认证配置
PubkeyAuthentication yes                # 启用公钥认证
AuthorizedKeysFile .ssh/authorized_keys # 公钥文件位置
PasswordAuthentication no               # 禁用密码认证
PermitEmptyPasswords no                 # 禁止空密码
ChallengeResponseAuthentication no      # 禁用质询响应认证
UsePAM yes                              # 使用 PAM 认证(用于日志和会话管理)

# 登录控制
PermitRootLogin no                      # 禁止 root 直接登录
MaxAuthTries 3                          # 最大认证尝试次数
MaxSessions 10                          # 最大会话数
MaxStartups 10:30:60                    # 并发连接限制

# 访问控制
AllowUsers deploy ops                   # 仅允许指定用户登录
# AllowGroups sshusers                  # 或仅允许指定组登录
# DenyUsers baduser                     # 拒绝指定用户登录
# DenyGroups badgroup                   # 拒绝指定组登录

# 会话配置
ClientAliveInterval 300                 # 客户端存活检测间隔(5 分钟)
ClientAliveCountMax 2                   # 最大存活检测次数
LoginGraceTime 60                       # 登录宽限时间(60 秒)
TCPKeepAlive yes                        # 启用 TCP keepalive

# 转发和隧道
X11Forwarding no                        # 禁用 X11 转发
AllowTcpForwarding no                   # 禁用 TCP 转发(如需端口转发则设为 yes)
AllowStreamLocalForwarding no           # 禁用 Unix 域套接字转发
GatewayPorts no                         # 禁用网关端口
PermitTunnel no                         # 禁用隧道

# 其他安全配置
PermitUserEnvironment no                # 禁止用户设置环境变量
StrictModes yes                         # 严格检查文件权限
IgnoreRhosts yes                        # 忽略 .rhosts 文件
HostbasedAuthentication no              # 禁用基于主机的认证
PrintMotd yes                           # 显示登录消息
PrintLastLog yes                        # 显示上次登录信息
Banner /etc/ssh/banner                  # 登录前显示警告信息(可选)

# 日志配置
SyslogFacility AUTH                     # 日志设施
LogLevel VERBOSE                        # 日志级别(推荐 VERBOSE 或 INFO)

# Subsystem
Subsystem sftp /usr/libexec/openssh/sftp-server   # SFTP 子系统

关键配置说明:

Port

  • 默认 22 端口容易被扫描
  • 修改为非标准端口(如 22222)可以减少扫描和攻击
  • 修改端口后防火墙也需要同步修改

PermitRootLogin

  • 禁止 root 直接登录,强制使用普通用户 + sudo
  • 如果必须允许 root 登录,设置为 prohibit-password(仅允许密钥)

PasswordAuthentication

  • 禁用密码认证,仅使用密钥认证
  • 配置密钥登录后再禁用
  • 禁用后无法使用密码登录,确保密钥已配置

AllowUsers / AllowGroups

  • 白名单方式,仅允许指定用户或组登录
  • 优先使用 AllowUsers
  • 如果用户数量多,使用 AllowGroups

ClientAliveInterval

  • 定期向客户端发送存活检测包
  • 防止长时间空闲连接被防火墙关闭
  • 也可以及时发现断开的连接

LogLevel

  • VERBOSE:记录详细日志,包括密钥指纹
  • INFO:记录常规日志
  • DEBUG:记录调试日志(不推荐生产环境)

4.2 创建登录警告信息(可选)

   bash# 创建 banner 文件
cat > /etc/ssh/banner << 'EOF'
###############################################################################
#                            WARNING                                          #
###############################################################################
# Unauthorized access to this system is forbidden and will be prosecuted by  #
# law. By accessing this system, you agree that your actions may be monitored#
# if unauthorized usage is suspected.                                        #
###############################################################################
EOF

# 在 sshd_config 中启用
# Banner /etc/ssh/banner

4.3 检查配置语法

   bash# 检查配置语法
sshd -t

# 或
/usr/sbin/sshd -t

预期输出:

   # 无输出表示配置正确

异常输出:

   /etc/ssh/sshd_config line 25: Bad configuration option: InvalidOption
/etc/ssh/sshd_config: terminating, 1 bad configuration options

判断逻辑:

  • 如果配置有误,sshd -t 会报错并指出错误行
  • 修复错误后再次检查,直到无错误

4.4 重新加载 SSH 服务

风险提醒:

  • 重新加载 SSH 配置可能导致当前连接断开
  • 必须保留至少一个已登录的会话(不要关闭)
  • 使用新会话测试配置
   bash# 方法 1:重新加载配置(不中断现有连接,推荐)
systemctl reload sshd

# 方法 2:重启服务(会中断现有连接,不推荐)
systemctl restart sshd

# 检查服务状态
systemctl status sshd

# 查看日志
journalctl -u sshd -f

4.5 测试 SSH 连接

保留当前会话,打开新终端测试:

   bash# 测试密钥登录
ssh -i ~/.ssh/id_ed25519 user@server-ip -p 22222

# 测试密码登录(应该被拒绝)
ssh user@server-ip -p 22222

# 测试 root 登录(应该被拒绝)
ssh root@server-ip -p 22222

预期结果:

  • 密钥登录成功
  • 密码登录被拒绝
  • root 登录被拒绝

如果测试失败:

  • 不要关闭当前会话
  • 检查配置文件
  • 查看日志:journalctl -u sshd -f
  • 修复问题后再次测试
  • 确认无误后再关闭旧会话

第五步:配置客户端 SSH

目的:简化 SSH 连接,配置客户端选项。

5.1 配置 SSH 客户端配置文件

编辑 ~/.ssh/config

   bash# 创建或编辑配置文件
vim ~/.ssh/config

# 设置权限
chmod 600 ~/.ssh/config

配置示例:

   sshconfig# 默认配置
Host *
    # 使用强加密算法
    Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
    MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
    KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org
    
    # 连接保持
    ServerAliveInterval 60
    ServerAliveCountMax 3
    TCPKeepAlive yes
    
    # 连接复用
    ControlMaster auto
    ControlPath ~/.ssh/sockets/%r@%h:%p
    ControlPersist 600
    
    # 其他选项
    Compression yes
    ForwardAgent no
    ForwardX11 no
    StrictHostKeyChecking ask
    HashKnownHosts yes

# 生产服务器
Host prod-web1
    HostName 192.168.1.101
    Port 22222
    User deploy
    IdentityFile ~/.ssh/id_ed25519_prod
    ForwardAgent no

Host prod-web2
    HostName 192.168.1.102
    Port 22222
    User deploy
    IdentityFile ~/.ssh/id_ed25519_prod

# 跳板机配置
Host jump
    HostName 1.2.3.4
    Port 22222
    User jump_user
    IdentityFile ~/.ssh/id_ed25519_jump

# 通过跳板机访问内网服务器
Host internal-*
    ProxyJump jump
    User deploy
    IdentityFile ~/.ssh/id_ed25519_internal

Host internal-db1
    HostName 10.0.1.101
    Port 22

Host internal-db2
    HostName 10.0.1.102
    Port 22

# 开发环境
Host dev-*
    User developer
    IdentityFile ~/.ssh/id_ed25519_dev
    ForwardAgent yes

Host dev-web1
    HostName 192.168.2.101

配置说明:

ControlMaster / ControlPath / ControlPersist

  • 连接复用,多个 SSH 会话共享一个连接
  • 提高连接速度,减少认证次数
  • ControlPersist 600 表示主连接空闲 600 秒后关闭

ServerAliveInterval / ServerAliveCountMax

  • 定期向服务器发送存活检测包
  • 防止连接被防火墙关闭
  • ServerAliveInterval 60 表示每 60 秒发送一次
  • ServerAliveCountMax 3 表示最多发送 3 次

ProxyJump

  • 通过跳板机访问内网服务器
  • 相当于 ssh -J jump internal-db1
  • 比 ProxyCommand 更简洁

ForwardAgent

  • SSH 代理转发,将本地 SSH 密钥转发到远程服务器
  • 风险:远程服务器可以使用你的密钥访问其他服务器
  • 仅在需要时启用,默认禁用

5.2 使用 SSH 配置连接

   bash# 直接使用别名连接
ssh prod-web1

# 相当于
ssh -i ~/.ssh/id_ed25519_prod -p 22222 deploy@192.168.1.101

# 通过跳板机连接内网服务器
ssh internal-db1

# 相当于
ssh -J jump_user@1.2.3.4:22222 deploy@10.0.1.101

5.3 配置连接复用目录

   bash# 创建连接复用目录
mkdir -p ~/.ssh/sockets
chmod 700 ~/.ssh/sockets

第六步:配置 sudo 权限

目的:禁止 root 直接登录后,使用 sudo 提权。

6.1 创建普通用户

   bash# 创建用户
useradd -m -s /bin/bash deploy

# 设置密码(可选,仅用于本地登录或紧急恢复)
passwd deploy

# 或创建用户时指定 UID 和 GID
useradd -m -s /bin/bash -u 1001 -g 1001 deploy

6.2 配置 sudo 权限

   bash# 编辑 sudoers 文件
visudo

# 或编辑单独的配置文件
vim /etc/sudoers.d/deploy

配置示例:

   sudoers# 允许 deploy 用户无密码执行所有命令
deploy ALL=(ALL) NOPASSWD: ALL

# 允许 deploy 用户执行指定命令
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl, /usr/bin/docker

# 允许 ops 组无密码执行所有命令
%ops ALL=(ALL) NOPASSWD: ALL

# 要求输入密码
deploy ALL=(ALL) ALL

配置说明:

  • NOPASSWD:无需输入密码即可 sudo
  • ALL=(ALL) ALL:可以以任何用户身份执行任何命令
  • /usr/bin/systemctl:仅允许执行指定命令
  • %ops:% 表示组

风险提醒:

  • NOPASSWD: ALL 风险较大,仅在自动化场景使用
  • 生产环境建议要求输入密码:ALL=(ALL) ALL
  • 或仅授权特定命令

6.3 测试 sudo 权限

   bash# 切换到 deploy 用户
su - deploy

# 测试 sudo
sudo whoami
# 应该输出: root

# 查看 sudo 权限
sudo -l

# 执行需要 root 权限的命令
sudo systemctl status sshd

第七步:配置防火墙

目的:限制 SSH 访问来源。

7.1 使用 iptables 限制访问

   bash# 清空现有规则(谨慎操作)
iptables -F
iptables -X

# 设置默认策略
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# 允许本地回环
iptables -A INPUT -i lo -j ACCEPT

# 允许已建立的连接
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# 允许特定 IP 访问 SSH(修改为实际端口)
iptables -A INPUT -p tcp -s 1.2.3.4 --dport 22222 -j ACCEPT
iptables -A INPUT -p tcp -s 5.6.7.0/24 --dport 22222 -j ACCEPT

# 拒绝其他 SSH 连接
iptables -A INPUT -p tcp --dport 22222 -j DROP

# 允许其他必要服务(根据实际情况)
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# 保存规则
iptables-save > /etc/iptables/rules.v4

# 或(CentOS/RHEL)
service iptables save

风险提醒:

  • 修改防火墙规则前必须保留当前 SSH 连接
  • 错误的规则可能导致无法连接
  • 建议先在测试环境验证

7.2 使用 firewalld 限制访问

   bash# 查看当前规则
firewall-cmd --list-all

# 移除默认的 SSH 服务(端口 22)
firewall-cmd --permanent --remove-service=ssh

# 添加自定义端口(修改为实际端口)
firewall-cmd --permanent --add-port=22222/tcp

# 限制来源 IP
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="1.2.3.4" port port="22222" protocol="tcp" accept'
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="5.6.7.0/24" port port="22222" protocol="tcp" accept'

# 重新加载规则
firewall-cmd --reload

# 查看规则
firewall-cmd --list-all

7.3 使用云服务商安全组

如果是云服务器,优先使用安全组:

  • 阿里云:安全组规则
  • 腾讯云:安全组
  • AWS:Security Group
  • Azure:Network Security Group

安全组配置示例:

   入方向规则:
协议   端口     来源            动作
TCP   22222   1.2.3.4/32      允许
TCP   22222   5.6.7.0/24      允许
TCP   80      0.0.0.0/0       允许
TCP   443     0.0.0.0/0       允许
ALL   ALL     其他            拒绝

第八步:配置 fail2ban

目的:防止暴力破解。

8.1 安装 fail2ban

   bash# CentOS/RHEL
yum install -y epel-release
yum install -y fail2ban

# Ubuntu/Debian
apt install -y fail2ban

# 启动服务
systemctl start fail2ban
systemctl enable fail2ban

8.2 配置 fail2ban

   bash# 创建自定义配置(不要直接修改 jail.conf)
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

# 编辑配置
vim /etc/fail2ban/jail.local

配置示例:

   ini[DEFAULT]
# 忽略的 IP(白名单)
ignoreip = 127.0.0.1/8 ::1 1.2.3.4

# 封禁时长(秒)
bantime = 3600

# 检测时间窗口(秒)
findtime = 600

# 最大失败次数
maxretry = 3

# 邮件通知(可选)
destemail = admin@example.com
sendername = Fail2Ban
mta = sendmail
action = %(action_mwl)s

[sshd]
enabled = true
port = 22222
filter = sshd
logpath = /var/log/secure
# CentOS/RHEL 使用 /var/log/secure
# Ubuntu/Debian 使用 /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600

配置说明:

  • bantime:封禁时长,3600 秒 = 1 小时
  • findtime:检测时间窗口,600 秒内
  • maxretry:最大失败次数,超过 3 次封禁
  • logpath:日志文件路径

8.3 启动 fail2ban

   bash# 重启服务
systemctl restart fail2ban

# 检查状态
systemctl status fail2ban

# 查看 SSH 保护状态
fail2ban-client status sshd

预期输出:

   Status for the jail: sshd
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     0
|  `- File list:        /var/log/secure
`- Actions
   |- Currently banned: 0
   |- Total banned:     0
   `- Banned IP list:

8.4 测试 fail2ban

   bash# 故意输错密码 3 次
ssh user@server-ip -p 22222

# 查看封禁列表
fail2ban-client status sshd

# 手动解封 IP
fail2ban-client set sshd unbanip 1.2.3.4

# 手动封禁 IP
fail2ban-client set sshd banip 1.2.3.4

第九步:配置日志和审计

目的:记录 SSH 登录和操作日志,方便审计。

9.1 配置 SSH 日志

SSH 日志默认记录在:

  • CentOS/RHEL:/var/log/secure
  • Ubuntu/Debian:/var/log/auth.log

查看 SSH 日志:

   bash# 查看所有 SSH 日志
grep sshd /var/log/secure

# 查看登录成功日志
grep "Accepted" /var/log/secure

# 查看登录失败日志
grep "Failed" /var/log/secure

# 查看特定用户的登录日志
grep "user deploy" /var/log/secure

# 查看特定 IP 的登录日志
grep "1.2.3.4" /var/log/secure

# 实时监控日志
tail -f /var/log/secure | grep sshd

9.2 配置命令审计(记录所有执行的命令)

使用 script 命令记录会话:

   bash# 在用户的 .bashrc 或 .bash_profile 中添加
cat >> ~/.bashrc << 'EOF'
# 记录所有命令到日志文件
if [ -z "$SCRIPT_LOG" ]; then
    export SCRIPT_LOG=1
    logdir=/var/log/user_commands
    mkdir -p $logdir
    logfile=$logdir/$(whoami)_$(date +%Y%m%d_%H%M%S).log
    script -q -a -f $logfile
    exit
fi
EOF

风险提醒:

  • 日志文件会占用磁盘空间,需要定期清理
  • 日志文件包含敏感信息,需要严格控制权限
  • 日志目录需要 root 权限,普通用户无法删除

9.3 使用 auditd 审计

   bash# 安装 auditd
yum install -y audit  # CentOS/RHEL
apt install -y auditd # Ubuntu/Debian

# 启动服务
systemctl start auditd
systemctl enable auditd

# 添加审计规则(审计 SSH 相关文件)
auditctl -w /etc/ssh/sshd_config -p wa -k sshd_config
auditctl -w /etc/ssh/ssh_host_rsa_key -p wa -k ssh_host_key
auditctl -w /home/ -p wa -k home_directory

# 查看审计规则
auditctl -l

# 查看审计日志
ausearch -k sshd_config
ausearch -k ssh_host_key

# 生成审计报告
aureport --summary

第十步:密钥管理和轮换

目的:定期更新密钥,防止密钥泄露。

10.1 定期更新密钥

   bash# 生成新密钥
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_new -C "new_key"

# 上传新密钥到服务器
ssh-copy-id -i ~/.ssh/id_ed25519_new.pub user@server-ip

# 测试新密钥是否可用
ssh -i ~/.ssh/id_ed25519_new user@server-ip

# 确认无误后,删除旧密钥
# 在服务器上编辑 authorized_keys,删除旧公钥
vim ~/.ssh/authorized_keys

# 备份并删除旧密钥
mv ~/.ssh/id_ed25519 ~/.ssh/id_ed25519.old
mv ~/.ssh/id_ed25519_new ~/.ssh/id_ed25519

10.2 撤销泄露的密钥

   bash# 在服务器上删除泄露的公钥
vim ~/.ssh/authorized_keys
# 删除对应的公钥行

# 或使用命令删除特定公钥
ssh-keygen -R hostname  # 删除 known_hosts 中的主机指纹

10.3 密钥备份

   bash# 备份私钥(加密存储)
tar -czf ssh_keys_backup.tar.gz ~/.ssh/
gpg -c ssh_keys_backup.tar.gz
rm ssh_keys_backup.tar.gz

# 存储到安全位置(离线存储、密码管理器等)

第十一步:启用双因素认证(可选)

目的:增加额外的安全层。

11.1 安装 Google Authenticator

   bash# CentOS/RHEL
yum install -y google-authenticator

# Ubuntu/Debian
apt install -y libpam-google-authenticator

11.2 配置 Google Authenticator

   bash# 以需要配置的用户身份运行
google-authenticator

# 按提示操作:
# - Do you want authentication tokens to be time-based? (y/n) y
# - 扫描二维码或手动输入密钥到手机 APP
# - Do you want me to update your "/home/user/.google_authenticator" file? (y/n) y
# - Do you want to disallow multiple uses of the same authentication token? (y/n) y
# - By default, tokens are good for 30 seconds. Do you want to increase? (y/n) n
# - Do you want to enable rate-limiting? (y/n) y

11.3 配置 PAM

编辑 /etc/pam.d/sshd

   bash# 在文件开头添加
auth required pam_google_authenticator.so

11.4 配置 SSH

编辑 /etc/ssh/sshd_config

   sshd_config# 启用双因素认证
ChallengeResponseAuthentication yes
AuthenticationMethods publickey,keyboard-interactive

11.5 重启 SSH 服务

   bashsystemctl restart sshd

11.6 测试双因素认证

   bash# 连接服务器
ssh user@server-ip

# 应该提示输入验证码
Verification code:

# 输入手机 APP 显示的 6 位数字

第十二步:配置跳板机(堡垒机)

目的:集中管理 SSH 访问,增强审计能力。

12.1 跳板机架构

   用户 → 跳板机 → 内网服务器

跳板机配置要点:

  • 仅允许特定用户登录跳板机
  • 跳板机到内网服务器使用密钥认证
  • 记录所有通过跳板机的操作
  • 限制跳板机的权限(仅允许 SSH 转发)

12.2 配置跳板机 SSH

跳板机 /etc/ssh/sshd_config

   sshd_config# 仅允许特定用户登录
AllowUsers jump_user1 jump_user2

# 禁止 shell 登录(仅允许端口转发)
ForceCommand /bin/false

# 或允许登录但限制命令
ForceCommand /usr/local/bin/jump_menu.sh

# 启用 TCP 转发
AllowTcpForwarding yes
GatewayPorts no

# 记录详细日志
LogLevel VERBOSE

12.3 配置跳板机脚本

创建 /usr/local/bin/jump_menu.sh

   bash#!/bin/bash

# 记录登录信息
logger -t JUMP "User $USER logged in from $SSH_CLIENT"

# 显示菜单
cat << EOF
=== Jump Server Menu ===
1) Connect to prod-web1
2) Connect to prod-web2
3) Connect to prod-db1
4) Exit
========================
EOF

read -p "Select option: " option

case $option in
    1)
        ssh deploy@10.0.1.101
        ;;
    2)
        ssh deploy@10.0.1.102
        ;;
    3)
        ssh deploy@10.0.2.101
        ;;
    4)
        exit 0
        ;;
    *)
        echo "Invalid option"
        exit 1
        ;;
esac

12.4 使用 ProxyJump 连接

客户端配置 ~/.ssh/config

   sshconfig# 跳板机
Host jump
    HostName jump.example.com
    Port 22222
    User jump_user
    IdentityFile ~/.ssh/id_ed25519_jump

# 通过跳板机访问内网服务器
Host prod-web1
    HostName 10.0.1.101
    User deploy
    Port 22
    ProxyJump jump
    IdentityFile ~/.ssh/id_ed25519_prod

连接:

   bash# 一条命令连接到内网服务器
ssh prod-web1

# 相当于
ssh -J jump_user@jump.example.com:22222 deploy@10.0.1.101

常用命令

SSH 密钥管理

   bash# 生成密钥
ssh-keygen -t ed25519 -C "your_email@example.com"
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

# 上传公钥
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server-ip

# 查看密钥指纹
ssh-keygen -l -f ~/.ssh/id_ed25519.pub

# 修改密钥密码
ssh-keygen -p -f ~/.ssh/id_ed25519

# 测试连接
ssh -v user@server-ip

SSH 服务管理

   bash# 检查配置
sshd -t

# 重新加载配置
systemctl reload sshd

# 重启服务
systemctl restart sshd

# 查看状态
systemctl status sshd

# 查看日志
journalctl -u sshd -f
tail -f /var/log/secure

fail2ban 管理

   bash# 查看状态
fail2ban-client status
fail2ban-client status sshd

# 解封 IP
fail2ban-client set sshd unbanip 1.2.3.4

# 封禁 IP
fail2ban-client set sshd banip 1.2.3.4

# 重新加载配置
fail2ban-client reload

日志分析

   bash# 查看登录成功日志
grep "Accepted" /var/log/secure

# 查看登录失败日志
grep "Failed" /var/log/secure

# 统计失败登录次数
grep "Failed password" /var/log/secure | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn

# 查看当前登录用户
w
who

# 查看登录历史
last
lastlog

配置示例

完整的配置示例已在实战步骤中给出。

风险提醒

高风险操作

禁用密码认证

   bash# 风险:如果密钥未配置或丢失,将无法登录
# 操作前:确保密钥已配置并测试成功
# 操作前:保留至少一个已登录的会话
# 操作:修改 sshd_config,设置 PasswordAuthentication no
# 回滚:恢复配置,重新加载服务

修改 SSH 端口

   bash# 风险:防火墙未同步修改,导致无法连接
# 操作前:确保防火墙规则正确
# 操作前:保留至少一个已登录的会话
# 操作:修改 sshd_config,设置 Port 22222
# 回滚:恢复配置,重新加载服务

禁止 root 登录

   bash# 风险:如果普通用户未配置 sudo,将无法管理服务器
# 操作前:确保普通用户已配置 sudo 权限
# 操作前:测试普通用户可以 sudo 执行命令
# 操作:修改 sshd_config,设置 PermitRootLogin no
# 回滚:恢复配置,重新加载服务

配置防火墙

   bash# 风险:错误的防火墙规则可能导致无法连接
# 操作前:保留至少一个已登录的会话
# 操作前:在测试环境验证规则
# 操作:添加防火墙规则,允许特定 IP 访问 SSH
# 回滚:清除规则,恢复默认策略

常见误区

误区 1:禁用密码后立即关闭当前会话

应该保留当前会话,使用新会话测试密钥登录,确认无误后再关闭。

误区 2:私钥权限设置为 644

私钥权限必须为 600,否则 SSH 会拒绝使用该密钥。

误区 3:在容器内运行 SSH

容器内运行 SSH 不符合容器设计理念,且安全性差。应该使用 docker exec 或 kubectl exec 进入容器。

误区 4:所有用户都配置 NOPASSWD sudo

NOPASSWD: ALL 风险较大,应仅在自动化场景使用。生产环境建议要求输入密码。

误区 5:修改 SSH 配置后直接重启服务

应该使用 systemctl reload sshd 重新加载配置,而非 restart,避免中断现有连接。

验证方式

验证密钥登录

   bash# 测试密钥登录
ssh -i ~/.ssh/id_ed25519 user@server-ip

# 应该不提示输入密码(或仅提示密钥密码)

验证密码登录已禁用

   bash# 尝试密码登录
ssh user@server-ip

# 应该提示 Permission denied (publickey)

验证 root 登录已禁止

   bash# 尝试 root 登录
ssh root@server-ip

# 应该提示 Permission denied (publickey)

验证防火墙规则

   bash# 从允许的 IP 测试
ssh user@server-ip
# 应该成功

# 从不允许的 IP 测试
ssh user@server-ip
# 应该超时或被拒绝

验证 fail2ban 工作

   bash# 故意输错密码 3 次
ssh user@server-ip

# 查看是否被封禁
fail2ban-client status sshd

回滚方案

SSH 配置回滚

   bash# 恢复备份
cp /etc/ssh/sshd_config.backup /etc/ssh/sshd_config

# 检查配置
sshd -t

# 重新加载
systemctl reload sshd

防火墙规则回滚

   bash# iptables 回滚
iptables-restore < /etc/iptables/rules.v4.backup

# firewalld 回滚
firewall-cmd --reload

fail2ban 回滚

   bash# 停止服务
systemctl stop fail2ban

# 清空封禁列表
rm -f /var/lib/fail2ban/*

# 恢复配置
cp /etc/fail2ban/jail.local.backup /etc/fail2ban/jail.local

# 重启服务
systemctl start fail2ban

生产环境注意事项

操作前检查

  1. 备份当前配置
  2. 保留至少一个已登录的会话
  3. 准备回滚方案
  4. 在测试环境验证
  5. 通知相关团队

操作中注意

  1. 逐项配置,每项配置后测试
  2. 使用 systemctl reload 而非 restart
  3. 随时准备回滚
  4. 记录所有操作

操作后验证

  1. 测试密钥登录
  2. 测试密码登录(应被拒绝)
  3. 测试防火墙规则
  4. 测试 fail2ban
  5. 查看日志

持续维护

  1. 定期更新密钥
  2. 定期检查日志
  3. 定期更新 SSH 版本
  4. 定期审计用户权限
  5. 定期测试备份恢复

总结

SSH 安全加固是服务器安全的基础,需要从多个层面进行防护:

  1. 认证加固:禁用密码登录,启用密钥认证
  2. 访问控制:限制登录用户和来源 IP,禁止 root 直接登录
  3. 网络防护:修改默认端口,配置防火墙,使用 fail2ban
  4. 权限管理:配置 sudo 权限,使用跳板机
  5. 审计日志:记录所有 SSH 操作,定期审计
  6. 持续维护:定期更新密钥,定期检查配置

关键配置:

  • PasswordAuthentication no:禁用密码认证
  • PermitRootLogin no:禁止 root 登录
  • PubkeyAuthentication yes:启用密钥认证
  • AllowUsers:限制登录用户
  • Port:修改默认端口(可选)

安全是一个持续的过程,需要不断监控、审计和改进。

SSH 安全加固不是一劳永逸的,需要根据实际情况调整配置,平衡安全和易用性,确保服务器安全可控。

图片

文末福利

Linux SSH 安全加固:密钥登录、权限和访问限制插图1

本文链接:https://www.yunweipai.com/archives/49399

下一篇:

网友评论comments

发表回复

您的电子邮箱地址不会被公开。

暂无评论

Copyright © 2012-2022 YUNWEIPAI.COM - 运维派 京ICP备16064699号-6
扫二维码
扫二维码
返回顶部