从 hashi_vault
查找迁移
本指南旨在帮助您从 hashi_vault
查找插件 迁移到此集合中的较新内容。
要了解原因,请参阅本页描述插件的历史和未来。
关于查找与模块的说明
由于 hashi_vault
插件是查找插件,因此最直接的方式通常是使用其他查找插件替换它。以前没有模块选项可用,但现在有了。
虽然可能涉及更多,但请考虑每个用例,以确定模块是否更合适。
有关详细信息,请参阅查找指南。
一般更改
本节将介绍一些与特定场景无关的一般差异。
选项:直接 vs. 项字符串
很长一段时间以来,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 替换。我们将再次使用我们的示例密钥
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 密钥存储中读取密钥。
- 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') }}"
两者的返回值都是密钥中键/值对的字典,不包含 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 返回密钥数据,但这意味着无法访问 KV2 元数据中的任何其他信息。
KV1 和 KV2 API 路径
KV1 的 API 路径直接将密钥路径连接到挂载点。因此,例如,如果一个 KV1 引擎挂载在 kv/v/1
(挂载路径可以包含 /
),并且在该存储中创建了一个位于 app/deploy_key
的密钥,则该路径将为 kv/v/1/app/deploy_key
。
在 KV2 中,有单独的路径来处理密钥的数据和元数据,因此需要在挂载点和路径之间插入额外的 /data/
或 /metadata/
组件。
例如,如果一个 KV2 存储挂载在 kv/v/2
,并且一个密钥位于 app/deploy_key
,则读取密钥数据的路径为 kv/v/2/data/app/deploy_key
。对于元数据操作,路径为 kv/v/2/metadata/app/deploy_key
。
由于 hashi_vault
对 API 路径执行通用读取,因此任何使用它的人都必须知道将它们插入路径中,这会导致很多混乱。
KV2 密钥版本
由于 KV2 是一个版本化的密钥存储,因此通常存在同一密钥的多个版本。使用 hashi_vault
查找没有专门的方法来获取除最新密钥(默认)之外的任何密钥,但是文档建议可以将 ?version=2
添加到路径以获取密钥版本 2。这确实有效,但它直接修改了 API 路径,因此不被视为稳定选项。集合中的专用 KV2 内容将此作为首要选项支持。
KV 获取替换
从集合版本 2.5.0 开始,添加了 vault_kv1_get
和 vault_kv2_get
查找和模块
这些专用插件清楚地分离了 KV1 和 KV2 操作。这确保了它们的行为清晰且可预测。
就 API 路径而言,这些插件采用了大多数 Vault 客户端库的方法,并由 HashiCorp 推荐,即接受挂载点作为选项 (engine_mount_point
),与要读取的路径分开。这确保了将在内部构建正确的路径,并且不需要调用方在 KV2 上插入 /data/
。
对于返回值,KV 插件不再返回直接密钥。相反,KV1 和 KV2 的返回值以及模块和查找形式都已统一,以便可以轻松访问密钥、完整的 API 响应以及响应的其他部分。
返回值直接在每个插件的文档中的返回和示例部分中介绍。
示例
以下是一些 KV 前后示例。
我们将回到我们的示例密钥
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
查找和模块
它们始终执行直接读取,并返回原始结果,而无需尝试对响应进行任何其他解释。有关示例,请参阅其文档。