Рубрики
Без рубрики

Вступление к Своду

Полное руководство по пониманию основ хранилища.

Автор оригинала: Philippe Sevestre.

1. Обзор

В этом уроке мы рассмотрим хранилище Hashicorp – популярный инструмент, используемый для безопасного управления конфиденциальной информацией в современных архитектурах приложений .

Основные темы, которые мы рассмотрим, включают в себя:

  • Какую проблему пытается решить Vault
  • Архитектура хранилища и основные концепции
  • Настройка простой тестовой среды
  • Взаимодействие с хранилищем с помощью инструмента командной строки

2. Проблема с конфиденциальной информацией

Прежде чем копаться в хранилище, давайте попробуем понять проблему, которую оно пытается решить: управление конфиденциальной информацией.

Большинству приложений необходим доступ к конфиденциальным данным для правильной работы . Например, приложение электронной коммерции может иметь имя пользователя/пароль, настроенные где-то для подключения к своей базе данных. Ему также могут потребоваться ключи API для интеграции с другими поставщиками услуг, такими как платежные шлюзы, логистика и другие деловые партнеры.

Учетные данные базы данных и ключи API-это некоторые примеры конфиденциальной информации, которую мы должны хранить и предоставлять нашим приложениям безопасным способом.

Простое решение состоит в том, чтобы сохранить эти учетные данные в файле конфигурации и прочитать их во время запуска. Однако проблема с таким подходом очевидна. Тот, кто имеет доступ к этому файлу, пользуется теми же привилегиями базы данных, что и наше приложение – обычно предоставляя ей полный доступ ко всем сохраненным данным.

Мы можем попытаться немного усложнить ситуацию, зашифровав эти файлы. Этот подход, однако, не добавит много с точки зрения общей безопасности. Главным образом потому, что наше приложение должно иметь доступ к мастер-ключу. Шифрование, когда оно используется таким образом, приведет только к “ложному” чувству безопасности.

Современные приложения и облачные среды, как правило, добавляют некоторую дополнительную сложность: распределенные службы, несколько баз данных, системы обмена сообщениями и т. Д., Все они имеют конфиденциальную информацию, распространяемую немного повсюду, что увеличивает риск нарушения безопасности.

Итак, что мы можем сделать? Давайте сделаем это!

3. Что Такое Хранилище?

Хранилище Hashicorp решает проблему управления конфиденциальной информацией – a secret на языке хранилища. “Управление” в этом контексте означает, что Vault контролирует все аспекты конфиденциальной информации : ее генерацию, хранение, использование и, что не менее важно, ее отзыв.

Hashicorp предлагает две версии хранилища. Версия с открытым исходным кодом, используемая в этой статье, бесплатна для использования даже в коммерческих средах. Также доступна платная версия, которая включает техническую поддержку в различных SLA и дополнительные функции, такие как поддержка HSM (аппаратного модуля безопасности).

3.1. Архитектура и основные функции

Архитектура хранилища обманчиво проста. Его основными компонентами являются:

  • Бэкэнд персистентности – хранилище для всех секретов
  • Сервер API, который обрабатывает запросы клиентов и выполняет операции с секретами
  • Количество секретных движков, по одному для каждого типа поддерживаемого секретного типа

Делегируя все секретные операции хранилищу, мы можем смягчить некоторые проблемы безопасности:

  • Нашим приложениям больше не нужно хранить их – просто спросите Vault, когда это необходимо, и откажитесь от него
  • Мы можем использовать недолговечные секреты, тем самым ограничивая “окно возможностей”, в котором злоумышленник может использовать украденный секрет

Хранилище шифрует все данные с помощью ключа шифрования перед их записью в хранилище. Этот ключ шифрования зашифрован еще одним ключом – главным ключом, используемым только при запуске.

Ключевым моментом в реализации хранилища является то, что он не хранит главный ключ на сервере. Это означает, что даже хранилище не может получить доступ к своим сохраненным данным после запуска. В этот момент экземпляр хранилища, как говорят, находится в “запечатанном” состоянии.

Позже мы рассмотрим шаги, необходимые для создания главного ключа и вскрытия экземпляра хранилища.

После вскрытия хранилище будет готово принимать запросы API. Эти запросы, конечно, нуждаются в аутентификации, что подводит нас к тому, как Vault аутентифицирует клиентов и решает, что они могут или не могут делать.

3.2. Аутентификация

Для доступа к секретам в хранилище клиенту необходимо пройти аутентификацию с помощью одного из поддерживаемых методов . Самый простой метод использует токены, которые представляют собой просто строки, отправляемые при каждом запросе API с использованием специального заголовка HTTP.

При первоначальной установке Vault автоматически генерирует “корневой токен”. Этот токен эквивалентен суперпользователю root в системах Linux, поэтому его использование должно быть ограничено до минимума. В качестве наилучшей практики мы должны использовать этот корневой токен только для создания других токенов с меньшим количеством привилегий, а затем отозвать его. Однако это не проблема, так как позже мы можем сгенерировать еще один корневой токен с помощью ключей unseal.

Хранилище также поддерживает другие механизмы аутентификации, такие как сертификаты LDAP, JWT, TLS и другие. Все эти механизмы основаны на базовом механизме токенов: как только Vault проверит нашего клиента, он предоставит токен, который мы затем сможем использовать для доступа к другим API.

Токены имеют несколько свойств, связанных с ними. Основными свойствами являются:

  • Набор связанных Политик (см. следующий раздел)
  • Время-жить
  • Можно ли его продлить
  • Максимальное количество использований

Если не указано иное, токены, созданные хранилищем, будут формировать отношения “родитель-потомок”. Дочерний токен может иметь не более того же уровня привилегий, что и родительский.

Обратное неверно: мы можем – и обычно делаем – создать дочерний токен с ограничительными политиками Еще один ключевой момент в этой связи: Когда мы аннулируем токен, все дочерние токены и их потомки также становятся недействительными .

3.3. Политика

Политики точно определяют, к каким секретам клиент может получить доступ и какие операции он может выполнять с ними . Давайте посмотрим, как выглядит простая политика:

path "secret/accounting" {
    capabilities = [ "read" ]
}

Здесь мы использовали синтаксис HCL (Язык конфигурации Hashicorp) для определения нашей политики. Vault также поддерживает JSON для этой цели, но мы будем придерживаться HCL в наших примерах, так как его легче читать.

Политики в хранилище по умолчанию” запрещены” . Токен, прикрепленный к этому образцу политики, получит доступ к секретам, хранящимся в secret/accounting , и ничего больше. Во время создания токен может быть присоединен к нескольким политикам. Это очень полезно, поскольку позволяет нам создавать и тестировать небольшие политики, а затем применять их по мере необходимости.

Политики в хранилище по умолчанию” запрещены” . Токен, прикрепленный к этому образцу политики, получит доступ к секретам, хранящимся в

Политики в хранилище по умолчанию” запрещены” . Токен, прикрепленный к этому образцу политики, получит доступ к секретам, хранящимся в secret/accounting

Когда это доступно, это позволяет нам учитывать в наших политиках дополнительные атрибуты, такие как время суток, несколько факторов аутентификации, происхождение клиентской сети и так далее. Например, мы можем определить политику, которая разрешает доступ к данному секрету только в рабочее время.

Более подробную информацию о синтаксисе политики можно найти в документации Vault .

4. Секретные Типы

Хранилище поддерживает ряд различных типов секретов, которые решают различные варианты использования:

  • Ключ-значение: простые статические пары ключ-значение
  • Динамически генерируемые учетные данные : генерируются хранилищем по запросу клиента
  • Криптографические ключи : Используются для выполнения криптографических функций с клиентскими данными

Каждый секретный тип определяется следующими атрибутами:

  • A mount point, который определяет свой префикс REST API
  • Набор операций, доступных через соответствующий API
  • Набор параметров конфигурации

Данный секретный экземпляр доступен через путь , подобно дереву каталогов в файловой системе. Первый компонент этого пути соответствует точке монтирования , где расположены все секреты этого типа .

Например, строка secret/my-application соответствует пути, по которому мы можем найти пары ключ-значение для my-application .

4.1. Секреты Ключ-значение

Секреты ключ-значение-это, как следует из названия, простые пары, доступные по заданному пути . Например, мы можем хранить пару foo=bar под путем /secret/my-application.

Позже мы используем один и тот же путь для извлечения одной и той же пары или пар – несколько пар могут храниться под одним и тем же путем.

Хранилище поддерживает три вида секретов ключ-значение:

  • Неверсионные пары ключей , где обновления заменяют существующие значения
  • Пары ключей версий, которые поддерживают настраиваемое количество старых версий
  • Cubyhole , специальный тип неверсионных пар ключей, значения которых ограничены областью действия

Секреты ключ-значение статичны по своей природе, поэтому нет понятия связанного с ними истечения срока действия. Основным вариантом использования такого рода секрета является хранение учетных данных для доступа к внешним системам, таким как ключи API.

В таких сценариях обновление учетных данных-это полуавтоматический процесс, обычно требующий, чтобы кто-то приобрел новые учетные данные и использовал командную строку Хранилища или его пользовательский интерфейс для ввода новых значений.

4.2. Динамически Генерируемые Секреты

Динамические секреты генерируются на лету хранилищем по запросу приложения . Хранилище поддерживает несколько типов динамических секретов, в том числе следующие:

  • Учетные данные базы данных
  • Пары ключей SSH
  • Сертификаты X. 509
  • Учетные данные AWS
  • Учетные записи облачных сервисов Google
  • Учетные записи Active Directory

Все они следуют одному и тому же шаблону использования. Во-первых, мы настраиваем секретный движок с деталями, необходимыми для подключения к соответствующей службе. Затем мы определяем одну или несколько ролей , которые описывают фактическое создание секрета.

Давайте возьмем в качестве примера механизм секрета базы данных. Во-первых, мы должны настроить хранилище со всеми данными о подключениях к базе данных пользователей, включая учетные данные ранее существовавшего пользователя с правами администратора для создания новых пользователей.

Затем мы создаем одну или несколько ролей (роли преподавателей, а не роли базы данных), содержащих фактические инструкции SQL, используемые для создания нового пользователя. Они обычно включают в себя не только инструкцию создания пользователя, но и все необходимые инструкции grant , необходимые для доступа к объектам схемы (таблицам, представлениям и т. Д.).

Когда клиент обращается к соответствующему API, Vault создаст нового временного пользователя в базе данных с помощью предоставленных инструкций и вернет его учетные данные . Затем клиент может использовать эти учетные данные для доступа к базе данных в течение периода, определенного атрибутом time-to-live запрашиваемой роли.

Как только срок действия учетных данных истечет, Vault автоматически отменит все привилегии, связанные с этим пользователем. Клиент также может запросить Vault обновить эти учетные данные. Процесс обновления будет выполняться только в том случае, если он поддерживается конкретным драйвером базы данных и разрешен соответствующей политикой.

4.3. Криптографические ключи

Секретные механизмы типа обрабатывают криптографические функции, такие как шифрование, дешифрование, подпись и так далее. Все эти операции используют криптографические ключи, сгенерированные и хранящиеся внутри хранилища . Если это не указано явно, Vault никогда не будет раскрывать данный криптографический ключ.

Связанный API позволяет клиентам отправлять текстовые данные хранилища и получать их зашифрованную версию. Возможно и обратное: мы можем отправить зашифрованные данные и получить обратно исходный текст.

В настоящее время существует только один двигатель этого типа: двигатель Transit . Этот движок поддерживает популярные типы ключей, такие как RSA и ECDSA, а также поддерживает Конвергентное шифрование. При использовании этого режима заданное значение открытого текста всегда приводит к одному и тому же результату зашифрованного текста, свойство, которое очень полезно в некоторых приложениях.

Например, мы можем использовать этот режим для шифрования номеров кредитных карт в таблице журнала транзакций. При конвергентном шифровании каждый раз, когда мы вставляем новую транзакцию, зашифрованное значение кредитной карты будет одинаковым, что позволит использовать регулярные SQL-запросы для отчетности, поиска и так далее.

5. Настройка хранилища

В этом разделе мы создадим локальную тестовую среду, чтобы проверить возможности хранилища.

Развертывание хранилища просто: просто загрузите пакет , соответствующий вашей операционной системе, и извлеките его исполняемый файл ( vault или vault.exe в Windows) в какой-то каталог на нашем ПУТИ. Этот исполняемый файл содержит сервер, а также является стандартным клиентом . Существует также официальный образ докера , но мы не будем его здесь освещать.

Vault поддерживает режим development , который отлично подходит для быстрого тестирования и привыкания к инструменту командной строки, но он слишком упрощен для реальных случаев использования: все данные теряются при перезапуске, а доступ к API использует простой HTTP .

Вместо этого мы будем использовать постоянное хранилище на основе файлов и установочный HTTPS, чтобы мы могли изучить некоторые детали конфигурации в реальной жизни, которые могут быть источником проблем.

5.1. Запуск сервера Хранилища

Хранилище использует файл конфигурации в формате HCL или JSON. Следующий файл определяет всю конфигурацию, необходимую для запуска нашего сервера с использованием хранилища файлов и самозаверяющего сертификата:

storage "file" {
  path = "./vault-data"
}
listener "tcp" {
  address = "127.0.0.1:8200"
  tls_cert_file = "./src/test/vault-config/localhost.cert"
  tls_key_file = "./src/test/vault-config/localhost.key"
}

А теперь давайте запустим Хранилище. Откройте командную оболочку, перейдите в каталог, содержащий

$ vault server -config ./vault-test.hcl

Хранилище запустится и покажет несколько сообщений об инициализации. Они будут включать его версию,

5.2. Инициализация Хранилища

Наш сервер хранилища сейчас работает, но так как это его первый запуск, нам нужно его инициализировать.

Давайте откроем новую оболочку и выполним следующие команды для достижения этой цели:

$ export VAULT_ADDR=https://localhost:8200
$ export VAULT_CACERT=./src/test/vault-config/localhost.cert
$ vault operator init

Здесь мы определили несколько переменных среды, поэтому нам не нужно каждый раз передавать их в хранилище в качестве параметров:

  • VAULT_ADDR : базовый URI, где наш сервер API будет обслуживать запросы
  • VAULT_CACERT : Путь к открытому ключу сертификата нашего сервера

В нашем случае мы используем VAULT_CACERT , поэтому мы можем использовать HTTPS для доступа к API хранилища. Нам это нужно, потому что мы используем самозаверяющие сертификаты. Это не было бы необходимо для производственных сред, где у нас обычно есть доступ к сертификатам, подписанным центром сертификации.

После выполнения приведенной выше команды мы должны увидеть сообщение, подобное этому:

Unseal Key 1: 
Unseal Key 2: 
Unseal Key 3: 
Unseal Key 4: 
Unseal Key 5: 

Initial Root Token: 

... more messages omitted

Пять первых строк-это общие ресурсы главного ключа, которые мы позже будем использовать для вскрытия хранилища хранилища. Пожалуйста, обратите внимание, что Хранилище отображает только общий главный ключ во время инициализации – и никогда больше. Примите к сведению и храните их в безопасности, иначе мы потеряем доступ к нашим секретам при перезагрузке сервера!

Кроме того, пожалуйста , обратите внимание на токен root , так как он нам понадобится позже. В отличие от ключей unseal, корневые токены могут быть легко сгенерированы позже , поэтому их можно безопасно уничтожить после завершения всех задач настройки. Поскольку позже мы будем выдавать команды, требующие маркера аутентификации, давайте пока сохраним корневой маркер в переменной среды:

$ export VAULT_TOKEN= (Unix/Linux)

Давайте посмотрим состояние нашего сервера теперь, когда мы его инициализировали, с помощью следующей команды:

$ vault status
Key                Value
---                -----
Seal Type          shamir
Sealed             true
Total Shares       5
Threshold          3
Unseal Progress    0/3
Unseal Nonce       n/a
Version            0.10.4
HA Enabled         false

Мы видим, что Хранилище все еще запечатано. Мы также можем следить за ходом вскрытия: “0/3” означает, что хранилище нуждается в трех общих ресурсах, но не получило ни одного

5.3. Вскрытие хранилища

Теперь мы вскрываем хранилище, чтобы начать использовать его секретные службы. Нам нужно предоставить любые три из пяти ключевых акций, чтобы завершить процесс вскрытия:

$ vault operator unseal 
$ vault operator unseal 
$ vault operator unseal 

После выполнения каждой команды хранилище распечатает ход выполнения вскрытия, включая количество необходимых общих ресурсов. После отправки последнего общего ключа мы увидим сообщение, подобное этому:

Key             Value
---             -----
Seal Type       shamir
Sealed          false
... other properties omitted

Свойство “Sealed” в этом случае имеет значение “false”, что означает, что хранилище готово принимать команды.

6. Хранилище для тестирования

В этом разделе мы протестируем настройку хранилища с использованием двух поддерживаемых типов безопасности: Ключ/Значение и база данных. Мы также покажем, как создавать новые токены с привязанными к ним конкретными политиками.

6.1. Использование Секретов Ключа/Значения

Во-первых, давайте сохраним пары секретный ключ-значение и прочитаем их обратно. Предполагая, что командная оболочка, используемая для инициализации хранилища, все еще открыта, мы используем следующую команду для хранения этих пар под secret/fakebank path:

$ vault kv put secret/fakebank api_key=abc1234 api_secret=1a2b3c4d

Теперь мы можем восстановить эти пары в любое время с помощью следующей команды:

$ vault kv get secret/fakebank
======= Data =======
Key           Value
---           -----
api_key       abc1234
api_secret    1a2b3c4d

Этот простой тест показывает нам, что хранилище работает так, как должно. Теперь мы можем протестировать некоторые дополнительные функции.

6.2. Создание Новых Токенов

До сих пор мы использовали корневой токен для аутентификации наших запросов. Поскольку корневой токен way слишком мощный, рекомендуется использовать токены с меньшим количеством привилегий и более коротким временем жизни.

Давайте создадим новый токен, который мы можем использовать так же, как корневой токен, но срок действия которого истекает через минуту:

$ vault token create -ttl 1m
Key                  Value
---                  -----
token                
token_accessor       
token_duration       1m
token_renewable      true
token_policies       ["root"]
identity_policies    []
policies             ["root"]

Давайте протестируем этот токен, используя его для чтения пар ключ/значение, которые мы создали ранее:

$ export VAULT_TOKEN=
$ vault kv get secret/fakebank
======= Data =======
Key           Value
---           -----
api_key       abc1234
api_secret    1a2b3c4d

Если мы подождем минуту и попытаемся переиздать эту команду, мы получим сообщение об ошибке:

$ vault kv get secret/fakebank
Error making API request.

URL: GET https://localhost:8200/v1/sys/internal/ui/mounts/secret/fakebank
Code: 403. Errors:

* permission denied

Сообщение указывает на то, что наш токен больше не действителен, чего мы и ожидали.

6.3. Политика тестирования

Образец токена, который мы создали в предыдущем разделе, был недолговечным, но все еще очень мощным. Теперь давайте использовать политики для создания более ограниченных токенов.

Например, давайте определим политику, которая разрешает доступ только для чтения к пути secret/fakebank , который мы использовали ранее:

$ cat > sample-policy.hcl <
$ vault policy write fakebank-ro ./sample-policy.hcl
Success! Uploaded policy: fakebank-ro

Теперь мы создаем токен с этой политикой с помощью следующей команды:

$ export VAULT_TOKEN=
$ vault token create -policy=fakebank-ro
Key                  Value
---                  -----
token                
token_accessor       
token_duration       768h
token_renewable      true
token_policies       ["default" "fakebank-ro"]
identity_policies    []
policies             ["default" "fakebank-ro"]

Как мы уже делали раньше, давайте прочитаем наши секретные значения, используя этот токен:

$ export VAULT_TOKEN=
$ vault kv get secret/fakebank
======= Data =======
Key           Value
---           -----
api_key       abc1234
api_secret    1a2b3c4d

Пока все идет хорошо. Мы можем считывать данные, как и ожидалось. Давайте посмотрим, что произойдет, когда мы попытаемся обновить этот секрет:

$ vault kv put secret/fakebank api_key=foo api_secret=bar
Error writing data to secret/fakebank: Error making API request.

URL: PUT https://127.0.0.1:8200/v1/secret/fakebank
Code: 403. Errors:

* permission denied

Поскольку наша политика явно не разрешает запись, Vault возвращает код состояния 403 – Доступ запрещен.

6.4. Использование Учетных Данных Динамической Базы Данных

В качестве последнего примера в этой статье давайте используем механизм секрета базы данных Vault для создания динамических учетных данных. Здесь мы предполагаем, что у нас есть сервер MySQL, доступный локально, и что мы можем получить к нему доступ с правами “root”. Мы также будем использовать очень простую схему, состоящую из одной таблицы – account .

Сценарий SQL, используемый для создания этой схемы, и привилегированный пользователь доступны здесь.

Теперь давайте настроим хранилище для использования этой базы данных. Механизм секрета базы данных по умолчанию не включен, поэтому мы должны исправить это, прежде чем мы сможем продолжить:

$ vault secrets enable database
Success! Enabled the database secrets engine at: database/

Теперь мы создаем ресурс конфигурации базы данных:

$ vault write database/config/mysql-fakebank \
  plugin_name=mysql-legacy-database-plugin \
  connection_url="{{username}}:{{password}}@tcp(127.0.0.1:3306)/fakebank" \
  allowed_roles="*" \
  username="fakebank-admin" \
  password="Sup&rSecre7!"

Префикс пути database/config – это место, где должны храниться все конфигурации базы данных. Мы выбираем имя mysql-поддельный банк , чтобы мы могли легко выяснить, к какой базе данных относится эта конфигурация. Что касается конфигурационных ключей:

  • plugin_name: Определяет, какой плагин базы данных будет использоваться. Доступные имена плагинов описаны в Vault’s docs
  • connection_url : Это шаблон, используемый плагином при подключении к базе данных. Обратите внимание на заполнители шаблонов {{имя пользователя}} и {{пароль}}. При подключении к базе данных Vault заменит эти заполнители фактическими значениями
  • allowed_roles : Определите, какие роли хранилища (обсуждаемые далее) могут использовать эту конфигурацию. В нашем случае мы используем “*”, поэтому он доступен для всех ролей
  • имя пользователя и пароль: Это учетная запись, которую Vault будет использовать для выполнения операций с базой данных, таких как создание нового пользователя и отзыв его привилегий

Настройка роли базы данных Хранилища

Конечная задача настройки-создать ресурс роли базы данных хранилища, содержащий команды SQL, необходимые для создания пользователя. Мы можем создать столько ролей, сколько необходимо, в соответствии с нашими требованиями безопасности.

Здесь мы создаем роль, которая предоставляет доступ только для чтения ко всем таблицам схемы fake bank :

$ vault write database/roles/fakebank-accounts-ro \
    db_name=mysql-fakebank \
    creation_statements="CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}';GRANT SELECT ON fakebank.* TO '{{name}}'@'%';"

Компонент database engine определяет префикс пути база данных/роли в качестве местоположения для хранения ролей. fakebank-accounts-ro – это имя роли, которое мы позже будем использовать при создании динамических учетных данных. Мы также поставляем следующие ключи:

  • db_name : Имя существующей конфигурации базы данных. Соответствует последней части пути, который мы использовали при создании ресурса конфигурации
  • creation_statements: Список шаблонов инструкций SQL, которые Vault будет использовать для создания нового пользователя

Создание Динамических Учетных данных

Как только у нас будет готова роль базы данных и соответствующая конфигурация, мы создадим новые динамические учетные данные с помощью следующей команды:

$ vault read database/creds/fakebank-accounts-ro
Key                Value
---                -----
lease_id           database/creds/fakebank-accounts-ro/0c0a8bef-761a-2ef2-2fed-4ee4a4a076e4
lease_duration     1h
lease_renewable    true
password           
username           

Префикс database/creds используется для создания учетных данных для доступных ролей. Поскольку мы использовали роль fake bank-accounts-ro , возвращенное имя пользователя/пароль будет ограничено операциями select .

Мы можем проверить это, подключившись к базе данных с помощью предоставленных учетных данных, а затем выполнив некоторые команды SQL:

$ mysql -h 127.0.0.1 -u  -p fakebank
Enter password:
MySQL [fakebank]> select * from account;
... omitted for brevity
2 rows in set (0.00 sec)
MySQL [fakebank]> delete from account;
ERROR 1142 (42000): DELETE command denied to user 'v-fake-9xoSKPkj1'@'localhost' for table 'account'

Мы видим, что первый select успешно завершен, но мы не смогли выполнить инструкцию delete /. Наконец, если мы подождем один час и попытаемся подключиться, используя те же учетные данные, мы больше не сможем подключиться к базе данных. Хранилище автоматически отозвало все привилегии у этого пользователя

7. Заключение

В этой статье мы изучили основы хранилища Hashicorp, включая некоторые сведения о проблеме, которую он пытается решить, его архитектуре и базовом использовании.

Попутно мы создали простую, но функциональную тестовую среду, которую хорошо использовать в последующих статьях.

В следующей статье будет рассмотрен очень конкретный случай использования Vault: Использование его в контексте приложения Spring Boot . Оставайтесь с нами!