ssh 通过跳板机登陆远程服务器

发布时间 2023-08-05 13:33:15作者: 星宇x

开心一刻

       “老师,你认识元芳吗?”
       “不”
       “你认识程祖吗?”
       “不”
       “那你知道他们的姐是谁吗?”
       “不”
       “老师你都不知道,我怎么知道:原方程组的解是______?”
       “……”

写在前面

       公司服务器只能用内网访问,想要登陆内网服务器只能先登陆跳板机,然后在跳板机登陆内网服务器。不过总想能省点事,从本地直接登陆内网服务器,从网上找到通过 ssh 借助跳板机登陆的文章,自己尝试了之后觉得非常香,就在自己的播客中记录一下,其实就是懒,哈哈哈哈哈。

ProxyCommand

       借助 ssh 的 -o 选项指定一条 ProxyCommand 命令,ProxyCommand 内部就是登陆跳板机的ssh命令,

命令格式如下:

ssh username@目标机器IP -p 22 -o ProxyCommand='ssh -p 22 username@跳板机IP -W %h:%p'

或者

ssh username@目标机器IP -p 22 -o ProxyCommand='ssh -p 22 username@跳板机IP nc -q 1 -w 30 %h %p'

说明:

ProxyCommand 后面跟随的命令放在那个位置不重要,和 -o 选项一起出现即可,后面跟的是一个完整的 ssh 命令;
第二种格式使用登陆跳板机后又使用 nc 命令连接,属于 ssh 登陆远程服务器之后执行一条命令的用法,效果与第一种一样

       命令实际使用起来会比较长,因此 ssh 提供了一个配置文件,可以将相关配置内容放到 ~/.ssh/config 中,例如:

Host 目标机器ip
  # 调试容器登录配置
  Port 22
  ProxyCommand ssh -o "ControlMaster=no" 跳板机IP nc -q 1 -w 30 %h %p

       配置好后,就可以使用 ssh username@目标机器IP 进行登陆。

       上述配置便能登陆目标服务器,并处于目标用户的家目录下,而我在使用时需要进行特定的项目目录并且要导入一些环境变量,因此对于配置文件做了一些修改,以便我登陆服务器后就不必再导入相关的环境变量了,当然进入服务器之后手动导入环境变量也是可以的。

Host 目标机器ip
  # 调试容器登录配置
  Port 22
  RequestTTY yes
  ProxyCommand ssh -o "ControlMaster=no" 跳板机IP nc -q 1 -w 30 %h %p
  RemoteCommand cd xxx ; bash --login

       上述配置中 RemoteCommand 是为了进行服务器后先执行某些命令,加入 bash --login 不仅是为了导入 /etc/profile 下的环境变量,同时也能停留在目标服务器中,没加 bash --login 将只会执行 cd 命令,然后退出。这里加入了 RequestTTY yes 是分配一个服务器终端,否则会报 mesg: ttyname failed: Inappropriate ioctl for device 的错误,如果不加 bash --login,那么 RequestTTY yes 应该也可以不加。

       上述配置也可以写成一条命令来执行,只不过会较长。

ProxyJump

       需要 OpenSSH 7.3 以上版本才可以使用 ProxyJump, 使用下列命令查看OpenSSH 版本:

ssh -V

ProxyJump 命令行使用方法:

ssh -J username@domain:port1,username@domain:port2  username@目标服务器IP -p 22

       可以直接使用上述命令通过跳板机直接登录内网机器,port 和 username 等选项可以不填,可根据需要进行填写。

       如果需要通过多个跳板机则以 , 分割:

ssh username@目标机器IP -p 22 -J username1@跳板机IP1:22,username2@跳板机IP2:22

       如果觉得每次都需要加上 -J 的配置很多麻烦,可以写到配置文件里。修改配置文件 ~.ssh\config,默认没有需要自己创建。增加以下内容:

Host tiaoban1    # 代表跳板机 1
    HostName 跳板机 1 的 IP
    Port 22    # ssh 连接端口
    User username1    # 跳板机 1 的用户名

Host tiaoban2    # 代表跳板机 2
    HostName 跳板机 2 的 IP
    Port 22    # ssh 连接端口
    User username2    # 跳板机 2 的用户名
Host 目标机器ip
  # 调试容器登录配置
  Port 22
  ProxyJump tianban1,tiaoban2

       ProxyJump 实现的效果和 ProxyCommand 实现的效果是一样的,不过 ProxyJump 使用起来要比 ProxyCommand 简单许多,尤其是在用多个跳板机进行跳转时,ProxyCommand 就会变得比较复杂。但是我目前还没有使用到多个跳板机,因此 ProxyJump 还没有尝试使用,不过先把使用方法贴在这里,以便后面使用是查看。

其他有用的命令

        1. 借助跳板机上传代码文件

scp -o "ProxyCommand ssh -p 22 root@10.182.34.52 nc -w 1 %h %p" -P 22 -r root@target.machine:/root/ .

如果 ~/.ssh/config 已有相关配置,则可以使用

scp root@target.machine:/root/ .

或者使用 rsync 上传文件

rsync -av -e 'ssh -o RemoteCommand=none' --delete-after ~/project_path/ root@10.152.34.233:/root --exclude=.git  2> /dev/null
  1. 借助跳板机执行远程服务器中的命令
ssh -o "ProxyCommand ssh -o \"ControlMaster=no\" gwpek. nc -q 1 -w 30 %h %p" -p 22 "root@${addr}" -o 'RemoteCommand pwd' &> /dev/null

这里执行远程服务器中的命令借助了 RemoteCommand ,不过这里执行完后就会退出,并不会停留在远程服务起中,其中远程服务器命令执行之后的结果可以直接打印到本地。
这里的命令有时候也可以这样写:

ssh -o "ProxyCommand ssh -o \"ControlMaster=no\" gwpek. nc -q 1 -w 30 %h %p" -p 22 "root@${addr}"  'pwd' &> /dev/null

ssh 执行远程服务器命令可以直接在最后把想要执行的命令写上去,但是我自己尝试了之后有时候在 terminal 中无法执行,但是放到脚本里执行没问题,具体原因也没定位出来。但是 RemoteCommand 是可以的,不管是直接执行还是放到脚本里执行。我估计 RemoteCommand 就是为了替换直接写命令的那种方式而加入的。

总结

       还是熟能生巧,要多踩些坑,才能更快解决碰到的问题。

参考