Vault
A tool for managing secrets.
Желательно проскролить по диагонали: https://github.com/hashicorp/vault
Vault - это тулзня от хашикорпа (по сути один бинарник на Голанге), который позволяет секурно управлять секретами. Секрет, как они говорят, это что угодно, к чему нужен гибкий доступ (АПИ ключи, пароли, сертификаты). Vault предоставляет унифицированный интерфейс к каждому секрету, и дает гибкий настраиваемый доступ с очень детальным логированием (кто что прочитал, кто что хотел прочитать и не смог).
Основные фичи:
-
сторедж для секретов
-
динамическая генерация секретов
-
шифрование данных
-
ttl секрета, регенерация
-
отзыв секрета
В общем, получается что это куча удобных фичей в одном флаконе.
Решение проблем
Со стороны инфраструктуры есть куча проблем, которые на данный момент никто не решает:
- пароли лежат плеин текстом в репке
Детальное описание проблемы:
Почти везде, где есть Infrastructure as Code (IaC) есть пару репо для Configuration management, где лежат настройки провижининга баз данных, менеджеров очередей, эндпоинтов других сервисов с аутентификацией, и так далее. Как правило, это не совсем секурно. Нужно бы как-то их оттуда убрать
- все знают все пароли
Детальное описание проблемы:
Окей, у нас пароли в репо, и нас это не беспокоит. Но вот проблема - есть несколько команд, и их менеджат разные люди. Например, если есть DBA - зачем ему знать креды к реббиту?
- при увольнении человека пароли никто не меняет
Детальное описание проблемы:
Периодически люди уходят, и очень желательно иметь одно место, в котором можно поменять пассворд, и это применится на всей инфраструктуре. Не так ли? Очень часто этот этап скипают, потому что нужно пройтись по куче мест, где захардкожен этот пароль (и не дай бог в самом апликейше), и ооочень большая вероятность где-то в одном маленьком месте забыть.
Анализ требований
Ок, если у нас будут лежать в Vault все пароли, то это должно быть: - сесурно (внезапно!), - отказоустойчиво, - гибко, - и вообще - модно.
В общем, все это примерно так и есть.
Перед внедрением
Перед внедрением нужно обязательно поднять шумиху по поводу сесурити, иначе кто потом оценит?
Внедрение
Выкачать бинарник на сервер, и на клиент (пока только себе).
Создаем очень простой конфиг на сервере: внимание - это не json, это hcl
backend "file" {
path = "/etc/vault/data/"
}
listener "tcp" {
address = "10.10.10.10:8200"
tls_disable = 1
}
tls_disable = 1
- это только в тестовых целях, конечно
Тут есть несколько нюансов. Vault умеет сторить зашифрованную информацию в файл, различные базы данных, эндпоинты и т.п. Для теста - в файл. Для прода - в какой-то постргрес в кластере и с репликацией.
Заходим куда-то, инициализируем сервер vault init
$ vault init
Key 1: 427cd2c310be3b84fe69372e683a790e01
Key 2: 0e2b8f3555b42a232f7ace6fe0e68eaf02
Key 3: 37837e5559b322d0585a6e411614695403
Key 4: 8dd72fd7d1af254de5f82d1270fd87ab04
Key 5: b47fdeb7dda82dbe92d88d3c860f605005
Initial Root Token: eaf5cc32-b48f-7785-5c94-90b5ce300e9b
Vault initialized with 5 keys and a key threshold of 3!
...
Он нам вернул 5 ключей для разблокировки сервера после рестарта, и один самый главный рут-токен. В целях безопасности, его лучше потом удалить.
Собственно, запускаем:
vault server -config server.hcl -log-level=debug
Крутяк. Сервер работает.
В консоли на клиенте
Доступ к серверу можно получить с консоли на клиенте, предварительно выкачав бинарник Vault. Для подключения к серверу нужно иметь 2 переменных окружения.
export VAULT_ADDR=http://10.10.10.10:8200
export VAULT_TOKEN=eaf5cc32-b48f-7785-5c94-90b5ce300e9b
VAULT_ADDR - это ендпоин для подключения к серверу, VAULT_TOKEN - это Initial Root Token.
Окей. Создаем бэкенд, в который будет точкой отправки для всех остальных секретов (грубо говоря, как хомяк сайта).
$ vault mount generic
Successfully mounted 'generic' at 'generic'!
Отлично, теперь туда можно что-то написать:
vault write secret/mysql/dev user=secure_user password=sdflksdncdsjn343434sddsf
Success! Data written to: secret/mysql/dev
Иерархия ключей тут древовидная, т.е. Vault знал только про бэкенд secret, но потом создал еще подпуть mysql,туда положил dev, и уже туда положил секреты.
Прочитать их можно подобным образом:
vault read secret/hello
Key Value
lease_duration 2764800
excited yes
user mysql
password sdflksdncdsjn343434sddsf
Вооо. Очень круто. Это работает.
Убираем пароли из репозитория
Ansible
В общем, то, как нужно их убрать - будет зависеть от того, что именно лежит в репке. Например, самый простой кейс - это Ansible.
Ссылка почитать и посмотреть: https://github.com/jhaals/ansible-vault
В нашем случае в vars.yml нужно будет написать такое вот:
mysql_user: "{{ lookup('vault', 'secret/mysql/dev').user }}"
mysql_pass: "{{ lookup('vault', 'secret/mysql/dev').password }}"
При запуске Ansible заберет креды из Vault, и положит их в вариейблы, которые дальше можно юзать в плейбуках. Подобный синтаксис будет работать и в шаблонах j2.
Chef
Ссылка почитать: https://www.hashicorp.com/blog/using-hashicorp-vault-with-chef.html
В кукбуках для подключения эндпоинта нужно будет заюзать такую вещь (непосредственно в рецепте):
require 'vault'
mysql_vault = Vault.logical.read("secret/mysql/dev")
mysql_user = mysql_vault.data[:user]
mysql_password = mysql_vault.data[:password]
Вроде не напряжно.
Аппликейшн
Конечно, можно забирать инфу из Vault прямо из апликейшна. К примеру, у нас в компании очень хорошо прижился и активно используется ChatOps, и это копипаст оттуда (при инициализации он забирает токен для слека и рандека). Посмотрите, как это работает.
Ссылка на пекедж для питончика: https://github.com/ianunruh/hvac
Подобные модули есть на большинство языков программирования.
И сам код питончика:
from hvac import Client
try:
client = Client(url=environ.get('VAULT_ADDR'), token=environ.get('VAULT_TOKEN'))
SLACK_TOKEN = client.read('secret/slack')['data']['key']
RUNDECK_TOKEN = client.read('secret/rundeck')['data']['token']
except Exception:
raise Exception('Can not get slack token from vault!')
Все очень и очень просто. Апп пытается загрести токен из переменных окружения, потом забрать нужные ему данные из Vault. Если у него не получается - он падает с ошибкой 'Can not get slack token from vault!'
.
Настраиваем гибкие ACL
К примеру, настроим ACL для mysql аппа:
mkdir acl && touch acl/mysql.hcl
И прописываем детально что ему можно, что ему нельзя:
path "secret/mysql/dev" {
policy = "write"
}
path "secret/mysql/uat" {
policy = "read"
}
path "secret/mysql/prod" {
policy = "read"
}
Заимпортим полиси на сервер: vault policy-write mysql acl/mysql.hcl
И сгенерим токен с помощью этого ACL:
vault token-create -display-name='mysql app' -ttl="100500h" -policy="mysql"
Теперь, этот токен будет видеть только то, что мы ему наконфигурили, и ничего больше. Кстати, токен автоматически заекспайрится когда придет TTL.
Увольняем сотрудника
vault token-revoke eaf5cc32-b48f-7785-5c94-90b5ce300e9
Мне не приходилось, но в любом случае, достаточно будет ревоукнуть токен и поменять пароли, к которым у него был доступ.
Самое главное
Не нужно хранить пароли в репо, для этого есть специальные штуки, например, Vault.
Comments
comments powered by Disqus