Управление всеми вашими секретами с помощью Vault. Обзор и практические примеры.

от переводчика: чтобы некоторые термины усвоились более нативно, следует понимать, что Vault переводится с английского как «погреб/подвал». А ещё так обозначались убежища на случай ядерного апокалипсиса, что фигурируют в серии игр Fallout.

Когда Hashicorp выпустила Vault — open-source инструмент для управления секретами (пароли, ключи API и т.д.), мне не терпелось поскорее попробовать его в деле. Управление sensitive информацией, это значительная проблема в мире DevOps. Я повидал и испробовал множество разных подходов за последние годы, и ни один из них не отличается особой простотой или масштабируемостью:

  • Генерация разных паролей для каждого сервера/БД и т.д. Можно начать с чего-то из 32х символов типа T\ppktB>4TQXqz@"-sx=zfHz82q7r
    Проблемы этого подхода: где хранить все эти пароли; как их шарить с командой; как отзывать доступы, когда кто-то покинул команду и вы не хотели бы менять все пароли до единого.
  • Для инфраструктуры можно шифровать sensitive данные через CAPS инструмент. chef-vault для Chef, ansible-vault для Ansible, Hiera для Puppet и Pillars для SaltStack.
    Проблемы: невозможно отозвать доступ; нельзя использовать в приложениях или шарить с нетехническими членами команды.
  • Подход разработчика. Шифровать файлы с sensitive данными и хранить их в репозитории.
    Проблемы: сгодится, если вы сами по себе.
  • Использовать third party приложения, типа 1Password или Keypass.
    Проблемы: работает неплохо, чтобы шарить информацию в команде, но нельзя отозвать доступ. Не работает для инфраструктуры или приложений.
  • Использовать SaaS приложения вроде Lastpass. Хорошо работает для шеринга и отзыва доступа.
    Проблемы: не подойдёт для инфраструктуры или приложений. Хранение sensitive данных у третьих лиц, где у вас нет контроля, плохое решение в большинстве случаев.

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

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

Приступая к работе с Vault

Vault написан на Go и распространяется как статично собраный бинарник — это отличный вариант, чтобы протестировать всё прямо на локальной машине.

Мелкое неудобство, которые вы сразу можете заметить — проект не имеет готовых deb/rpm файлов или официальных репозиториев. Это делает несколько затратным процесс развёртывания Vault в Проде — придётся искать/писать/поддерживать собственные init скрипты и скрипты организующие CAPS. Как вариант, вы можете развернуть Vault в Docker контейнере или через Suprvisord.

Как только скачан бинарник, вы сразу же можете исполнять команды без какого-либо дополнительного конфигурирования. Вот так выглядит “hello world” в Vault. Чуть ниже мы сохраним ключ API от Digital Ocean и затем извлечём это значение.

vault server -dev
export VAULT_ADDR='http://127.0.0.1:8200' # Put this in your .bashrc/zshrc file

vault write secret/digitalocean-api-key value=7175b4cfff396de2c136d052bfac6b0d4
Success! Data written to: secret/digitalocean-api-key

vault read secret/digitalocean-api-key
Key Value
lease_duration 2592000
value 7175b4cfff396de2c136d052bfac6b0d4

# Just the value
value read -field=value secret/digitalocean-api-key
7175b4cfff396de2c136d052bfac6b0d4

Чтобы получить ключ API от DigitalOcean из ваших приложений, вам следует сделать что-то вроде такого:

# Using Python for this example, should be similar in other languages.
import requests
headers = {"X-Vault-Token": "b30ee2a3-ea4b-9da0-3e5c-4189d375cad9"}

r = requests.get('http://127.0.0.1:8200/v1/secret/digitalocean-api-key', headers=headers)
json_response = r.json()
# {u'lease_id': u'', u'warnings': None, u'auth': None, u'lease_duration': 2592000,
# u'data': {u'value': u'7175b4cfff396de2c136d052bfac6b0d4'}, u'renewable': False}

if r.status_code == 200:
api_key = json_response.get('data',{}).get('value', "")
# 7175b4cfff396de2c136d052bfac6b0d4

В ваших приложениях можно завернуть эту логику в функцию:

def vault_get_secret(value):
request ....
return value

# settings.py
API_KEY = vault_get_secret('digitalocean-api-key')

Концепции Vault

Sealing (Запечатывание)/Unsealing (Распечатывание) Vault

Информация, которую вы храните в Vault, защищается мастер-ключом. Vault использует его, чтобы кодировать/декодировать секреты. Мастер-ключ сам по себе недоступен и реконструируется каждый раз, когда вы запускаете/перезапускаете Vault.

Чтобы всё работало надёжно, Vault использует алгоритм Shamir’s Secret Sharing (Схема разделения секрета Шамира). Мастер-ключ по-умолчанию разделяется на 5 ключей — это называется number of shares (число сторон). Для реконструкции мастер-ключа вам понадобится предоставить любые 3 из 5 ключей — это называется threshold (порог). Число сторон и порог полностью кастомизируемые значения в зависимости от имеющихся потребностей. Это отлично объясняется в официальной документации и вот в этой статье принцип работы алгоритма раскрывается ещё полнее — с видео и примерами кода.

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

Авторизация и Tokens (Токены)

После того, как вы распечатали Vault, придётся произвести авторизацию. Токены — метод авторизации, используемый по-умолчанию. Вы получаете токены для admin/root, когда инициализируете Vault — с помощью vault init или vault server -dev. Токен root-а следует использовать только для конфигурации.

# Authenticate with the root token
vaul auth b30ee2a3-ea4b-9da0-3e5c-4189d375cad9

# This is still a root token, can be revoked, doesn't expire
vault token-create

Key Value
token f125ca98-a6dc-07da-bc48-a8cafce57889
token_duration 0
token_renewable false
token_policies [root]

vault token-revoke f125ca98-a6dc-07da-bc48-a8cafce57889

Revocation successful.

# Create a token with limited permissions
vault token-create -policy=djangoapp

Key Value
token 859a8125-d221-d1dd-b709-4629c1e9591b
token_duration 2592000
token_renewable true
token_policies [djangoapp default]

vault policies djangoapp

path "secret/djangoapp/*" {
policy = "read"
}

В Vault версии 0.4, которую я тестирую (в момент написания перевода доступна уже версия 0.8.0 — прим. переводчика), вы не можете вывести список токенов после их создания. Такая возможность описана в roadmap следующих релизов, но пока функционала нет, придётся вести учёт в стороннем приложении.

от переводчика: быстрый поиск в google о том, был ли этот функционал создан за прошедшее время, привёл меня к обсуждению в официальной Google Group. Вкратце — возможность list tokens может раскрыть важную информацию о секретах и доступах; это небезопасно – реализоваться не будет.

Важные моменты, которые следует помнить про Авторизацию и Токены.

  • Чтобы использовать Vault в терминале, следует авторизоваться. По-умолчанию — через токены.
  • Используя Vault из приложения или скрипта для CAPS, понадобится только токен, без авторизации.

Каждый токен может быть отозван и иметь разные уровни доступа, что контролируется через Policies (Политики). Политики в Vault, это ACL (Access Control List).

Policies (Политики)

Политики в Vault работают как chown/users в Unix — у вас есть пользователь root с доступом ко всему и отдельные пользователи с доступом только к определённому пути.

# djangoapp.hcl
path "secret/djangoapp/*" {
policy = "read"
}

# authenticate with the root token
vault auth 8a5dbab4-43cc-8b8d-e6a6-04d5e458dca9

# apply the policy, you can change it at any time and reapply with the same command
vault policy-write djangoapp djangoapp.hcl


# This token can only read secrets from secret/djangoapp/*
vault token-create -policy=djangoapp

Key Value
token cc9a61f9-0c40-27ff-74aa-5a082c4d269f
token_duration 2592000
token_renewable true
token_policies [djangoapp default]

# write some secrets
vault write secret/djangoapp/mongo-auth value="martinrusev:8PV2NW6k@192.168.0.1:27017"
vault write secret/djangoapp/digitalocean-api-key value=7175b4cfff396de2c136d052bfac6b0d4


vault auth cc9a61f9-0c40-27ff-74aa-5a082c4d269f

vault read secret/djangoapp/digitalocean-api-key

Key Value
lease_duration 2592000
value 7175b4cfff396de2c136d052bfac6b0d4

Backends (Бэкенд)

Бэкенды — ключевые компоненты всего Vault. Вы уже видели дефолтный бэкенд типа generic, где все данные хранятся в пути secret. Это работает похоже на файловую систему Unix – вы можете производить mount/unmount различных типов для путей.

$ vault mounts
Path Type Default TTL Max TTL Description
secret/ generic system system generic secret storage
sys/ system n/a n/a system endpoints used for control ...

vault mount -path=django -description="Secrets used in a Django project" generic

vault mounts
Path Type Default TTL Max TTL Description
secret/ generic system system generic secret storage
django/ generic system system Secrets used in a Django project
sys/ system n/a n/a system endpoints used for control ...

# We can write our data in this namespace
vault write django/aws-secret-key value="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
vault write django/aws-access-key value="AKIAIOSFODNN7EXAMPLE"

Каждый бэкенд служит разным целям:

  • mysql и postgresql бэкенды — можете использовать их для динамического создания/удаления пользователей БД с определёнными наборами привелегий;
  • aws — позволит вам создавать/удалять Amazon credentials на основании политик IAM;
  • ssh — вы можете использовать его для хранения/раздачи приватных SSH ключей;
  • cubbyhole — этот бэкенд работает как уникальное пространство имён для каждого токена. Уничтожение токена удаляет также все данные в его cubbyhole пространстве.

Установка Vault

Для развёртывания Vault в Проде, вам понадобится init скрипт, который в комплект не входит. Можно написать свой, упаковать Vault в Docker контейнер (самый простой вариант) или демонизировать его с помощью Supervisord.

Следующий этап — выбор хранилища: места, где Vault будет хранить ваши sensitive данные. Можно использовать файлы, S3, MySQL, Consul и т.д.

Лично я нахожу S3 сбалансированным решением между простотой использования и надёжностью. В Vault версии 0.4 вы не можете вывести список секретов, но сможете проверить их через Amazon Console.

# vault.hcl
backend "s3" {
bucket = "vault"
access_key = "AKIAIPR2HA"
secret_key = "nO6TK2NAPpZkBf+iSWrnQAojIp"
region = "eu-west-1"
}

listener "tcp" {
address = "127.0.0.1:8200"
tls_disable = 1
}

vault server -config=vault.hcl

vault init

# Key 1: 4cdc4cccb9e2ddda8a2163e8d1a1b94522e6e9c6d25d6a5a12e9677262547c1401
# Key 2: 8b94a7e4614956778ccce9a185d736e9d4a86dd75ca588056f9c10da60a8f31d02
# Key 3: 42378fbd9549091da0bcf6c14f9287e961e0738eb129b4b28d79538e702ab9db03
# Key 4: b35c835644358269219fd75378507380d9cc76ca47fe5f64ce28b28e9eb5f82c04
# Key 5: 7affab0fb035dd030defc833b215c2806c846893aa7263d32ccdf1da8e37b2ea05
# Initial Root Token: 8a5dbab4-43cc-8b8d-e6a6-04d5e458dca9

# You have to provide any 3 of the 5 keys printed to stdout after the init command
vault unseal

# authenticate with the root token, configure Vault, set policies, etc.
vault auth 8a5dbab4-43cc-8b8d-e6a6-04d5e458dca9

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

Вариантом попроще для охраны вашего экземпляра Vault может стать фронтенд через nginx/apache. К примеру, вы можете настроить basic auth или разрешить доступ только с определённых IP.

# Full configuration at https://mozilla.github.io/server-side-tls/ssl-config-generator/
# /etc/nginx/sites-enabled/vault
server {
listen 80;
listen 443 ssl;
server_name vault;
return 301 https://vault.yourdomain.com$request_uri;
}

server {
listen 443 ssl;
location / {
proxy_buffering off;
proxy_pass http://127.0.0.1:8200;
proxy_redirect off;
proxy_set_header Host $http_host;
}
}

Моё впечатление от Vault

Я недавно документировал мой опыт работы с Terraform, другим проектом Hashicorp, который я часто использую. Опыт работы с Vault был очень похож — действительно уникальный и стоящий проект, однозначно заслуживающий добавления к инструментарию DevOps.

Из минусов — крутая кривая обучения, нехватка документации, мало описанных примеров. Есть вероятность, что решать задачи/проблемы придётся в google groups, stackoverflow и т.д., что может отнимать много времени.


P.S.: Если вам понравилась эта статья — нажмите зеленое сердечко. Это много значит для меня. Спасибо!

Нашли ошибку? Воспользуйтесь функцией Private notes: выделяете текст с ошибкой, нажимаете на символ замка в появившемся дудле и оставляете свой комментарий. Спасибо!

Перевод статьи Managing all your secrets with Vault — Review and Walkthrough, написаной Martin Rusev для amon.cx.

Идею дизайна для поста с переводом украл у Workafrolic (±∞), спасибо!