# SSH 远程访问

URL: https://caijiao.org/rockylinux/ssh-access
Source: docs/rockylinux/ssh-access.md
Description: 详细介绍 Rocky Linux 中 SSH 服务的配置、密钥认证、安全加固以及远程访问最佳实践

SSH（Secure Shell）是一种加密网络协议，用于在不安全的网络上安全地执行网络服务。它提供了强大的身份验证和加密通信功能，是 Rocky Linux 系统管理中远程访问服务器的标准方式。本教程将详细介绍 SSH 服务的配置、密钥认证、安全加固以及远程访问最佳实践。

## SSH 概述

SSH 协议主要提供以下功能：

1. **安全的远程命令执行**：在远程服务器上安全地运行命令
2. **安全文件传输**：通过 SFTP（SSH 文件传输协议）或 SCP（安全复制）安全传输文件
3. **端口转发**：安全地隧道化其他网络连接
4. **X11 转发**：安全地转发图形界面应用程序
5. **安全隧道**：为其他协议提供加密通道

在 Rocky Linux 中，默认使用的 SSH 服务器实现是 OpenSSH，它是开源的 SSH 协议实现。

## 安装和启动 SSH 服务

### 检查 SSH 服务状态

```bash
# 检查 SSH 服务状态
systemctl status sshd

# 检查 SSH 服务是否已启用开机自启
systemctl is-enabled sshd
```

### 安装 SSH 服务（如果尚未安装）

```bash
# 安装 OpenSSH 服务器
sudo dnf install openssh-server -y

# 安装 OpenSSH 客户端（用于连接其他 SSH 服务器）
sudo dnf install openssh-clients -y
```

### 启动和启用 SSH 服务

```bash
# 启动 SSH 服务
sudo systemctl start sshd

# 设置 SSH 服务开机自启
sudo systemctl enable sshd
```

### 配置防火墙允许 SSH 连接

```bash
# 允许 SSH 服务通过防火墙
sudo firewall-cmd --permanent --add-service=ssh

# 重新加载防火墙规则
sudo firewall-cmd --reload
```

## SSH 客户端使用

### 基本 SSH 连接

```bash
# 基本连接语法
ssh username@hostname_or_ip

# 示例：连接到 IP 为 192.168.1.100 的服务器，用户名为 admin
ssh admin@192.168.1.100

# 指定端口连接（默认端口为 22）
ssh -p 2222 username@hostname_or_ip
```

### 使用 SSH 密钥进行身份验证

#### 生成 SSH 密钥对

在客户端机器上生成 SSH 密钥对：

```bash
# 生成 RSA 密钥对（默认）
ssh-keygen -t rsa -b 4096

# 生成 ED25519 密钥对（更安全的选择）
ssh-keygen -t ed25519
```

生成密钥时，可以选择设置密钥的保存位置和密码短语（passphrase）。密码短语提供了额外的安全层，即使私钥被泄露，没有密码短语也无法使用。

#### 将公钥复制到远程服务器

```bash
# 使用 ssh-copy-id 工具复制公钥
ssh-copy-id username@hostname_or_ip

# 或者手动复制公钥
cat ~/.ssh/id_rsa.pub | ssh username@hostname_or_ip "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
```

#### 使用密钥进行连接

```bash
# 基本连接（默认会使用 ~/.ssh/id_rsa 或 ~/.ssh/id_ed25519）
ssh username@hostname_or_ip

# 指定私钥文件
ssh -i ~/.ssh/my_private_key username@hostname_or_ip
```

### 高级 SSH 客户端选项

```bash
# 启用压缩
ssh -C username@hostname_or_ip

# 启用 X11 转发（图形界面转发）
ssh -X username@hostname_or_ip

# 启用信任的 X11 转发（更快但安全性较低）
ssh -Y username@hostname_or_ip

# 在连接时执行命令并退出
ssh username@hostname_or_ip "ls -la"

# 使用指定的配置文件
ssh -F ~/.ssh/my_config username@hostname_or_ip
```

### 创建 SSH 配置文件

为了简化 SSH 连接，可以创建一个 SSH 配置文件：

```bash
vim ~/.ssh/config
```

添加以下内容：

```
# 服务器别名配置
Host server1
    HostName 192.168.1.100
    User admin
    Port 22
    IdentityFile ~/.ssh/id_rsa
    Compression yes
    ForwardX11 yes

Host server2
    HostName example.com
    User root
    Port 2222
    IdentityFile ~/.ssh/id_ed25519
```

设置正确的权限：

```bash
chmod 600 ~/.ssh/config
```

现在可以使用别名连接：

```bash
ssh server1
ssh server2
```

## SSH 服务器配置

SSH 服务器的主配置文件是 `/etc/ssh/sshd_config`。在修改前，建议先备份原始配置：

```bash
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
```

### 编辑 SSH 服务器配置

```bash
sudo vim /etc/ssh/sshd_config
```

### 基本配置选项

#### 修改默认端口

```
# 将默认端口 22 改为其他端口，例如 2222
Port 2222
```

#### 限制允许的用户

```
# 只允许特定用户登录
AllowUsers admin user1 user2

# 只允许特定用户组登录
AllowGroups admins developers

# 禁止特定用户登录
DenyUsers guest test

# 禁止特定用户组登录
DenyGroups guests testusers
```

#### 禁用 root 直接登录

```
# 禁止 root 用户直接登录
PermitRootLogin no

# 允许 root 用户通过密钥登录但禁止密码登录
PermitRootLogin prohibit-password
```

#### 密码认证设置

```
# 禁用密码认证（仅使用密钥认证）
PasswordAuthentication no

# 启用密码认证
PasswordAuthentication yes

# 禁用空密码
PermitEmptyPasswords no

# 设置密码尝试次数
MaxAuthTries 3
```

#### 密钥认证设置

```
# 启用公钥认证
PubkeyAuthentication yes

# 指定授权密钥文件
AuthorizedKeysFile .ssh/authorized_keys

# 启用挑战响应认证
ChallengeResponseAuthentication no
```

#### 登录尝试限制

```
# 设置登录宽限期（秒）
LoginGraceTime 30

# 最大同时连接数
MaxStartups 10:30:100
```

#### 其他安全设置

```
# 禁用 X11 转发
X11Forwarding no

# 禁用 TCP 转发
AllowTcpForwarding no

# 禁用 SSH 代理转发
AllowAgentForwarding no

# 禁用 PAM 认证
UsePAM yes

# 禁用子系统（如 sftp）
# Subsystem sftp /usr/libexec/openssh/sftp-server
```

### 应用配置更改

修改配置后，需要重启 SSH 服务以应用更改：

```bash
# 测试配置语法是否正确
sudo sshd -t

# 重启 SSH 服务
sudo systemctl restart sshd
```

## SSH 安全加固

### 禁用不安全的 SSH 协议版本

确保仅使用 SSH 协议 2，在 `sshd_config` 中添加：

```
# 仅使用 SSH 协议 2
Protocol 2
```

### 限制登录尝试次数

结合使用 `fail2ban` 可以有效防止暴力破解攻击：

```bash
# 安装 fail2ban
sudo dnf install epel-release -y
sudo dnf install fail2ban fail2ban-systemd -y

# 创建 fail2ban 配置文件
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

# 编辑 fail2ban 配置
sudo vim /etc/fail2ban/jail.local
```

修改 SSH 相关配置：

```ini
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
```

启动 fail2ban 服务：

```bash
# 启动 fail2ban 服务
sudo systemctl start fail2ban

# 设置 fail2ban 开机自启
sudo systemctl enable fail2ban

# 查看 fail2ban 状态
sudo fail2ban-client status
sudo fail2ban-client status sshd
```

### 使用防火墙限制 SSH 访问

除了允许 SSH 服务外，还可以限制只接受来自特定 IP 地址或网段的连接：

```bash
# 只允许来自 192.168.1.0/24 网段的 SSH 连接
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" service name="ssh" accept'

# 移除默认的 SSH 服务允许规则
sudo firewall-cmd --permanent --remove-service=ssh

# 重新加载防火墙规则
sudo firewall-cmd --reload
```

### 更改 SSH 横幅

可以自定义 SSH 登录横幅，显示警告信息：

```bash
# 创建横幅文件
sudo vim /etc/ssh/banner
```

添加警告内容：

```
########################################################
# 警告：这是一个私有系统。未经授权，禁止访问或使用！   #
# 所有活动将被记录并可能接受审查。                     #
########################################################
```

在 `sshd_config` 中启用横幅：

```
# 启用登录横幅
Banner /etc/ssh/banner
```

重启 SSH 服务：

```bash
sudo systemctl restart sshd
```

### 定期轮换 SSH 主机密钥

定期轮换 SSH 主机密钥可以增强安全性：

```bash
# 备份现有密钥
sudo mkdir -p /etc/ssh/old_keys
sudo mv /etc/ssh/ssh_host_* /etc/ssh/old_keys/

# 重新生成主机密钥
sudo ssh-keygen -A

# 重启 SSH 服务
sudo systemctl restart sshd

# 通知用户更新 known_hosts 文件
```

## SSH 隧道和端口转发

### 本地端口转发

将本地端口转发到远程服务器：

```bash
# 将本地 8080 端口转发到远程服务器的 80 端口
ssh -L 8080:localhost:80 username@remote_server
```

现在访问 `http://localhost:8080` 就相当于访问远程服务器的 80 端口。

### 远程端口转发

将远程服务器端口转发到本地：

```bash
# 将远程服务器的 8080 端口转发到本地的 80 端口
ssh -R 8080:localhost:80 username@remote_server
```

### 动态端口转发（SOCKS 代理）

创建一个 SOCKS 代理：

```bash
# 创建本地 SOCKS 代理在端口 1080
ssh -D 1080 username@remote_server
```

然后在浏览器或其他应用程序中配置 SOCKS 代理为 `localhost:1080`。

### 使用 SSH 隧道挂载远程文件系统

结合 SSHFS 使用 SSH 隧道挂载远程文件系统：

```bash
# 安装 SSHFS
sudo dnf install fuse-sshfs -y

# 创建本地挂载点
mkdir ~/remote_files

# 挂载远程文件系统
sshfs username@remote_server:/path/to/remote/directory ~/remote_files

# 卸载远程文件系统
fusermount -u ~/remote_files
```

## SSH 会话管理

### 保持 SSH 会话活动

在 `~/.ssh/config` 或 `/etc/ssh/ssh_config` 中添加以下内容以防止连接超时：

```
Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3
```

### 使用 screen 或 tmux 管理长期运行的任务

```bash
# 安装 screen
sudo dnf install screen -y

# 启动 screen 会话
screen -S session_name

# 分离会话
按 Ctrl+A，然后按 D

# 列出所有会话
screen -ls

# 重新连接会话
screen -r session_name
```

使用 tmux：

```bash
# 安装 tmux
sudo dnf install tmux -y

# 启动 tmux 会话
tmux new -s session_name

# 分离会话
按 Ctrl+B，然后按 D

# 列出所有会话
tmux ls

# 重新连接会话
tmux attach -t session_name
```

## SSH 密钥管理

### SSH 代理（ssh-agent）

使用 ssh-agent 可以避免频繁输入密钥密码短语：

```bash
# 启动 ssh-agent
eval $(ssh-agent -s)

# 添加私钥到代理
ssh-add ~/.ssh/id_rsa

# 查看已添加的密钥
ssh-add -l

# 移除密钥
ssh-add -d ~/.ssh/id_rsa

# 清空所有密钥
ssh-add -D
```

### 密钥权限设置

确保 SSH 密钥文件具有正确的权限：

```bash
# 设置私钥权限
chmod 600 ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_ed25519

# 设置公钥权限
chmod 644 ~/.ssh/id_rsa.pub
chmod 644 ~/.ssh/id_ed25519.pub

# 设置 authorized_keys 权限
chmod 600 ~/.ssh/authorized_keys

# 设置 .ssh 目录权限
chmod 700 ~/.ssh
```

## SSH 常见问题排查

### 连接被拒绝

如果收到 "Connection refused" 错误：

1. 检查 SSH 服务是否正在运行：

   ```bash
   sudo systemctl status sshd
   ```

2. 检查防火墙是否允许 SSH 连接：

   ```bash
   sudo firewall-cmd --list-services
   ```

3. 确认 SSH 配置中的端口设置：
   ```bash
   sudo grep Port /etc/ssh/sshd_config
   ```

### 权限被拒绝（publickey）

如果收到 "Permission denied (publickey)" 错误：

1. 检查客户端是否使用了正确的私钥：

   ```bash
   ssh -v username@hostname
   ```

2. 验证服务器上的 authorized_keys 文件是否包含正确的公钥：

   ```bash
   cat ~/.ssh/authorized_keys
   ```

3. 确保 authorized_keys 文件权限正确：

   ```bash
   chmod 600 ~/.ssh/authorized_keys
   ```

4. 检查 SELinux 上下文（如果启用了 SELinux）：
   ```bash
   restorecon -Rv ~/.ssh
   ```

### 连接超时

如果连接经常超时：

1. 配置客户端保持活动状态：

   ```
   # 在 ~/.ssh/config 中添加
   ServerAliveInterval 60
   ```

2. 配置服务器端保持活动状态：
   ```
   # 在 /etc/ssh/sshd_config 中添加
   ClientAliveInterval 60
   ClientAliveCountMax 3
   ```

## SSH 最佳实践

1. **使用密钥认证代替密码认证**：密钥认证比密码认证更安全，不易受到暴力破解攻击。

2. **禁用 root 直接登录**：始终使用普通用户登录，然后通过 sudo 执行需要特权的操作。

3. **更改默认 SSH 端口**：虽然这不是完整的安全解决方案，但可以减少大量的自动扫描和攻击。

4. **限制允许登录的用户和 IP**：仅允许需要访问的用户和 IP 地址连接到 SSH 服务。

5. **使用 fail2ban 防止暴力破解**：自动阻止频繁失败的登录尝试。

6. **定期更新 SSH 软件**：确保安装最新的安全补丁。

7. **使用强密码短语保护私钥**：即使私钥被泄露，没有密码短语也无法使用。

8. **定期轮换密钥**：定期更换 SSH 密钥可以减少长期密钥泄露的风险。

9. **使用防火墙限制 SSH 访问**：结合使用防火墙规则进一步限制 SSH 访问。

10. **监控 SSH 登录活动**：定期检查 SSH 登录日志，及时发现异常活动。

## 总结

SSH 是 Rocky Linux 系统管理中不可或缺的工具，提供了安全的远程访问能力。本教程详细介绍了 SSH 服务的安装配置、密钥认证、安全加固、端口转发以及常见问题的排查方法。

通过正确配置和使用 SSH，您可以安全地管理远程服务器，执行命令，传输文件，并保护敏感数据免受网络窃听和攻击。遵循本教程中的最佳实践，可以大大提高系统的安全性，减少潜在的安全风险。

记住，安全是一个持续的过程，定期审查和更新 SSH 配置，以及保持软件的最新状态，是维护安全环境的关键。
