> ssh 是一个非常常用的工具,通常用来登录到远程主机上,不过 ssh 不仅仅只能用来登录,还能执行远程命令,或者进行多种的端口转发
## 基本使用
#### 登录到远程主机
```bash
$ ssh <user>@<remote-ip>
```
ssh 默认连接的端口是 `22`,如果 ssh server 监听的其他端口的话
那么可以使用 `-p <port>`来指定端口
如果使用本地当前用户名登录的话,也可以省略 `<user>@`,只需要 `<remote-ip>`即可
**如何查看 ssh server 监听的地址**
```bash
# 远程主机上
$ netstat -tlnp | grep sshd
```
#### 如何免密登录
使用 ssh 登录时,通常会需要输入密码,总会感觉不是很安全,比如让别人协助登录到主机上,就需要把密码告诉他
如果使用公钥认证的话,就只需要登录人提供一下公钥,而不需要告诉他密码了
**查看 ssh server 是否支持公钥认证**
```bash
# 远程主机中
$ cat /etc/ssh/sshd_config | grep Pub
#PubkeyAuthentication yes
```
默认为开启公钥认证,如果为 no 的话就需要修改为 yes,然后重启 ssh server
**查看一下本地主机 ~/.ssh 目录下是否存在 rsa 秘钥(`id_rsa.pub`,`id_rsa`)**
**没有的话使用 `ssh-keygen` 生成秘钥,询问输入回车就行**
```bash
[iceber@localhost ~]$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/iceber/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/iceber/.ssh/id_rsa.
Your public key has been saved in /home/iceber/.ssh/id_rsa.pub.
The key fingerprint is:
e7:af:48:91:e7:61:c4:0b:c2:11:74:0d:1f:56:61:13 iceber@localhost.localdomain
The key's randomart image is:
+--[ RSA 2048]----+
| .+.ooo.Eo |
| . o +.o . |
| o . + |
| . + . |
| S * |
| B . |
| . o |
| . . . |
| . ... |
+-----------------+
```
**使用 `ssh-copy-id` 将公钥记录到到远程主机上**
```bash
$ ssh-copy-id <user>@<remote-ip>
```
> 一般主机中都会有 ssh-copy-id 命令,如果不存在的话,可以手动将公钥添加到远端主机中
> ```bash
> $ ssh <user>@<remote-ip> 'mkdir -p .ssh && cat >> .ssh/authorized_keys' < ~/.ssh/id_rsa.pub
> ```
> 需要注意 `~/.ssh` 目录的权限必须是 `700`,`~/.ssh/authorized_keys` 的权限必须是 `600` 或者 `644` ,否则会出现异常
远程主机信任该公钥后,就不需要输入密码啦
##### 使用其他秘钥
ssh 会默认使用 `~/.ssh/id_rsa` 和 `~/.ssh/id_rsa.pub`,如果想要使用其他的秘钥文件怎么呢
**在执行 `ssh-keygen` 时,会要求选择秘钥的路径,输入新的秘钥路径**
```
Enter file in which to save the key (/home/iceber/.ssh/id_rsa): /home/iceber/.ssh/custom_rsa
```
~/.ssh 中就会生成私钥`custom_rsa` 和公钥 `custom_rsa.pub`
**`ssh-copy-id -i <公钥路径> <user>@<remote-ip>` 将指定的公钥发送给服务端**
**ssh 使用 `-i <私钥路径> ` 来指定私钥**
#### 禁止密码登录
既然公钥可以登录了,有时为了安全考虑,也就不需要密码登陆了
修改 ssh server 配置 `/etc/ssh/sshd_config`
```bash
# /etc/ssh/sshd_config
PasswordAuthentication no # 关闭密码验证
```
#### 配置远程主机,使用别名登录
虽然可以免密登录的,但是每次登录还是需要配置 `user`,`remote-ip`,感觉好麻烦
在 `~/.ssh/config` 中可以配置远程主机的信息
```bash
# ~/.ssh/config
Host iceber
HostName 10.10.10.100
User iceber
```
可以直接使用 `ssh iceber` 登录了
> *`Host * ` 相当于全局配置*
还可以配置一些其他信息
* **`Port <port>`** 远程主机的 ssh server port
* **`ServerAliveInterval <seconds>`** client 会每隔多少秒向 server 发送一次请求,防止和服务器的连接断开
* **`IdentityFile <path>`** 秘钥路径,rsa 的秘钥地址 (~/.ssh/id_rsa)
## 端口转发
ssh 不止能用来登录或者执行远程命令,还是用做端口转发
ssh 的端口转发分为三种 `本地转发`,`远程转发`,`动态转发`
**在使用端口转发时,通常会使用到 `-N`,`-f` 两个 flag**
* `-N` 表示不需要执行任何命令,用于端口转发
* `-f` 表示在后台运行,不需要登录到远端主机上
### 本地转发
**`本地转发`是指将发送到本地端口的请求发送到远端主机上**
**`ssh -Nf -L <本地地址>:<本地端口>:<远程主机目标地址>:<远程主机目标端口> <user>@<remote-ip>`**
访问 `<本地地址>:<本地端口>`,数据会转发到 `<remote-ip>` 主机的`<远程主机目标地址>:<远程主机目标端口>`中
*`<本地地址>` 可以省略,默认为 127.0.0.1*
##### 场景
远端主机(10.10.10.100)中运行一个 http server,但是他只监听了 localhost:8080 地址,但是我想在本地访问这个地址,该怎么办
```bash
ssh -Nf -L 8000:127.0.0.1:8080 iceber@10.10.10.100
```
这时通过本地 127.0.0.1:8000 就可以访问到 10.10.10.100 机器中的本地服务了
> 有时 MySQL 会限制登录的 ip,这时就可以使用本地端口转发来访问了
### 远程转发
**`远程转发`是指将发送到远端主机的请求转发到本地的目标端口**
**`ssh -Nf -R <远程主机地址>:<远程主机端口>:<本地目标地址>:<本地目标端口> <user>@<remote-ip>`**
在本地执行 ssh 远程转发命令,访问 `<远程主机地址>:<远程主机端口>`时,请求会转发到本地`<本地目标地址>:<本地目标端口>`
`<远程主机地址>:` 可以省略,默认为 127.0.0.1,可以设置为 0.0.0.0 在所有网卡上建立转发
**转发远程主机的非 localhost ip 时,需要修改 `/etc/ssh/sshd_config`**
```
# /etc/ssh/sshd_config
GatewayPorts yes
```
##### 场景
**将局域网中的 ssh 通过远程主机暴露给外网**
在局域网外,我们无法通过 ssh 连接到局域网中的主机,但是如果把局域网主机中将 ssh 端口和可以外网访问的远程主机端口建立远程转发,那么就可以通过远程主机访问局域网主机了
```bash
ssh -Nf R 10022:localhost:22 iceber@<remote-ip>
```
将远程主机的 localhost:10022 端口接收的请求转发到本地 localhost:22 中
这时在外网登录远程主机,然后 ssh -p 10022 <user>@localhost 就可以登录到局域网中了
> 不建议局域网中 ssh 端口直接和远程主机的外部 ip 建立端口映射
### 动态转发
**`动态转发`会在本地监听端口,所有发送到该端口的请求都转发到远程主机中,由远程主机来执行请求**
**`ssh -Nf -D <本地地址>:<本地端口> <user>@<remote-ip>`**
可以用来做 SOCKS5 代理,如果远程主机可以访问外网,这样通过把浏览器的代理服务器设置为 socks5://127.0.0.1:10080 就可以让远程主机来执行请求,同样可以访问到外网了
```bash
$ ssh -Nf -D 10080 iceber@<remote-ip>
```
## 其他设置
> 登录日志可以通过 /var/log/secure 来查看
### 配置 SSH 登录提醒
```bash
# /etc/ssh/sshd_config
Banner <path>
```
可以在密码输入前会打印 `<path>` 中的内容
> 登录后同样会有一些提示内容,这些提示内容再 `/etc/update-motd.d`中(ubuntu)
### ssh server 配置
ssh server 的配置文件时 `/etc/ssh/sshd_config`
常用的一些配置项:
* `Port <port>` 设置ssh server 端口
* `ListenAddress 0.0.0.0` 监听地址
* `PasswordAuthentication no` 关闭密码验证
* `PubkeyAuthentication yes` 可以使用公钥登录
* `RSAAuthentication yes` 只允许RSA安全验证
* `PermitRootLogin yes` 运行 root 登录
* `PermitEmptyPasswords no` 不允许空密码登录
* `LoginGraceTime 2m` 用户不能成功登录,2m 后断开连接
* `PrintLastLog yes` 登录后打印上次登录信息

SSH 用法进阶 —— 免密登录与端口转发