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"
更新gcloud
Google 工程师做出了不应被调用的回复在平行下!看“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}