从 hashi_vault
查询迁移
本指南旨在帮助您从 hashi_vault
查询插件 迁移到此集合中的更新内容。
要了解原因,请参阅 此页面描述插件的历史和未来。
关于查询与模块的说明
由于 hashi_vault
插件是一个查询,因此通常最直接的方法是用其他查询替换它的使用。之前没有可用的模块选项,但现在有了。
尽管可能更复杂,但请考虑每个用例以确定模块是否更合适。
有关更多信息,请参阅 查询指南。
通用更改
本节将介绍一些与特定场景无关的通用差异。
选项:直接与术语字符串
长期以来,hashi_vault
查询将其所有选项作为 name=value
字符串放入术语字符串中,因此您将使用如下所示的单个字符串进行查询:secret/data/path auth_method=userpass username=my_user password=somepass
。
不鼓励使用这种传递选项的方式,并且 hashi_vault
已更新(在此集合存在之前)以支持将选项作为单独的关键字参数传递。保留术语字符串方法是为了向后兼容。
注意
此集合中的其他查询均不支持旧式术语字符串语法,因此强烈建议更改为直接选项。
如果您的现有查询在术语字符串中使用选项,您可能希望先更改为直接使用选项,然后再尝试更改插件,**特别是如果您打算继续使用查询而不是模块**。
术语字符串样式的示例
- name: Term string style
vars:
user: my_user
pass: '{{ my_secret_password }}'
mount: secret
relpath: path
ansible.builtin.debug:
msg:
- "Static: {{ lookup('community.hashi_vault.hashi_vault', 'secret/data/path auth_method=userpass username=my_user password=somepass') }}"
- "Variables: {{ lookup('community.hashi_vault.hashi_vault', mount ~ '/data/' ~ path ~ ' auth_method=userpass username=' ~ user ~ ' password=' ~ pass) }}"
# note these necessary but easy to miss spaces ^ ^
以及转换为直接选项的相同查询
- name: Direct option style
vars:
user: my_user
pass: '{{ my_secret_password }}'
mount: secret
relpath: path
ansible.builtin.debug:
msg:
- "Static: {{ lookup('community.hashi_vault.hashi_vault', 'secret/data/path', auth_method='userpass', username='my_user', password='somepass') }}"
- "Variables: {{ lookup('community.hashi_vault.hashi_vault', mount ~ '/data/' ~ path, auth_method='userpass', username=user, password=pass) }}"
键解引用
对于这些示例,我们将假设我们的结果字典具有以下结构
key_1: value1
'key-2': 2
'key three': three
hashi_vault
还支持使用冒号 :
的字典解引用语法,因此经常看到这种情况
- ansible.builtin.debug:
msg:
- "KV1 (key1): {{ lookup('community.hashi_vault.hashi_vault', 'kv1_mount/path/to/secret:key_1') }}"
- "KV2 (key1): {{ lookup('community.hashi_vault.hashi_vault', 'kv2_mount/data/path/to/secret:key_1') }}"
使用上述语法,仅返回 key_1
的*值*。请注意,无法以这种方式检索 key three
,因为空格是术语字符串选项的分隔符。
注意
此集合中的任何其他查询均不支持冒号 :
语法,并且不鼓励使用该语法。
**冒号** :
**的使用不对应任何服务器端过滤或其他优化**,因此除了紧凑的语法之外,使用它没有任何优势。
冒号 :
语法始终可以通过在 Jinja2 模板中直接解引用来替换。可以直接使用 Jinja2 点 .
语法(对键名称有限制)或通过方括号 []
来进行直接解引用,如下所示(KV 版本无关紧要)
- vars:
k1: key_1
k2: key-2
k3: key three
ansible.builtin.debug:
msg:
- "KV1 (key1, dot): {{ lookup('community.hashi_vault.hashi_vault', 'kv1_mount/path/to/secret').key_1 }}"
- "KV1 (key1, [ ]): {{ lookup('community.hashi_vault.hashi_vault', 'kv1_mount/path/to/secret')['key_1'] }}"
- "KV1 (var1, [ ]): {{ lookup('community.hashi_vault.hashi_vault', 'kv1_mount/path/to/secret')[k1] }}"
- "KV1 (key2, [ ]): {{ lookup('community.hashi_vault.hashi_vault', 'kv1_mount/path/to/secret')['key-2'] }}"
- "KV1 (var2, [ ]): {{ lookup('community.hashi_vault.hashi_vault', 'kv1_mount/path/to/secret')[k2] }}"
- "KV1 (key3, [ ]): {{ lookup('community.hashi_vault.hashi_vault', 'kv1_mount/path/to/secret')['key three'] }}"
- "KV1 (var3, [ ]): {{ lookup('community.hashi_vault.hashi_vault', 'kv1_mount/path/to/secret')[k3] }}"
请注意,只有 key_1
可以使用点 .
语法,因为允许的字符仅限于 Python 符号允许的字符。变量也不能与点 .
访问一起使用。
此外,冒号 :
语法鼓励仅为了获取不同的键而对同一秘密进行多次查询,从而导致向 Vault 发送多个相同的请求。**上面的示例也存在这种情况**。
更 DRY 的方法可能如下所示
- vars:
secret: "{{ lookup('community.hashi_vault.hashi_vault', 'kv1_mount/path/to/secret') }}"
k1: key_1
k2: key-2
k3: key three
ansible.builtin.debug:
msg:
- "KV1 (key1, dot): {{ secret.key_1 }}"
- "KV1 (key1, [ ]): {{ secret['key_1'] }}"
- "KV1 (var1, [ ]): {{ secret[k1] }}"
- "KV1 (key2, [ ]): {{ secret['key-2'] }}"
- "KV1 (var2, [ ]): {{ secret[k2] }}"
- "KV1 (key3, [ ]): {{ secret['key three'] }}"
- "KV1 (var3, [ ]): {{ secret[k3] }}"
这看起来好多了,从可读性的角度来看是这样,但实际上它的操作方式完全相同,每次引用 secret
时都会发出新的请求。这是因为 Ansible 中的模板延迟评估,在查找指南中有更详细的讨论。可以通过使用 ansible.builtin.set_fact
设置 secret
变量,或者使用模块进行读取来解决这个问题。
如果你大量使用冒号 :
语法,建议在转向其他插件之前更新它。
返回格式
注意
return_format
选项在其他插件中将不受支持。 如果你目前正在使用它,建议用 Jinja2 替换它。
hashi_vault
查找采用 return_format
选项,默认为 dict
。该查找始终查找 data
字段(有关详细信息,请参阅KV 响应详细信息),这是默认返回的内容。
return_format
的 raw
值提供来自请求的原始 API 响应。例如,这可以用于获取 KV2 请求的元数据(通常会被剥离),或者用于从响应恰好看起来像 KV 响应(具有一个或多个 data
结构)的非 KV 路径读取,并因此被解释为一个 KV 响应。
对于读取非 KV 路径,有其他选项可用。
要获取对 KV2 元数据的访问权限,请参阅KV 替换部分。
return_format
选项也可以设置为 values
以返回字典的值列表。
这可以用 Jinja2 替换。我们将再次使用我们的示例 secret
key_1: value1
'key-2': 2
'key three': three
并查看 return_format
的用法
# show a list of values, ['value1', 2, 'three']
- ansible.builtin.debug:
msg:
- "KV1: {{ lookup('community.hashi_vault.hashi_vault', 'kv1_mount/path/to/secret', return_format='values') }}"
# run debug once for each value
- ansible.builtin.debug:
msg: "{{ item }}"
loop: "{{ query('community.hashi_vault.hashi_vault', 'kv1_mount/path/to/secret', return_format='values') }}"
我们可以用 Jinja2 做同样的事情
# show a list of values
- ansible.builtin.debug:
msg:
- "KV1: {{ lookup('community.hashi_vault.hashi_vault', 'kv1_mount/path/to/secret').values() | list }}"
# run debug once for each value
- ansible.builtin.debug:
msg: "{{ item }}"
loop: "{{ lookup('community.hashi_vault.hashi_vault', 'kv1_mount/path/to/secret').values() | list }}"
Vault KV 读取
hashi_vault
查找的最常见用途是从 KV 秘密存储读取 secret。
- ansible.builtin.debug:
msg:
- "KV1: {{ lookup('community.hashi_vault.hashi_vault', 'kv1_mount/path/to/secret') }}"
- "KV2: {{ lookup('community.hashi_vault.hashi_vault', 'kv2_mount/data/path/to/secret') }}"
两者的返回值都是 secret 中键/值对的字典,没有来自 API 响应的附加信息,也没有元数据(在 KV2 的情况下)。
KV1 和 KV2 响应结构
在底层,KV 存储的第 1 版和第 2 版的返回格式不同。
这是一个示例 KV1 响应
{
"auth": null,
"data": {
"Key1": "val1",
"Key2": "val2"
},
"lease_duration": 2764800,
"lease_id": "",
"renewable": false,
"request_id": "e26a7521-e512-82f1-3998-7cc494f14e86",
"warnings": null,
"wrap_info": null
}
这是一个示例 KV2 响应
{
"auth": null,
"data": {
"data": {
"Key1": "val1",
"Key2": "val2"
},
"metadata": {
"created_time": "2022-04-21T15:56:58.8525402Z",
"custom_metadata": null,
"deletion_time": "",
"destroyed": false,
"version": 2
}
},
"lease_duration": 0,
"lease_id": "",
"renewable": false,
"request_id": "15538d55-0ad9-1c39-2f4b-dcbb982f13cc",
"warnings": null,
"wrap_info": null
}
hashi_vault
查找传统上返回它正在读取的任何内容的 data
字段,然后该插件后来更新到其当前行为,即查找嵌套的 data.data
结构,如果找到,则仅返回内部 data
。 这旨在始终以一致的格式从 KV1 和 KV2 返回 secret 数据,但这意味着无法访问 KV2 元数据的任何附加信息。
KV1 和 KV2 API 路径
KV1 的 API 路径将 secret 路径直接连接到挂载点。 因此,例如,如果 KV1 引擎挂载在 kv/v/1
(挂载路径可以包含 /
),并且在该存储中以 app/deploy_key
创建了一个 secret,则路径将为 kv/v/1/app/deploy_key
。
在 KV2 中,有单独的路径处理 secret 的数据和元数据,因此需要在挂载点和路径之间插入额外的 /data/
或 /metadata/
组件。
例如,对于挂载在 kv/v/2
的 KV2 存储和 app/deploy_key
的 secret,读取 secret 数据的路径是 kv/v/2/data/app/deploy_key
。对于元数据操作,它将是 kv/v/2/metadata/app/deploy_key
。
由于 hashi_vault
对 API 路径执行通用读取,因此任何使用它的人都必须知道将这些插入到路径中,这会导致很多混乱。
KV2 secret 版本
由于 KV2 是一个版本化的 secret 存储,因此通常存在同一 secret 的多个版本。使用 hashi_vault
查找没有专门的方法来获取除最新 secret(默认)之外的任何内容,但是文档建议可以将 ?version=2
添加到路径中以获取 secret 版本 2。这确实有效,但是它直接修改了 API 路径,因此不被认为是稳定的选项。集合中专用的 KV2 内容将此作为一等选项支持。
KV 获取替换
从集合版本 2.5.0 开始,添加了 vault_kv1_get
和 vault_kv2_get
查找和模块
这些专用插件清楚地分离了 KV1 和 KV2 操作。这确保了它们的行为清晰且可预测。
就 API 路径而言,这些插件采用大多数 Vault 客户端库的方法,并由 HashiCorp 推荐,即将挂载点作为与要读取的路径分开的选项 (engine_mount_point
)。这确保将在内部构建正确的路径,并且不需要调用者在 KV2 上插入 /data/
。
对于返回值,KV 插件不再返回直接 secret。相反,来自 KV1 和 KV2 的返回值,以及模块和查找形式,都已被统一,可以轻松访问 secret、完整的 API 响应以及响应的其他部分。
返回值直接在每个插件的文档中的返回和示例部分中进行介绍。
示例
以下是一些 KV 示例的之前和之后。
我们将回到我们的示例 secret
key_1: value1
'key-2': 2
'key three': three
以及一些用法
- name: Reading secrets with hashi_vault and colon dereferencing
ansible.builtin.debug:
msg:
- "KV1 (key1): {{ lookup('community.hashi_vault.hashi_vault', 'kv1_mount/path/to/secret:key_1') }}"
- "KV2 (key1): {{ lookup('community.hashi_vault.hashi_vault', 'kv2_mount/data/path/to/secret:key_1') }}"
- name: Replacing the above
ansible.builtin.debug:
msg:
- "KV1 (key1): {{ lookup('community.hashi_vault.vault_kv1_get', 'path/to/secret', engine_mount_point='kv1_mount').secret.key_1 }}"
- "KV2 (key1): {{ lookup('community.hashi_vault.vault_kv2_get', 'path/to/secret', engine_mount_point='kv2_mount').secret.key_1 }}"
- name: Reading secret version 7 (old)
ansible.builtin.debug:
msg:
- "KV2 (v7): {{ lookup('community.hashi_vault.hashi_vault', 'kv2_mount/data/path/to/secret?version=7') }}"
- name: Reading secret version 7 (new)
ansible.builtin.debug:
msg:
- "KV2 (v7): {{ lookup('community.hashi_vault.vault_kv2_get', 'path/to/secret', engine_mount_point='kv2_mount', version=7).secret }}"
- name: Reading KV2 metadata (old)
ansible.builtin.debug:
msg:
- "KV2 (metadata): {{ lookup('community.hashi_vault.hashi_vault', 'kv2_mount/data/path/to/secret', return_format='raw').data.metadata }}"
- name: Reading KV2 metadata (new)
ansible.builtin.debug:
msg:
- "KV2 (metadata): {{ lookup('community.hashi_vault.vault_kv2_get', 'path/to/secret', engine_mount_point='kv2_mount').metadata }}"
通用读取(非 KV)
由于 hashi_vault
查找在内部执行通用读取,因此它可以用于读取不是 KV 特定的其他路径,例如从 cubbyhole 读取或检索 AppRole 的角色 ID。
未来会推出更多特定用途的内容,例如用于检索角色 ID 的插件,但对于目前未涵盖的任何内容,我们有 vault_read
查找和模块
这些始终执行直接读取,并返回原始结果,而不尝试对响应进行任何其他解释。 请参阅他们的文档以获取示例。