SSH 使用介绍

发布时间: 更新时间: 总字数:3326 阅读时间:7m 作者: IP上海 分享 网址

本文详细介绍SSH(Secure Shell Protocol)相关知识,如如何在一台服务器中,生成 ssh-key,并为不同地址配置不同 ssh key,该方法适合为不同 git client 配置不同 key。

介绍

high level
    +-------------------------+---------------------+
    | Authentication Protocol | Connection Protocol |
    +-------------------------+---------------------+
    |           Transport Layer Protocol            |
    +-----------------------------------------------+
    |              Underlying Connection            |
    +-----------------------------------------------+
low  level

部署 SSH

服务端

  • SSH 服务端是一个守护讲程 (daemon)sshd,用来响应来自客户端的连接请求和响应,一般包括公共密钥认证、密钥交换、对称密钥加密和非安全连接等
# 安装服务端
$ apt install openssh-server

$ dpkg -S `which sshd`
openssh-server: /usr/sbin/sshd

$ dpkg -L openssh-server

# 配置文件
$ tree /etc/ssh/
/etc/ssh/
├── moduli
├── ssh_config
├── ssh_config.d
├── sshd_config  # 配置文件
├── sshd_config.d
│   └── 50-cloud-init.conf
├── sshd_config.ucf-dist
├── ssh_host_dsa_key  # 下面 key 和 pub 是在启动时生成的,在第一次启动服务时自动生成
├── ssh_host_dsa_key.pub
├── ssh_host_ecdsa_key
├── ssh_host_ecdsa_key.pub
├── ssh_host_ed25519_key
├── ssh_host_ed25519_key.pub
├── ssh_host_rsa_key
├── ssh_host_rsa_key.pub
└── ssh_import_id

3 directories, 14 files

启动服务端

systemctl status ssh.service

# 启动前,可以使用以下命令检测配置文件是否合法
sshd -t /etc/ssh/sshd_config

客户端

  • SSH 客户端 包括:
    • ssh 远程登陆,软连接 slogin
    • scp 远程拷贝
    • sftp(Secure File Transfer Protocol, 安全文件传送协议) 等应用程序
# 安装客户端
$ apt install openssh-client

$ dpkg -S `which ssh`
openssh-client: /usr/bin/ssh

$ dpkg -L openssh-client | grep bin
/usr/bin
/usr/bin/scp
/usr/bin/sftp  # 安全FTP文件传输
/usr/bin/ssh
/usr/bin/ssh-add
/usr/bin/ssh-agent
/usr/bin/ssh-argv0
/usr/bin/ssh-copy-id
/usr/bin/ssh-keygen
/usr/bin/ssh-keyscan
/usr/bin/slogin

$ ls -lh /usr/bin/slogin
lrwxrwxrwx 1 root root 3 Feb 15 10:13 /usr/bin/slogin -> ssh

ssh-keygen 生成 ssh key

通常,要为多个邮箱账号分别生成公钥,公私钥都是放到~/.ssh下面,生成步骤如下:

$ ssh-keygen -t ed25519 -b 4096 -C "me@xiexianbin.cn"  # 推荐,比 rsa 短,安全性高
$ ssh-keygen -t rsa -C "me@xiexianbin.cn"  # 把这个文件命名为id_rsa_github,然后一路回车
$ ssh-keygen -t rsa -C "10972072@qq.com"   # 把这个文件命名为id_rsa_aliyun,然后一路回车
$ ssh-keygen -t rsa -b 4096 -C "me@xiexianbin.cn"

将 SSH 私钥增加到 ssh-agent:

ssh-add ~/.ssh/id_rsa

查看已经 add 的SSH KEY:

ssh-add -l

若报错:Could not open a connection to your authentication agent.,执行:

ssh-agent bash

PS:将 ~/.ssh/id_rsa.pub 添加到目标及其的 .ssh/authorized_keys 可以实现 ssh 证书登录。

修改key密码

ssh-keygen -f ~/.ssh/id_rsa -p

ssh-copy-id 分发公钥

ssh-copy-id $IP    #$IP为本虚机地址,按照提示输入yes 和密码,然后可以无密码登录服务器

上述过程,是将 id_rsa.pub 添加到对应主机的 ~/.ssh/authorized_keys 目录下。

多个服务器分别配置key

此时在~/.ssh下面生成了两对公私钥,把id_rsa_aliyun.pub的内容贴到aliyun的git服务的ssh keys中,把id_rsa_github.pub的内容贴到github的ssh keys中。然后touch一个配置文件:

touch ~/.ssh/config
chmod 600 ~/.ssh/*

最后在~/.ssh/config中添加如下内容即可:

host code.aliyun.com
    # user xiexianbin
    hostname code.aliyun.com
    port 22
    identityfile ~/.ssh/id_rsa_aliyun

host github.com
    User git
    hostname github.com
    port 22
    identityfile ~/.ssh/id_rsa_github
Host 10.0.0.* 10.0.1.*
  port 22
  IdentityFile ~/.ssh/id_rsa
  User root
  • 快捷登录
host vm1
    User root
    hostname 10.0.0.2
    port 22
    identityfile ~/.ssh/id_rsa

可以直接 ssh vm1 登录该机器。

测试

然后用ssh命令分别测试:

ssh -T git@github.com

调试

如果到这里你没有成功的话,可以 –debug,比如测试 github:

ssh -vT git@github.com

-v 是输出编译信息,然后根据编译信息自己去解决问题吧。

配置免确认

修改 ~/.ssh/config,内容如下:

UserKnownHostsFile=/dev/null
StrictHostKeyChecking=no
LogLevel=ERROR

修改权限:

chmod 400 ~/.ssh/config

ssh 免 hostkey check 登录:

sudo ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i .ssh/ssh_key.key ubuntu@10.0.0.1

自动登陆文件

cat 10.0.0.1
#!/bin/sh

user="root"
host=`basename $0`

ssh -i ~/.ssh/id_rsa $user@$host

TCP port or Unix socket 转发

man ssh 查看

本地端口转发

  • 目标:将远程主机服务监听的端口转发到本地
  • 参数
本地端口转发 ...
$ man ssh

     -C      Requests compression of all data (including stdin, stdout, stderr, and data for forwarded X11, TCP and
             UNIX-domain connections).  The compression algorithm is the same used by gzip(1).  Compression is de‐
             sirable on modem lines and other slow connections, but will only slow down things on fast networks.
             The default value can be set on a host-by-host basis in the configuration files; see the Compression
             option.

     -g      Allows remote hosts to connect to local forwarded ports.  If used on a multiplexed connection, then
             this option must be specified on the master process.

     -L [bind_address:]port:host:hostport
     -L [bind_address:]port:remote_socket
     -L local_socket:host:hostport
     -L local_socket:remote_socket
             Specifies that connections to the given TCP port or Unix socket on the local (client) host are to be
             forwarded to the given host and port, or Unix socket, on the remote side.  This works by allocating a
             socket to listen to either a TCP port on the local side, optionally bound to the specified
             bind_address, or to a Unix socket.  Whenever a connection is made to the local port or socket, the
             connection is forwarded over the secure channel, and a connection is made to either host port
             hostport, or the Unix socket remote_socket, from the remote machine.

             Port forwardings can also be specified in the configuration file.  Only the superuser can forward
             privileged ports.  IPv6 addresses can be specified by enclosing the address in square brackets.

             By default, the local port is bound in accordance with the GatewayPorts setting.  However, an explicit
             bind_address may be used to bind the connection to a specific address.  The bind_address of
             “localhost” indicates that the listening port be bound for local use only, while an empty address or
             ‘*’ indicates that the port should be available from all interfaces.

     -N      Do not execute a remote command.  This is useful for just forwarding ports.
  • 使用场景

    • 远程机器监听在 127.0.0.1:3306 的MySQL想在本地访问
    • 远程机器(到本地近通 22 端口)能访问的某个服务端口想在本地访问
  • 示例

# 远程机器启动本地服务
$ python -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

# 本地转发,监听在本地的 5000 端口
ssh -L 127.0.0.1:5000:127.0.0.1:8000 root@<server-ip>
# ssh -v -CNg -L 127.0.0.1:5000:127.0.0.1:8000 root@<server-ip> -p 22

# 本地查看 ssh 监听在 5000 端口
$ ss -lpn | grep 5000
tcp   LISTEN 0      128        127.0.0.1:5000      0.0.0.0:*    users:(("ssh",pid=133,fd=4))

# 访问本地的 5000 端口(等价于访问远程的 8000 端口)
$ curl -i -v 127.0.0.1:5000
*   Trying 127.0.0.1:5000...
* Connected to 127.0.0.1 (127.0.0.1) port 5000
...
< HTTP/1.0 200 OK

远程端口转发

  • 目标:将本地主机(或局域网)服务监听的端口转发到远程服务器
  • 参数
       -R [bind_address:]port:host:hostport
       -R [bind_address:]port:local_socket
       -R remote_socket:host:hostport
       -R remote_socket:local_socket
       -R [bind_address:]port

需要配合修改 /etc/ssh/sshd_configGatewayPorts yes

  • 使用场景

    • 远程服务器想访问本地监听在 127.0.0.1:8000 上的服务
  • 示例

# 本地启动本地服务
$ python -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

# 远程端口转发,监听在远程的 5000 端口
ssh -R 127.0.0.1:5000:127.0.0.1:8000 root@<server-ip>

# 远程查看 sshd 监听在 5000 端口
$ ss -lpn | grep 5000
tcp   LISTEN 0      128                                          127.0.0.1:5000             0.0.0.0:*    users:(("sshd",pid=31006,fd=6))

# 远程访问自己的 5000 端口(等价于访问客户端的 8000 端口)
$ curl -i -v 127.0.0.1:5000
*   Trying 127.0.0.1:5000...
* Connected to 127.0.0.1 (127.0.0.1) port 5000
...
< HTTP/1.0 200 OK
  • 扩展,也可利用 yum install autossh 实现

动态转发

  • 目标:将本地主机(或局域网)服务监听的端口转发到远程服务器
       -D [bind_address:]port
               Specifies a local “dynamic” application-level port forwarding.  This works by allocating a socket to
               listen to port on the local side, optionally bound to the specified bind_address.  Whenever  a  con‐
               nection  is made to this port, the connection is forwarded over the secure channel, and the applica‐
               tion protocol is then used to determine where to connect to from the remote machine.  Currently  the
               SOCKS4  and  SOCKS5 protocols are supported, and ssh will act as a SOCKS server.  Only root can for‐
               ward privileged ports.  Dynamic port forwardings can also be specified in the configuration file.

               IPv6 addresses can be specified by enclosing the address in square brackets.  Only the superuser can
               forward privileged ports.  By default, the local port is bound in accordance with  the  GatewayPorts
               setting.   However,  an  explicit  bind_address may be used to bind the connection to a specific ad‐
               dress.  The bind_address of “localhost” indicates that the listening port be  bound  for  local  use
               only, while an empty address or ‘*’ indicates that the port should be available from all interfaces.
  • 示例
# 本地创建 SOCKS 代理,且监听在 5000 端口
$ ssh -D 5000 root@192.168.179.159

# 本地监听 5000 端口
$ ss -lpn | grep 5000
tcp   LISTEN 0      128        127.0.0.1:5000      0.0.0.0:*    users:(("ssh",pid=279,fd=4))

# 本地指定代理,可以访问远程服务器可以访问的任意服务?
HTTP_PROXY=127.0.0.1:50000 curl 192.168.179.159:8000

高级用法

执行多个命令

ssh -CT -o BatchMode=yes c1

F&Q

ssh 链接慢

  • 修改:/etc/ssh/sshd_config
UseDNS no
# GSSAPI options, 使用 ssh -v xiexianbin@git.xiexianbin.cn 调试发现连接gssapi-with-mic消耗时间较长
GSSAPIAuthentication no
GSSAPICleanupCredentials no
  • w 命令查看当前ssh远程连接数,是否达到最大连接数
vim /etc/ssh/sshd_config
LoginGraceTime 2m   # 参数表示登录验证时间
MaxAuthTries 6      # 最大验证重试次数
MaxSessions 10      # 最大远程连接数
  • last 命令查看最近登录日志
  • /var/log/secure 系统安全日志
  • /etc/hosts.all/etc/hosts.deny查看限定的ip

ssh 连接超时中断

超时时,ssh console 的错误日志

client_loop: send disconnect: Broken pipe
  • 修复方式:客户端配置
  1. ssh 指定超时时长 ssh -o ServerAliveInterval=600 xxx
  2. 配置文件指定 echo "ServerAliveInterval 600" >>> ~/.ssh/config
  3. 或在 ~/.ssh/config 中配置
Host *
    ServerAliveInterval 600
  • 修复方式:服务器配置

服务器端,修改/etc/ssh/sshd_config,重启 sshd 后生效:

# 单位:秒,SSH 客户端不活动时间间隔
ClientAliveInterval  200

# SSH 服务器向客户端尝试发送活动消息的次数,超过该次数后将中断 SSH 连接
ClientAliveCountMax  3

禁用密码登录

编辑/etc/ssh/sshd_config,将PasswordAuthentication参数值修改为no

sed 's/#PasswordAuthentication yes/PasswordAuthentication no/g' -i /etc/ssh/sshd_config
systemctl restart ssh.service  # sshd.service

禁止提示 Warning: Permanently added ’’ (ED25519) to the list of known hosts.

Host *.mydomain.com
  StrictHostKeyChecking no
  UserKnownHostsFile /dev/null
  User foo
  LogLevel QUIET

# 或
ssh -o LogLevel=ERROR xxx
ssh -o LogLevel=quiet xxx

扩展

  • 其他的实现
    • dropbear 是 Matt Johnston 编写的一个软件包,提供与安全壳兼容的服务器和客户端
      • 它被设计为标准 OpenSSH 的替代品,适用于内存和处理器资源较少的环境,如嵌入式系统
      • 它是 OpenWrt 和其他路由器发行版的核心组件
      • 官网

参考

  1. https://en.wikipedia.org/wiki/Secure_Shell
Home Archives Categories Tags Statistics
本文总阅读量 次 本站总访问量 次 本站总访客数