Управление секретами и почему это так важно для нас?

Привет! Меня зовут Евгений, я работаю на позиции Lead DevOps в EXANTE. В этой статье мы разберем жизненный опыт сетапа high availability Hashicorp Vault с gcp storage backend и auto unseal в k8s.

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

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

Мы решили сделать наш продукт cloud native, и для этого нужно было изменить подход к разработке и инфраструктуре, провести рефакторинг наших легаси сервисов, начать двигаться в сторону микросервисной архитектуры, разворачивать сервисы в cloud k8s, использовать managed ресурсы (redis, postgres).

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

Почему Hashicorp Vault?

У нас есть несколько причин:

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

  2. Hashicorp Vault – наиболее популярный инструмент с необходимой функциональностью (хранение секретов, управление доступом к секретам, инъекция секретов в поды k8s, интеграция с chef, gitlab ci).

  3. Наличие практического опыта у наших devops инженеров в конфигурировании HA и unseal.

  4. Возможность в дальнейшем интегрировать в наш k8s кластер Secret injection webhook.

Где и в какой конфигурации мы разворачиваем Hashicorp Vault?

Мы разворачиваем Hashicorp Vault в k8s кластере на отдельном нодпуле.

С точки зрения конфигурации, мы используем подход с автоматическим распечатыванием хранилища при помощи gcpckms в момент рестарта подов Hashicorp Vault. В качестве storage backend для хранения данных Hashicorp Vault мы используем Google Cloud Storage, так как это позволяет просто и дешево кластеризовать сервис Hashicorp Vault.

Почему нам так важен автоматический unseal?

Здесь все довольно просто – на данный момент большая часть сервисов получает секреты в виде переменных окружения при помощи Vault Secret injection webhook, именно поэтому нам необходим автоматический unseal: без него мы потенциально столкнемся с недоступностью сервисов Hashicorp Vault и отсутствием возможности передать переменные окружения в сервисы при любых манипуляциях с подами (рестарт, новый релиз и т.д.)

Что необходимо иметь для настройки HA с gcs storage backend и gcpckms auto unseal?

  1. Сервисный аккаунт для Hashicorp Vault.

  2. GCS bucket.

  3. Keyring + cryptokey.

Мы создаем необходимые сущности при помощи terraform.

Подробнее про iam политики для сервисного аккаунта и про связку keyring и cryptokey gcpckms можно прочитать в официальной документации. 

Каким образом мы разворачиваем Hashicorp Vault в k8s?

В k8s кластере мы используем подход GitOps при помощи инструмента Flux CD. Соответственно все новые приложения деплоятся в кластер через репозиторий Flux CD. Мы не будем вдаваться в подробности использования GitOps в этой статье.
Для шифрования первичных секретов (необходимых для развертывания Hashicorp Vault) мы используем SOPS. SOPS — редактор зашифрованных файлов, поддерживающий форматы YAML, JSON, ENV, INI и BINARY и шифрующий с помощью AWS KMS, GCP KMS, Azure Key Vault, age и PGP. Мы используем age, и ключ для расшифровки находится в секретах k8s.


Мы конфигурируем Hashicorp Vault следующим образом:


- HA режим (3 реплики).

- GCS storage backend.

- Auto unseal при помощи gcpckms.

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

apiVersion: v1
kind: Secret
metadata:
    name: vault-gcs
    namespace: vault
type: Opaque
data:
    Vault_gcs_key.json: <base64-serviceaccount>


Для корректной работы Hashicorp Vault в указанной конфигурации необходимо пробросить в под файл с нашим сервисным аккаунтом и указать дополнительные переменные окружения. Таким образом, мы наполняем файл values.yaml:

server:
  enabled: true
  extraEnvironmentVars:
    GOOGLE_APPLICATION_CREDENTIALS: /vault/userconfig/vault-gcs/vault_gcs_key.json
    GOOGLE_PROJECT: your-project
  extraVolumes:
  - name: vault-gcs
    path: /vault/userconfig
    type: secret

Далее мы продолжаем наполнять values.yaml. Важно корректно настроить конфиг HA для работы в несколько реплик и поддержки gcs storage backend + gcpckms unseal. В конечном итоге values.yaml выглядит следующим образом:

server:
  enabled: true
  extraEnvironmentVars:
    GOOGLE_APPLICATION_CREDENTIALS: /vault/userconfig/vault-gcs/vault_gcs_key.json
    GOOGLE_PROJECT: your-project
  extraVolumes:
  - name: vault-gcs
    path: /vault/userconfig
    type: secret
  ha:
    config: |
      ui = true
      listener "tcp" {
        address = "[::]:8200"
        cluster_address = "[::]:8201"
      }
      storage "gcs" {
        bucket     = "bucket-name"
        ha_enabled = "true"
      }
      seal "gcpckms" {
        project     = "gcp-project-name"
        region      = "global"
        key_ring    = "your-keyring"
        crypto_key  = "your-cryptokey"
      }
    enabled: true
    replicas: 3

Дополнительно в нашем helm chart используются настройки внутреннего ingress, но они довольно специфичные и для общего понимания не требуются. Помимо этого, мы отключаем использование vault-agent-injector, данные параметры можно настроить самостоятельно на основе примера в официальном helm-chart.

Установка в кластер производится при помощи Flux CD и полностью автоматизирована, используется официальный helm chart от hashicorp.

После успешной установки мы имеем три пода vault-0, vault-1, vault-2 в неймспейсе vault. Для успешного запуска сервиса достаточно выполнить команду:

kubectl exec -ti vault-0 -- vault operator init

В результате выполнения получаем root token и пять recovery keys. 

Настоятельно рекомендуем сохранить эти данные, так как их утрата является фатальной и фактически отрезает доступ к управлению Hashicorp Vault кластером.

Мы провели сравнительное тестирование производительности Hashicorp Vault с разными storage backend. Мы запускали его с postgresql, consul, aws s3, gcs. В наших тестах gcs был примерно в 10 раз медленнее, чем postgresql.


Поскольку для нас скорость отдачи секретов не критична и приоритетом является возможность удобного auto unseal, быстрой интеграции с storage backend – было принято решение использовать gcs.

Наш k8s работает в такой конфигурации с Hashicorp Vault два года, на текущий момент мы не встречали проблем в использовании данной конфигурации.

Итоги:

Hashicorp Vault для нас – это постоянно доступный, единый и безопасный источник правды с разграничением доступа к секретам и различными методами авторизации. Это простой в использовании и конфигурировании инструмент, имеющий актуальную документацию. Он позволяет интегрировать Secret injection webhook, который предоставляет необходимую функциональность: создавать последующие секреты внутри кластера без SOPS шифрования, импортируя их прямо из хранилища, интегрировать практически любые другие инструменты и импортировать в них секреты из хранилища (ci, k8s поды, chef и т.д), но об этом – в следующий раз!

Комментарии (10)


  1. abakarowar
    29.08.2024 15:28

    отличная статья! возьму на заметку!)


  1. Kaloud
    29.08.2024 15:28

    Привет! Интересная статья! Круто


  1. smeniugli
    29.08.2024 15:28

    Прекрасно! Меняю угли и иду делать!


  1. Alexxlow
    29.08.2024 15:28

    Хорошая и рабочая статья’


  1. IgorekProkuratura
    29.08.2024 15:28

    Cтатья 10 из 10, автор гений


  1. smotryashii
    29.08.2024 15:28

    Интересный подход к использованию gcpckms и gsc для HA


  1. eigrad
    29.08.2024 15:28

    То есть безопасность всех секретов у вас заложена в ключ сервис аккаунта зашифрованный sops..? А расшифровывается он как?


  1. eigrad
    29.08.2024 15:28

    Смущает что pod'а три а не два, не смотря на то что используется gcs. Но в целом конечно пофиг.


  1. eigrad
    29.08.2024 15:28
    +1

    их утрата является фатальной и фактически отрезает доступ к управлению кластером

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

    рекавери ключи изначально должны быть выведены в зашифрованном виде, доступны для расшифровки только хранителями разделенного секрета, и понадобятся они в случае gkms+gcs ровно никогда (ну либо root токен можно заранее не генерировать, его можно сделать новый при наличии кворума рекавери ключей)


  1. Artarik
    29.08.2024 15:28

    Вы все равно в Гугле сидите и используете management сервисы типа redis, postgres, зачем вам vault? Возьмите google secret manager + external secret operator. Как по мне, вряд ли стоимость секретов в облаке превысит стоимость затрачиваемых человеческих и железных ресурсов вашем кластере.