SSH 通过跳板机连接服务器 | Ansible通过跳板机连接目标机器

前言

某些场景下,目标服务器只能通过特定的堡垒机(Bastion)或者叫跳板机(Jump Host)进行访问,有可能还涉及到多个跳板机。在这篇文章中,我们将演示如何使用跳板机进行 ssh 登录 与 Ansible 使用跳板机来访问目标服务器。

原理

我们可以通过一个或多个跳板机连接到另一台主机,以便客户端可以像直接连接一样。man ssh 文档有相关介绍

-J destination

Connect to the target host by first making a ssh connection to the jump host described by destination and then establishing a TCP forward‐ing to the ultimate destination from there. Multiple jump hops may be specified separated by comma characters. This is a shortcut to specify a ProxyJump configuration directive. Note that configuration directives supplied on the command-line generally apply to the desti‐nation host and not any specified jump hosts. Use ~/.ssh/config to specify configuration for jump hosts.

主要方法是使用 SSH 连接,使用 ProxyJump 指令,通过一台或多台跳转主机将 SSH 协议转发到目标主机上运行的 SSH 服务器。这是最安全的方法,因为加密是端到端的。除了进行任何其他加密之外,链的末端还会加密和解密彼此的流量。因此通过中间跳板主机的流量始终是加密的。但如果中间主机拒绝端口转发,则无法使用此方法。

当端口转发可用时,最简单的方法是在配置文件中(~/.ssh/config)使用 ProxyJump-J 作为运行时参数。-J 用法的一个示例是:

bash 复制代码
ssh -J user1@jump_host root@target_host

不过使用命令行这种方式,当跳板机和目标主机 key 不一样时会失败或者有其他特殊配置的时候,目前没有找到资料可以适配任何场景,建议还是使用配置文件方式。

在老的SSH版本中,-J 不可用。在这种情况下,可以使用 -W建立隧道方式来"反弹"通过跳板机的连接。

bash 复制代码
ssh -o ProxyCommand="ssh -W %h:%p user1@jump_host" root@target_host

搭建环境

我使用一台 vps 充当 Jump Host,在 vps 上部署两个 sshd docker 容器充当 Server 1 和Server 2 来简单模拟下面2个场景。

  1. 创建 Server 1,Server 2 相关文件目录
ssh 复制代码
mkdir ${PWD}/s1/{ssh,keys}/ -pv
mkdir ${PWD}/s2/{ssh,keys}/ -pv
  1. 创建 Server 1,Server 2 ssh-key
ruby 复制代码
root@zzwade:/data/ssh/s2/ssh# ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): /data/ssh/s2/ssh/id_rsa
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /data/ssh/s2/ssh/id_rsa
Your public key has been saved in /data/ssh/s2/ssh/id_rsa.pub
The key fingerprint is:
SHA256:hKjimWc9D780ziBR0UdQCSKpPAqCZ8GuEgQyzjz3fCk root@zzwade
The key's randomart image is:
+---[RSA 3072]----+
|=. ..o.o=o.      |
|=oo...oo o       |
|+*.o... o        |
|=+*.+  ..        |
|==o. E oS        |
|=.o o o          |
|.+ + = o         |
|  o . X .        |
|       *.        |
+----[SHA256]-----+
  1. 创建motd文件,该文件的主要作用是在用户登录系统时向其显示一些重要信息。这些信息可以是系统管理员自定义的消息、版权声明、系统状态信息等。
bash 复制代码
echo "Welcome to S2 container! " > s2/motd
echo "Welcome to S1 container! " > s1/motd

目录结构

ruby 复制代码
root@zzwade:/data/ssh# tree s2
s2
├── keys
├── motd
└── ssh
    ├── id_rsa
    └── id_rsa.pub

3 directories, 3 files
  1. 创建 docker-compose 文件,这里选用的 sshd 容器镜像如下,更多参数可参考:github.com/panubo/dock...,Server 1和 Server 2 ssh 端口暴露到宿主机(跳板机)22221 和 22222 端口,都设置成root用户直接登录
yaml 复制代码
services:
   s1:
     image: quay.io/panubo/sshd:1.6.0 
       #  restart: always
     ports:
       - "22221:22"
     volumes:
       - ${PWD}/s1/ssh/id_rsa.pub:/root/.ssh/authorized_keys:ro 
       - ${PWD}/s1/keys/:/etc/ssh/keys 
       - ${PWD}/s1/motd:/etc/motd 
     environment:
       - SSH_ENABLE_ROOT=true
   s2:
     image: quay.io/panubo/sshd:1.6.0 
       #  restart: always
     ports:
       - "22222:22"
     volumes:
       - ${PWD}/s2/ssh/id_rsa.pub:/root/.ssh/authorized_keys:ro 
       - ${PWD}/s2/keys/:/etc/ssh/keys 
       - ${PWD}/s2/motd:/etc/motd 
     environment:
       - SSH_ENABLE_ROOT=true
  1. 启动服务,测试Server 1和 Server 2 ssh 登录

使用跳板机登录

配置 User ~/.ssh/config文件,配置文件中的 IdentityFile配置项是登录到对应ssh 服务器的私钥,这些私钥文件都是在 User 服务器上。ProxyJump 就是上面说到的配置跳板机登录,可以配置多个跳板机,用逗号分隔。

bash 复制代码
Host jump                                                                                                                                                  
         HostName x.zwade.top                                                                                                                               
         User ubuntu                                                                                                                                        
         IdentityFile /data/tmp_keys/x_key                                                                                                                  
                                                                                                                                                            
Host s1                                                                                                                                                    
         HostName localhost                                                                                                                                 
         User root
         Port 22221
         ProxyJump jump                                                                                                                                     
         IdentityFile /data/tmp_keys/s1_key                                                                                                                 
                                                                                                                                                            
Host s2                                                                                                                                                    
         HostName localhost                                                                                                                                 
         User root
         Port 22222
         ProxyJump jump                                                                                                                                     
         IdentityFile /data/tmp_keys/s2_key

User -> Jump Host -> s1,s2

查看 s1, s2 ip 地址

ruby 复制代码
root@zzwade:/data/ssh# docker network inspect ssh_default 
[
    {
        "Name": "ssh_default",
        ...
        "Containers": {
            "c6477d969c75ce2e8fa529c53244249492f6f14c48930e7f5f10e59ae4855597": {
                "Name": "ssh-s2-1",
                "EndpointID": "d9f3e125521d50578ddfa2c2c58ef8ecda43c740a8c9f833245030e099860b9c",
                "MacAddress": "02:42:ac:12:00:03",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            },
            "fd7f5250e0ce6684cc75ac8860252c5b59686c547f096d1ff2b1788bbb8ee4b9": {
                "Name": "ssh-s1-1",
                "EndpointID": "fc0ee601a5e4f485a03aba28bb0b8157ee4c1d7a5c7325e9b146b9e8a8cd4810",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            }
        },
        ...
    }
]

创建另一个 ssh config 文件tmp_config,来实现 User -> Jump Host -> s1 -> s2

bash 复制代码
[root@z2024 tmp_keys]# cat tmp_config 
Host jump
        HostName x.zwade.top
        User ubuntu
        IdentityFile /data/tmp_keys/x_key

Host s1
        HostName 172.18.0.2
        User root
        Port 22
        ProxyJump jump
        IdentityFile /data/tmp_keys/s1_key

Host s2
        HostName s2
        User root
        Port 22
        ProxyJump s1
        IdentityFile /data/tmp_keys/s2_key

使用-F指定 ssh config 配置文件,测试下可否通过多个跳板机登录到 s2 上面是因为 s1 容器 sshd 没有打开 AllowTcpForwarding 配置,一般 linux sshd 服务默认是打开的。

配置下 s1 容器 ,添加TCP_FORWARDING=true环境变量,然后重启 s1 容器

bash 复制代码
services:
   s1:
     image: quay.io/panubo/sshd:1.6.0 
       #  restart: always
     ports:
       - "22221:22"
     volumes:
       - ${PWD}/s1/ssh/id_rsa.pub:/root/.ssh/authorized_keys:ro 
       - ${PWD}/s1/keys/:/etc/ssh/keys 
       - ${PWD}/s1/motd:/etc/motd 
     environment:
       - SSH_ENABLE_ROOT=true
       - TCP_FORWARDING=true

打开 AllowTcpForwarding 配置后,就可以登录了。

不同主机使用不同跳板机

在 ssh config 配置文件中可以使用Match指令根据不同主机来使用不同跳板机,host 支持通配符

sql 复制代码
Match host 192.168.1.* 
        ProxyJump jump1

Match host 192.168.2.* 
        ProxyJump jump2

Ansible 使用跳板机

同样的,Ansible 工具也可以利用 ssh jump host 去管理需要登录跳板机的主机,下面的例子复用上面使用tmp_config配置文件,先配置下 ansible host 文件。

ini 复制代码
(pyenv) root@vm1:/data/tmp_keys# cat my_ansible_host                                                                                                        
[vps]                                                                                                                                                       
jump ansible_ssh_user=ubuntu                                                                                                                                
                                                                                                                                                            
[container]                                                                                                                                                 
s1 ansible_ssh_user=root                                                                                                                                    
s2 ansible_ssh_user=root

使用 ansible ping 模块测试,可以加上 --ssh-common-args='-F tmp_config' 指定ansible 使用自定义的ssh config 文件

报错提示是找不到 Python 程序,因为容器没有安装 Python ,我们在容器上安装好 Python ,重新测试下。

可以看到 ansible ping 执行成功

总结

以上介绍了SSH 通过跳板机连接服务器和 Ansible 通过跳板机连接目标机器,这种跳板机只是普通的 ssh 转发,缺少了像商业或者开源堡垒机的一些很重要的功能,比如审计,权限管控,图形化等。如果您在阅读过程中发现了任何问题,或者有任何可以改进的地方,欢迎留言讨论,也可以关注我的微信公众号运维小猪,谢谢!

参考链接: en.wikibooks.org/wiki/OpenSS...

相关推荐
Amelio_Ming11 小时前
Permissions 0755 for ‘/etc/ssh/ssh_host_rsa_key‘ are too open.问题解决
linux·运维·ssh
Diamond技术流1 天前
从0开始学习Linux——远程连接工具
linux·学习·centos·ssh·xshell·ftp
紫晓宁1 天前
jmeter结合ansible分布式压测--3压测执行
分布式·jmeter·ansible
恒创科技HK2 天前
ssh和ssl的区别在哪些方面?
运维·ssh·ssl
上烟雨心上尘2 天前
通过 ssh config 快速免密连接服务器
运维·服务器·ssh
紫晓宁3 天前
jmeter结合ansible分布式压测--1数据准备
分布式·jmeter·ansible
紫晓宁3 天前
jmeter结合ansible分布式压测--2jmter环境准备
分布式·jmeter·ansible
就叫你天选之人啦3 天前
vscode ssh连接autodl失败
linux·ide·笔记·vscode·ssh
Linux运维日记4 天前
Rocky Linux 9安装后无法远程ssh密码登录解决
linux·运维·ssh
yunteng5214 天前
VisualStudio远程编译调试linux_c++程序(二)
linux·c++·ssh·gdb·visual studio·remote