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...

相关推荐
张3239 小时前
Ansible实施任务控制
linux·ansible
Garfield20059 小时前
VSCode SSH 连接远程服务器后,Codex 插件登录失败
服务器·vscode·ssh·claude·codex
张32311 小时前
Ansible Playbook
ansible
Garfield200511 小时前
VSCode Remote SSH 使用 Codex 无法账号登录
vscode·chatgpt·ssh·codex
张32312 小时前
Ansible文件部署
服务器·ansible
程序员大辉12 小时前
开源客户端SSH Netcatty:免费替代Termius,带AI的现代化运维工具
运维·开源·ssh
张32312 小时前
Ansible介绍
ansible
热爱Liunx的丘丘人1 天前
Ansible的Playbook案例一
linux·运维·服务器·ansible
小梦爱安全1 天前
Ansible剧本1
java·网络·ansible
WJ.Polar1 天前
Ansible任务控制
linux·运维·网络·python·ansible