使用 Ansible,是否可以连接到 GCP 中 Cloud IAP(身份感知代理)后面的主机?

使用 Ansible,是否可以连接到 GCP 中 Cloud IAP(身份感知代理)后面的主机?

Cloud IAP 是 Google Cloud Platform 的一种代理,可让您无需 VPN 即可连接到没有公共 IP 地址的计算实例。您建立一个实例,然后可以使用该gcloud实用程序按名称连接到它,如下所示:gcloud compute ssh my-server-01。这会通过代理对您进行身份验证,并使用您自己的 Google 帐户(使用称为操作系统登录的功能)将您登录到目标服务器。

我认为要让 ansible 执行该gcloud工具正在执行的操作,我需要一个自定义连接插件。

答案1

经过讨论后https://www.reddit.com/r/ansible/comments/e9ve5q/ansible_slow_as_a_hell_with_gcp_iap_any_way_to/我更改了解决方案以通过套接字使用 SSH 连接共享。

它比 @mat 解决方案快两倍。我把它放在我们的产品中。这是一个不依赖于主机名模式的实现!

正确的解决方案是使用 Bastion/Jump 主机,因为gcloud命令仍然会生成生成的 Python 解释器ssh- 它仍然效率低下!

ansible.cfg:

[ssh_connection]
pipelining = True
ssh_executable = misc/gssh.sh
ssh_args =
transfer_method = piped

[privilege_escalation]
become = True
become_method = sudo

[defaults]
interpreter_python = /usr/bin/python
gathering = False
# Somehow important to enable parallel execution...
strategy = free

gssh.sh:

#!/bin/bash

# ansible/ansible/lib/ansible/plugins/connection/ssh.py
# exec_command(self, cmd, in_data=None, sudoable=True) calls _build_command(self, binary, *other_args) as:
#   args = (ssh_executable, self.host, cmd)
#   cmd = self._build_command(*args)
# So "host" is next to the last, cmd is the last argument of ssh command.

host="${@: -2: 1}"
cmd="${@: -1: 1}"

# ControlMaster=auto & ControlPath=... speedup Ansible execution 2 times.
socket="/tmp/ansible-ssh-${host}-22-iap"

gcloud_args="
--tunnel-through-iap
--zone=europe-west1-b
--quiet
--no-user-output-enabled
--
-C
-o ControlMaster=auto
-o ControlPersist=20
-o PreferredAuthentications=publickey
-o KbdInteractiveAuthentication=no
-o PasswordAuthentication=no
-o ConnectTimeout=20"

exec gcloud compute ssh "$host" $gcloud_args -o ControlPath="$socket" "$cmd"

更新gcloudGoogle 工程师做出了不应被调用的回复在平行下!看“gcloudcomputessh”无法并行使用

实验表明,使用 Ansiblefork=5我几乎总是会遇到错误。我fork=2从来没有经历过。

更新2随着时间的推移,到 2020 年底,我可以并行运行gcloud compute ssh(在 WSL 中我做到了fork = 10),而不会出现锁定错误。

答案2

我找到了一种无需连接插件即可完成这项工作的方法。基本上,您可以编写一个包装该工具的脚本gcloud并将ansible_ssh_executable参数指向该脚本,您可以在清单级别定义该参数。您确实需要确保gcp_compute清单插件按名称识别主机,因为这是所gcloud compute ssh期望的。

这是脚本:

#!/bin/sh
set -o errexit
# Wraps the gcloud utility to enable connecting to instances which are behind
# GCP Cloud IAP. Used by setting the `ansible_ssh_executable` setting for a play
# or inventory. Parses out the relevant information from Ansible's call to the
# script and injects into the right places of the gcloud utility.

arg_string="$@"

grep_hostname_regex='[a-z]*[0-9]\{2\}\(live\|test\)'
sed_hostname_regex='[a-z]*[0-9]{2}(live|test)'

target_host=$(
  echo "$arg_string\c" | grep -o "$grep_hostname_regex"
)

ssh_args=$(
  echo "$arg_string\c" | sed -E "s# ${sed_hostname_regex}.*##"
)

cmd=$(
  echo "$arg_string\c" | sed -E "s#.*${sed_hostname_regex} ##"
)

gcloud compute ssh "$target_host" \
  --command="$cmd" \
  --tunnel-through-iap \
  -- $ssh_args

笔记:

  • 这是在 macOS 上测试的。sed例如,Linux 上的选项可能会有所不同。
  • “主机”正则表达式需要符合您的命名约定。如果您没有像我一样的一致命名约定,您将需要找到其他方法来解析信息。

答案3

感谢您发布这些@gavenkoa 和@matt。一项建议是添加以下内容,这样您就不需要对区域进行硬编码。

片段:

ZONE=$(gcloud compute instances list --filter="name:${host}" --format='value(zone)')

gcloud_args="
--tunnel-through-iap \
--zone=${ZONE}

相关内容