查找指南
本指南并非包含的查找插件及其使用方法的详尽列表,而是旨在解释查找插件在 community.hashi_vault
中的作用以及它们的使用方式,特别是与同名模块相比时。
有关 hashi_vault
查找的详细信息,请参阅详细介绍它的本页。
查找和写入
大多数 Ansible 查找执行只读、非破坏性操作。它们在模板中运行,通常返回值,并且在检查模式下运行方式没有差异(即它们执行的操作与正常模式相同,即使这意味着更改某些内容)。但是,一些查找确实会更改状态,有时会执行写入操作。例如,password
查找会将生成的密码写入文件,以充当某种缓存,而 pipe
查找运行任意 shell 命令,因此很容易写入或更改状态。
Vault 中的写入
在 Vault 中执行写入操作不仅仅限于诸如写入密钥值、创建策略或启用新的身份验证方法等显而易见的操作。
例如,任何创建令牌的操作(如任何登录操作)也是写入;令牌在 Vault 中使用存储空间,并且活动令牌过多是导致性能问题的常见原因。
此外,Vault 中的某些值只能在创建时“读取”,因此检索此类值的唯一方法是从创建它的“写入”操作中获取它。一个常见的例子是 AppRole 密钥 ID。
这与 Ansible 和此集合的关系是,我们可能有查找插件,它们要么以不直观的方式执行写入(如 vault_login
),要么看起来不适合首先作为查找存在,例如计划的 vault_write
查找。
这样做的原因是,我们通常认为这些操作是逻辑“读取”操作,例如执行登录,并希望在其他表达式中使用其结果。
类似 vault_write
的操作并不总是符合该描述,因为您可以使用它来执行明显的显式写入,例如,您可以使用查找创建一个新策略。但有时在查找语义中使用它可能是合适的,例如在“检索”(实际上是创建)AppRole 的新密钥 ID 时。
在考虑对身份验证方法的内置支持时,除 token
或 none
之外的任何身份验证方法都会使每个查找(即使是 vault_read
)都变成更改状态并在 Vault 中执行写入的操作。这实际上也适用于许多模块,即使在使用检查模式时也是如此。
如何判断何时使用查找
由于任何查找中都可能进行写入,因此仔细考虑何时使用查找与模块/其他插件非常重要。检查模式对查找没有任何影响,因此在检查模式运行中可能会执行多次写入,但有时您可能希望这样做,例如,如果您通过查找执行 vault_login
来检索令牌以在模块调用中使用,您可能希望在检查模式下仍然执行此操作,以便模块调用可以正确检查它们需要检查的内容。
某些以读取为中心的模块(如 vault_read
模块),在与 token
或 none
之外的身份验证方法一起使用时,即使在检查模式下仍会执行内部登录,因此这仍然是另一个需要考虑的因素。
查找和延迟模板
如果使用不当,Ansible 的“延迟”模板会加剧查找执行写入或更改状态的能力。
考虑以下示例
- vars:
token: "{{ lookup('community.hashi_vault.vault_login', auth_method='userpass', username='user', password='pass') | community.hashi_vault.vault_login_token }}"
secret: "{{ lookup('community.hashi_vault.vault_read', 'secrets/data/my-secret', token=token) }}"
value_a: "{{ secret.data.data.a }}"
value_b: "{{ secret.data.data.b }}"
ansible.builtin.debug:
msg: "Secret value A is '{{ value_a }}' while value B is '{{ value_b }}'."
由于模板是递归的并且延迟计算,因此不幸的是,这将不会导致单次登录,而是重用令牌来执行单次密钥读取,然后在字典查找中使用。
相反,对 value_a
和 value_b
的求值将各自导致对 secret
的单独求值,因此会执行两次查找,并且每次查找都会导致对 token
的单独求值,这将执行两次单独的登录,导致创建两个令牌,并且对完全相同的 secret 执行两次读取。
如果将其与循环结合使用,或者在多个任务中重用变量,您可能会很快地将发送到 Vault 的请求数量以及写入情况下创建的对象数量成倍增加。
对于这种情况,任务可能更好,因为它们在遇到时执行而不会被意外重复,并且它们返回的值是静态的。
- name: login
community.hashi_vault.vault_login:
auth_method: userpass
username: user
password: pass
register: login
- name: get secret
community.hashi_vault.vault_read:
token: '{{ login | community.hashi_vault.vault_login_token }}'
path: 'secrets/data/my-secret'
register: secret
- vars:
value_a: "{{ secret.data.data.data.a }}"
value_b: "{{ secret.data.data.data.b }}"
ansible.builtin.debug:
msg: "Secret value A is '{{ value_a }}' while value B is '{{ value_b }}'."
即使这个例子更加冗长,它也只会执行一次登录和 secret 查找。这也意味着 secret
和 login
变量可以在更多任务中重用,而无需向 Vault 发送额外的请求。
在两个示例中,另一个需要考虑的事情是任务是按主机运行的,因此您可能再次将请求成倍增加。
在查找示例中,所有这些请求都发生在控制器上,而在模块示例中,它们发生在远程主机上,除非 play 或任务的目标是本地。
在这两种情况下,您可能希望按主机发出这些请求,因为查找中涉及的一些变量可能依赖于按主机的值,例如不同的身份验证、不同的 secret 路径,甚至是完全不同的 Vault 服务器,或者在某些访问限制的情况下,您可能需要远程主机而不是控制器来建立连接。
但是,如果您的所有 secret 访问都旨在从控制器进行,并且请求不依赖于主机级别的变量,您可以通过使用 run_once
,或者在仅以 localhost
为目标的单独 play 中进行 Vault 调用并使用 ansible.builtin.set_fact
,或者通过其他方法,来大量减少您的请求。