Переход с lookup hashi_vault
Это руководство по переходу с hashi_vault плагина lookup на более новые компоненты этой коллекции.
Чтобы понять причины, см. эту страницу, где описана история плагина и его будущее.
Примечание о lookup-плагинах и модулях
Поскольку плагин hashi_vault является lookup-плагином, обычно проще всего заменить его другими lookup-плагинами. Ранее варианта с модулем не было, но теперь он доступен.
Хотя это может потребовать дополнительных усилий, рассмотрите каждый сценарий использования и определите, не будет ли модуль более подходящим вариантом.
Дополнительные сведения см. в руководстве по lookup-плагинам.
Общие изменения
В этом разделе рассматриваются некоторые общие различия, не связанные с конкретными сценариями.
Параметры: прямое указание и строка term
Долгое время lookup-плагин hashi_vault принимал все параметры в виде строк name=value внутри строки term, поэтому для выполнения lookup использовалась одна строка, например secret/data/path auth_method=userpass username=my_user password=somepass.
Такой способ передачи параметров не рекомендуется. Плагин hashi_vault был обновлён (ещё до появления этой коллекции), чтобы принимать параметры в виде отдельных именованных аргументов. Способ со строкой term сохранили для обратной совместимости.
Примечание
Другие lookup-плагины этой коллекции не поддерживают старый синтаксис строк term, поэтому настоятельно рекомендуется перейти на прямое указание параметров.
Если в существующих lookup-плагинах параметры указаны в строке term, возможно, прежде чем менять плагин, стоит сначала перейти на прямое указание параметров, особенно если вы планируете и дальше использовать lookup-плагины вместо модулей.
Примеры использования строк term:
- 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 ^ ^
Те же lookup-плагины с прямым указанием параметров:
- 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 нельзя было получить таким способом, поскольку пробел использовался как разделитель параметров строки term.
Примечание
Синтаксис с двоеточием : не поддерживается другими lookup-плагинами коллекции, и его использование не рекомендуется.
Использование двоеточия : не связано с фильтрацией на стороне сервера или другими оптимизациями, поэтому, кроме компактности синтаксиса, преимуществ у него нет.
Синтаксис с двоеточием : всегда можно было заменить прямым обращением в шаблоне 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. При обращении через точку . также нельзя использовать переменные.
Кроме того, синтаксис с двоеточием : побуждал выполнять несколько lookup-запросов к одному секрету только для получения разных ключей, что приводило к нескольким одинаковым запросам к Vault. Приведённый выше пример также страдает от этой проблемы.
Более лаконичный вариант может выглядеть так:
- 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 и подробнее рассматривается в руководстве по lookup-плагинам. Эту проблему можно решить, используя ansible.builtin.set_fact для задания переменной secret или выполнив чтение с помощью модуля.
Если вы широко используете синтаксис с двоеточием :, рекомендуется обновить его до перехода на другие плагины.
Формат возвращаемых данных
Примечание
Параметр return_format не будет поддерживаться другими плагинами. Если вы используете его сейчас, рекомендуется заменить его средствами Jinja2.
Lookup-плагин hashi_vault принимает параметр return_format, значение по умолчанию которого — dict. Lookup-плагин всегда ищет поле data (подробнее см. сведения об ответе KV), и именно оно возвращается по умолчанию.
Значение raw параметра return_format возвращает необработанный ответ API на запрос. Например, это можно использовать для получения метаданных из запроса KV2, которые обычно удаляются. Также этот режим можно использовать для чтения по пути, не относящемуся к KV, если ответ имеет структуру, похожую на ответ KV (с одной или несколькими структурами data), и поэтому интерпретируется как ответ 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
Наиболее распространённый способ использования lookup-плагина 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
Внутренний формат ответа для версий 1 и 2 хранилища KV различается.
Пример ответа 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
}
Lookup-плагин hashi_vault традиционно возвращал поле data из прочитанных данных. Позже плагин обновили: теперь он ищет вложенную структуру data.data и, если она найдена, возвращает только внутреннее поле data. Это позволяет всегда возвращать данные секретов KV1 и KV2 в согласованном формате, но не даёт доступа к дополнительной информации из метаданных KV2.
Пути API KV1 и KV2
В KV1 путь к секрету напрямую добавлялся к точке монтирования. Например, если движок 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 — это версионируемое хранилище секретов, обычно существует несколько версий одного секрета. Lookup-плагин hashi_vault не предоставлял отдельного способа получить версию, отличную от последней (используемой по умолчанию), однако в документации предлагалось добавлять ?version=2 к пути, чтобы получить версию секрета 2. Это работало, но напрямую изменяло путь API, поэтому такой вариант не считался стабильным. Выделенные компоненты KV2 в коллекции поддерживают эту возможность как полноценный параметр.
Замена операций получения данных KV
Начиная с версии коллекции 2.5.0 добавлены lookup-плагины и модули vault_kv1_get и vault_kv2_get:
-
vault_kv1_getlookup-плагин -
vault_kv2_getlookup-плагин -
vault_kv1_getмодуль -
vault_kv2_getмодуль
Эти специализированные плагины чётко разделяют операции KV1 и KV2. Благодаря этому их поведение понятно и предсказуемо.
Что касается путей API, эти плагины используют подход, принятый в большинстве клиентских библиотек Vault и рекомендованный HashiCorp: точка монтирования передаётся как параметр (engine_mount_point) отдельно от пути для чтения. Благодаря этому путь формируется корректно, и вызывающему коду не нужно вставлять /data/ для KV2.
KV-плагины больше не возвращают непосредственно секрет. Вместо этого возвращаемые значения для KV1 и KV2, как в виде модуля, так и lookup-плагина, унифицированы и обеспечивают удобный раздельный доступ к секрету, полному ответу 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)
Поскольку lookup-плагин hashi_vault выполняет общий запрос чтения, его можно использовать для чтения других путей, не относящихся к KV, например для чтения из cubbyhole или получения идентификатора роли AppRole.
В будущем ожидается появление компонентов для более специализированных задач, например плагинов для получения идентификатора роли. Для задач, которые пока не охвачены, доступны lookup-плагин и модуль vault_read:
-
vault_readlookup-плагин -
vault_readмодуль
Они всегда выполняют прямое чтение и возвращают необработанный результат, не пытаясь дополнительно интерпретировать ответ. Примеры см. в документации к ним.
© 2012–2018 Michael DeHaan
© 2018–2025 Red Hat, Inc.
Licensed under the GNU General Public License version 3.
https://docs.ansible.com/projects/ansible/latest/collections/community/hashi_vault/docsite/migration_hashi_vault_lookup.html