Установка, настройка и работа с Hashicorp Vault

Thank you for reading this post, don't forget to subscribe!

Hashicorp Vault

при­ло­же­ние для цен­тра­ли­зо­ван­но­го хра­не­ния сек­ре­тов: паро­лей, логи­нов, сер­ти­фи­ка­тов и токе­нов (Vault в пере­во­де с англий­ско­го — сейф). С его помо­щью мож­но улуч­шить без­опас­ность про­грамм­но­го кода, убрав из него все сек­рет­ные дан­ные и пере­не­ся их в Hashicorp Vault. Напи­сан на язы­ке Golang.

При­ло­же­ние инте­гри­ру­ет­ся со мно­ги­ми попу­ляр­ны­ми системами:

  • Обна­ру­же­ние сер­ви­сов: Consul.
  • Систе­мы оркест­ра­ции: Ansible, Puppet, Chief.
  • Кон­тей­не­ре­за­ция: Kubernetes, Docker.
  • CI/CD: GitLab, Jenkins, Teamcity.
  • и мно­ги­ми другими.

А так­же есть под­держ­ка боль­шин­ства совре­мен­ных язы­ков про­грам­ми­ро­ва­ния, напри­мер: Python, Node.js, PHP, Java, Go. Пол­ный спи­сок офи­ци­аль­ных биб­лио­тек мож­но най­ти на офи­ци­аль­ном сай­те. Так­же, вза­и­мо­дей­ство­вать с Hashicorp Vault мож­но через API.

При­ло­же­ние может быть уста­нов­ле­но на все попу­ляр­ные систе­мы. Воз­мож­ны сле­ду­ю­щие вари­ан­ты инсталляции:

  1. Из репо­зи­то­рия (для Linux).
  2. Копи­ро­ва­ние бинар­но­го файла.
  3. Сбор­ка из исходников.
  4. В виде кон­тей­не­ра Docker.

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

  • Встро­ен­ные сред­ства для систем оркест­ра­ции — ansible-vault (Ansible), chef-vault (Chef), Hiera (Puppet), Pillars (SaltStack).
  • Шиф­ро­ва­ние фай­лов, кото­рые хра­нят­ся в репозитории.
  • Исполь­зо­ва­ние облач­ных решений.

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

Установка пакетов

Нам пона­до­бят­ся неко­то­рые ути­ли­ты. Коман­ды для их уста­нов­ки зави­сят от исполь­зу­е­мой системы.

а) Debian:

apt-get install wget chrony curl apt-transport-https

б) CentOS:

yum install wget chrony curl

* где:

  • wget — ути­ли­та для загруз­ки файлов.
  • chrony — сер­вис для син­хро­ни­за­ции времени.
  • curl — ути­ли­та для отправ­ки POST и GET запро­сов на веб-сервер.
  • apt-transport-https — допол­не­ние для воз­мож­но­сти исполь­зо­вать репо­зи­то­рии по https.

Настройка времени

Для кор­рект­но­го полу­че­ния токе­нов необ­хо­ди­мо, что­бы вре­мя на сер­ве­ре было пра­виль­ное. Зада­ем необ­хо­ди­мый нам часо­вой пояс:

timedatectl set-timezone Europe/Moscow

* пол­ный пере­чень вари­ан­тов мож­но посмот­реть коман­дой timedatectl list-timezones.

Если у нас в сети есть свой сер­вер син­хро­ни­за­ции вре­ме­ни, откры­ва­ем на редак­ти­ро­ва­ние файл настрой­ки chrony.

а) Debian:

vi /etc/chrony/chrony.conf

б) CentOS:

vi /etc/chrony.conf

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

а) в Debian или CentOS 8:

pool test.local
#pool …

* в нашем при­ме­ре мы ком­мен­ти­ру­ем тот адрес pool, кото­рый был в кон­фи­гу­ра­ции и под­став­ля­ем адрес наше­го сер­ве­ра test.local.

а) в CentOS 7:

server test.local
#server 0.centos.pool.ntp.org iburst
#server 1.centos.pool.ntp.org iburst
#server 2.centos.pool.ntp.org iburst
#server 3.centos.pool.ntp.org iburst

* в нашем при­ме­ре мы ком­мен­ти­ру­ем адре­са server, кото­рые были в кон­фи­гу­ра­ции и под­став­ля­ем адрес наше­го сер­ве­ра test.local.

Раз­ре­ша­ем авто­ма­ти­че­ский запуск для сер­ви­са син­хро­ни­за­ции вре­ме­ни и пере­за­пус­ка­ем его.

а) для Debian:

systemctl enable chrony

systemctl restart chrony

б) для CentOS:

systemctl enable chronyd

systemctl restart chronyd

Настройка брандмауэра

Для кор­рект­ной рабо­ты сер­ви­са нам необ­хо­ди­мо открыть порт 8200. В зави­си­мо­сти от исполь­зу­е­мой ути­ли­ты управ­ле­ния netfilter мы долж­ны при­ме­нять раз­ные инструменты.

а) Iptables (как пра­ви­ло, Debian):

iptables -I INPUT -p tcp --dport 8200 -j ACCEPT

Для сохра­не­ния пра­ви­ла мож­но вос­поль­зо­вать­ся ути­ли­той iptables-persistent:

apt-get install iptables-persistent

netfilter-persistent save

б) Firewalld (как пра­ви­ло, для CentOS):

firewall-cmd --permanent --add-port=8200/tcp

firewall-cmd --reload

Установка и запуск

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

Под­клю­ча­ем офи­ци­аль­ный репо­зи­то­рий и уста­нав­ли­ва­ем пакет vault.

а) Debian:

curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -

echo "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main" > /etc/apt/sources.list.d/hashicorp.list

apt-get update

apt-get install vault

б) CentOS:

wget https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo -O /etc/yum.repos.d/hashicorp.repo

yum install vault

Раз­ре­ша­ем авто­за­пуск служ­бы и если она не запу­ще­на, стар­ту­ем ее:

systemctl enable vault --now

Уста­нов­ка выпол­не­на. При попыт­ке зай­ти по адре­су https://<IP-адрес сер­ве­ра Vault>:8200/ мы долж­ны уви­деть стра­ни­цу началь­ной настрой­ки мастер-ключей.

Идем даль­ше.

Настройка рабочего окружения

При попыт­ке выпол­нить любую опе­ра­цию в команд­ной стро­ке, мы полу­чим ошибку:

Error checking seal status: Get "https://127.0.0.1:8200/v1/sys/seal-status": x509: cannot validate certificate for 127.0.0.1 because it doesn't contain any IP SANs

Это зна­чит, что мы пыта­ем­ся под­клю­чить­ся к наше­му сер­ве­ру по https с непра­виль­ным сер­ти­фи­ка­том. На эта­пе пер­вич­ной настрой­ки не хочет­ся зани­мать­ся полу­че­ни­ем и настрой­кой валид­но­го сер­ти­фи­ка­та. В офи­ци­аль­ной доку­мен­та­ции ска­за­но, что нуж­но вве­сти команду:

export VAULT_ADDR=http://127.0.0.1:8200

Она ука­жет теку­ще­му окру­же­нию под­клю­чать­ся к сер­ве­ру по http. Одна­ко, это при­ве­дет к дру­гой ошибке:

Error checking seal status: Error making API request.

URL: GET http://127.0.0.1:8200/v1/sys/seal-status
Code: 400. Raw Message:

Client sent an HTTP request to an HTTPS server.

Она гово­рит, что мы под­клю­ча­ем­ся к сер­ве­ру по неза­щи­щен­но­му кана­лу, когда сер­вер тре­бу­ет без­опас­но­го соединения.

Для реше­ния про­бле­мы откры­ва­ем файл:

vi /etc/vault.d/vault.hcl

И сни­ма­ем ком­мен­та­рии со сле­ду­ю­щих строк, а так­же меня­ем зна­че­ние для поля address:

* так как для https уже исполь­зу­ет­ся порт 8200, мы долж­ны поме­нять пред­ло­жен­ный по умол­ча­нию вари­ант на свой, что­бы не воз­ни­ка­ло кон­флик­тов при запус­ке сервиса.

Пере­за­пус­ка­ем служ­бу vault:

systemctl restart vault

Обнов­ля­ем систем­ную пере­мен­ную VAULT_ADDR:

export VAULT_ADDR=http://127.0.0.1:8201

* обра­ти­те вни­ма­ние, что мы поме­ня­ли порт под­клю­че­ния на 8201.

Про­бу­ем выве­сти на экран статус:

vault status

Мы долж­ны полу­чить что-то на подобие:

Что­бы дан­ная систем­ная пере­мен­ная созда­ва­лась каж­дый раз при вхо­де поль­зо­ва­те­ля в систе­му, откры­ва­ем файл:

vi /etc/environment

И добав­ля­ем:

VAULT_ADDR=http://127.0.0.1:8201

Распечатывание

После уста­нов­ки, сер­вер Vault нахо­дит­ся в запе­ча­тан­ном (sealed) состо­я­нии. То есть, он не зна­ет, как ему рас­шиф­ро­вы­вать сек­ре­ты, кото­рые будут хра­нить­ся в базе.

При попыт­ке выпол­нить любую опе­ра­цию с хра­ни­ли­щем сек­ре­тов мы полу­чим ошибку:

* Vault is sealed

Что­бы испра­вить ситу­а­цию, нуж­но выпол­нить ини­ци­а­ли­за­цию сер­ве­ра [---] мы полу­чим клю­чи для рас­пе­ча­ты­ва­ния (Unseal Keys). После необ­хо­ди­мо вве­сти эти клю­чи и мож­но будет авто­ри­зо­вать­ся в системе.

Инициализация, распечатывание и вход

Для нача­ла, нам необ­хо­ди­мо ини­ци­а­ли­зи­ро­вать наш сер­вер. Это выпол­ня­ет­ся командой:

vault operator init

Коман­да нам вер­нет 5 клю­чей. Любые 3 из них явля­ют­ся клю­ча­ми для рас­пе­ча­ты­ва­ния сер­ве­ра (Unseal Key). Так­же нам будет предо­став­лен токен для root (Initial Root Token), с помо­щью кото­ро­го мож­но будет вой­ти в систе­му vault.

И так, рас­пе­ча­та­ем наш сер­вер, вве­дя по оче­ре­ди 3 команды.

Для пер­во­го ключа:

vault operator unseal

Для вто­ро­го:

vault operator unseal

И тре­тье­го:

vault operator unseal

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

Sealed          false

Это зна­чит, что сер­вер боль­ше не запе­ча­тан и с ним мож­но работать.

Теперь необ­хо­ди­мо зало­ги­нить­ся в систе­му командой:

vault login

… и вве­сти ключ root, кото­рый мы полу­чи­ли после инициализации.

Мы можем выпол­нять коман­ды для рабо­ты с Hashicorp Vault.

Автоматическое распечатывание

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

Одна­ко, если у нас есть при­чи­ны авто­ма­ти­че­ски под­ни­мать сер­вер после пере­за­груз­ки, рас­смот­рим, как это сделать.

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

Выпол­ним настрой­ку в несколь­ко шагов.

1. Скрипт.

Созда­дим ката­лог для хра­не­ния скриптов:

mkdir /scripts

Созда­дим скрипт:

vi /scripts/nseal.sh

* где w1SgHSWyXm+7kwmYk4bFX2rBLG5jKxIn01DMkj57071D38s4+FkxKTTANFZgCwEPFOgJIMwTvLca1j36yYPc3gdx и 4xlpKVwPuNlskydM/qmCmW22x7WZdfuiFu92HGRNOa8o [---] любых 3 токе­на (из 5 сге­не­ри­ро­ван­ных). Обра­ти­те вни­ма­ние, мы задер­жи­ва­ем выпол­не­ние скрип­та на 10 секунд х---х на прак­ти­ке, сер­вис vault может не успеть запу­стить­ся, и мы тогда полу­чим ошиб­ку при выпол­не­нии коман­ды vault operator unseal.

Раз­ре­ша­ем запуск скрип­та на выполнение:

chmod +x /scripts/unseal.sh

Мож­но, даже, выпол­нить скрипт:

/scripts/unseal.sh

В ито­ге, мы рас­пе­ча­та­ем наш сервер.

2. Авто­за­пуск скрип­та при стар­те системы:

Боль­шин­ство совре­мен­ных сер­вер­ных систем рабо­та­ет на осно­ве systemd. Рас­смот­рим авто­за­пуск с помо­щью последней.

Созда­ем юнит:

vi /etc/systemd/system/vault-unseal.service

* в дан­ном при­ме­ре мы выпол­ня­ем одну коман­ду при запус­ке сер­ви­са х---х запуск скрип­та /scripts/unseal.sh. Перед этим мы созда­ем систем­ную пере­мен­ную VAULT_ADDR, что­бы при выпол­не­нии команд в скрип­те систе­ма пони­ма­ла, к како­му сер­ве­ру подключаться.

Пере­чи­та­ем кон­фи­гу­ра­цию для systemd:

systemctl daemon-reload

Раз­ре­ша­ем авто­за­пуск создан­но­го сервиса:

systemctl enable vault-unseal

Про­бу­ем пере­за­гру­зить сер­вер [---] vault дол­жен ока­зать­ся распечатанным.

Работа с секретами

Наша систе­ма пол­но­стью гото­ва, что­бы ей пользоваться.

Для нача­ла дадим раз­ре­ше­ние на хра­не­ние сек­ре­тов по пути secret:

vault secrets enable -path=secret/ kv

Мы долж­ны полу­чить ответ:

Success! Enabled the kv secrets engine at: secret/

Теперь выпол­ним про­стую опе­ра­цию по созда­нию сек­ре­та. Вве­дем коман­ду, пред­ло­жен­ную на офи­ци­аль­ном сай­те разработчика:

vault kv put secret/hello foo=world

* коман­да kv вза­и­мо­дей­ству­ет с хра­ни­ли­щем Vault. В дан­ном при­ме­ре мы добав­ля­ем пару ключ-зна­че­ние, соот­вет­ствен­но foo-world.

Мы долж­ны полу­чить ответ:

Success! Data written to: secret/hello

Посмот­реть содер­жи­мое мож­но командой:

vault kv get secret/hello

На что мы получим:

Так­же мож­но вне­сти за раз мно­же­ство значений:

vault kv put secret/hello foo=world excited=yes

Посмот­реть спи­сок создан­ных сек­ре­тов мож­но командой:

vault kv list secret

Теперь уда­лим сек­рет командой:

vault kv delete secret/hello

Пол­ный пере­чень команд мож­но уви­деть так:

vault -help

После чего мож­но будет полу­чить помощь по кон­крет­ной коман­де vault, например:

vault kv -help

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

Версионность и метаданные

Hashicorp Vault под­дер­жи­ва­ет вер­си­он­ность дан­ных, то есть, мы можем посмот­реть опре­де­лен­ную вер­сию дан­ных внут­ри сек­ре­та. Одна­ко, по умол­ча­нию, сер­вис уста­нав­ли­ва­ет­ся с kv вер­сии 1, кото­рая не под­дер­жи­ва­ет дан­ной опе­ра­ции. При попыт­ке выпол­нить любую коман­ду, захва­ты­ва­ю­щую вер­си­он­ность, мы полу­чим ошибку:

Metadata not supported on KV Version 1

Для реше­ния обно­вим kv до вер­сии 2 для наше­го секрета.

Раз­ре­ша­ем вто­рую вер­сию командой:

vault secrets enable -version=2 kv

Вклю­ча­ем веде­ние вер­си­он­но­сти для наше­го секрета:

vault kv enable-versioning secret/

Теперь зане­сем 2 раза данные:

vault kv put secret/hello foo=world

vault kv put secret/hello foo=world2

Посмот­реть дан­ные опре­де­лен­ной вер­сии мож­но командой:

vault kv get -version=1 secret/hello

В нашем при­ме­ре мы увидим:

* то есть зна­че­ние, кото­рое вво­ди­лось пер­вой командой.

Посмот­реть мета­дан­ные сек­ре­та мож­но командой:

vault kv metadata get secret/hello

Для уда­ле­ния опре­де­лен­ной вер­сии сек­ре­та вводим:

vault kv destroy -versions=1 secret/hello

Динамические секреты

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

Рас­смот­рим при­мер настрой­ки дина­ми­че­ских сек­ре­тов для базы дан­ных MariaDB/MySQL.

Пер­вым делом, созда­дим поль­зо­ва­те­ля в СУБД с пра­ва­ми созда­вать дру­гих поль­зо­ва­те­лей. Под­клю­ча­ем­ся к базе данных:

mysql -uroot -p

Созда­ем учет­ную запись, под кото­рой будет под­клю­чать­ся vault к СУБД:

> CREATE USER 'vaultuser'@'localhost' IDENTIFIED BY 'vaultpass';

Дадим пра­ва создан­ной учет­ной запи­си созда­вать дру­гих поль­зо­ва­те­лей и назна­чать им права:

> GRANT CREATE USER ON *.* TO 'vaultuser'@'localhost' WITH GRANT OPTION;

Выхо­дим из обо­лоч­ки SQL:

> exit;

Теперь раз­ре­ша­ем меха­низм сек­ре­тов базы дан­ных (database secrets engine):

vault secrets enable database

Мы долж­ны увидеть:

Success! Enabled the database secrets engine at: database/

* так­же мы можем полу­чить ошиб­ку path is already in use at database/, если дан­ный меха­низм уже раз­ре­шен в нашей системе.

Созда­дим настрой­ку для под­клю­че­ния к нашей базе:

* пред­по­ла­га­ет­ся, что:

  • test х---ъ имя базы, для кото­рой vault смо­жет создать вре­мен­ную учет­ную запись.
  • plugin_name х---ъ имя пла­ги­на для созда­ния учет­ной запи­си. Важ­ный пара­метр, кото­рый дол­жен пра­виль­но быть подо­бран в зави­си­мо­сти от вер­сии СУБД. Ниже будет ком­мен­та­рий, с какой ошиб­кой мы можем столк­нуть­ся, выбрав непра­виль­ный плагин.
  • test-role [--] роль, кото­рая будет исполь­зо­вать­ся vault (ее созда­дим ниже).
  • vaultuser х---ъ поль­зо­ва­тель, под кото­рым мы под­клю­ча­ем­ся к СУБД (созда­ли выше).
  • vaultpass х---ъ пароль, с кото­рым мы под­клю­ча­ем­ся к сер­ве­ру баз данных.

Созда­дим роль, по сути, зада­дим коман­ду для созда­ния вре­мен­ной учет­ной записи:

* где:

  • db_name х---ъ имя базы дан­ных, для кото­рой мы будем созда­вать пользователя.
  • creation_statements х---ъ коман­ды SQL для созда­ния ново­го поль­зо­ва­те­ля. {{name}} и {{password}} явля­ют­ся спе­ци­аль­ны­ми пере­мен­ны­ми, вме­сто кото­рых vault под­ста­вит сге­не­ри­ро­ван­ные зна­че­ния. Обра­ти­те вни­ма­ние, что в дан­ном при­ме­ре созда­ет­ся поль­зо­ва­тель с пра­ва­ми под­клю­че­ния с любо­го хоста, одна­ко, в зави­си­мо­сти от вер­сии MariaDB, имен­но с локаль­но­го хоста под­клю­чить­ся под дан­ным поль­зо­ва­те­лем будет нель­зя. При такое необ­хо­ди­мо­сти, меня­ем % на localhost.
  • default_ttl х---ъ вре­мя, в тече­ние кото­ро­го будет дей­ство­вать пароль.
  • max_ttl х---ъ вре­мя, в тече­ние кото­ро­го поль­зо­ва­те­лю мож­но будет обнов­лять пароль.

И так, теперь давай­те созда­дим поль­зо­ва­те­ля и пароль:

vault read database/creds/test-role

* после вво­да коман­ды vault сге­не­ри­ро­вать и создать в базе ново­го поль­зо­ва­те­ля и пароль.

Мы долж­ны уви­деть что-то на подобие:

* Если мы уви­дим ошиб­ку, на подо­бие Error 1470: String 'v-root-test-role-KHWyA2IwdoaUth7c' is too long for user name (should be no longer than 16) мы столк­ну­лись с огра­ни­че­ни­ем на сто­роне СУБД (нель­зя созда­вать имя поль­зо­ва­те­ля с дли­ной более 16 сим­во­лов). Что­бы решить про­бле­му мы долж­ны пере­со­здать под­клю­че­ние database/config/test с новым пла­ги­ном mysql-legacy-database-plugin.

Так­же для созда­ния поль­зо­ва­те­ля мы можем исполь­зо­вать API запрос:

curl --header "X-Vault-Token: s.e0YKJEOHlpfgQiWqZlzVuUbY" http://127.0.0.1:8201/v1/database/creds/test-role

* где X-Vault-Token х---ъ токен с досту­пом. Для теста мож­но исполь­зо­вать тот, что был полу­чен для root после ини­ци­а­ли­за­ции системы.

Теперь давай­те про­ве­рим, что создан­ные учет­ные запи­си име­ют нуж­ный нам доступ. Для нача­ла, под поль­зо­ва­те­лем root мож­но про­ве­рить, что запи­си созданы:

> SELECT user, host FROM mysql.user;

Мы долж­ны уви­деть в спис­ках нуж­ную запись (в нашем при­ме­ре, v-test--gVPavnGVr).

Теперь зай­дем под учет­ной запи­сью, кото­рая была созда­на с помо­щью vault:

mysql -h192.168.0.15 -u'v-test--gVPavnGVr' -p'7v9jC-XHXJjQ2sicLI42'

* в моем слу­чае из-за досту­па %, под­клю­че­ние с localhost было запре­ще­но. Поэто­му я про­ве­ряю доступ с дру­го­го хоста в локаль­ной сети, доба­вив опцию -h192.168.0.15 (где 192.168.0.15 х---ъ сер­вер с СУБД, доступ к кото­рой предо­став­лял­ся через vault).

Мы долж­ны под­клю­чить­ся к базе.

Отме­нить доступ мож­но командой:

vault lease revoke database/creds/test-role/JpEmEh2MJV115Lr4S4Lx5UHW

* где database/creds/test-role/JpEmEh2MJV115Lr4S4Lx5UHW х---ъ зна­че­ние lease_id, кото­рое нам вер­ну­ла систе­ма при созда­нии вре­мен­ной учет­ной записи.

Посмот­реть спи­сок всех иден­ти­фи­ка­то­ром мож­но командой:

vault list sys/leases/lookup/database/creds/test-role

* где test-role [---] имя создан­ной нами роли.

Про­длить lease_duration или default_ttl (пароль) мож­но с помо­щью команды:

vault lease renew database/creds/test-role/JpEmEh2MJV115Lr4S4Lx5UHW

Аутентификация и политики

Hashicorp Vault поз­во­ля­ет управ­лять досту­па­ми с помо­щью поли­тик и токе­нов авто­ри­за­ции. Рас­смот­рим про­цесс настройки.

Работа с токенами

Для нача­ла научим­ся управ­лять токе­на­ми. Про­стая коман­да для созда­ния нового:

vault token create

Систе­ма сге­не­ри­ру­ет новый ключ и сде­ла­ет вывод на экран.

Так­же мы можем создать вре­мен­ный токен:

vault token create -period=1h

* на один час.

Посмот­реть инфор­ма­цию о токене мож­но через его аксес­сор. Сна­ча­ла полу­чим спи­сок аксессоров:

vault list auth/token/accessors

После смот­рим токен по аксессору:

vault token lookup -accessor uW9Ajr8VzFiCwHzHWn75qWVe

Вой­ти в систе­му с помо­щью токе­на мож­но командой:

vault login

После вво­дим наш токен. Или одной командой:

vault login s.Db9j6Q4TvyFDr3j2aQmXttrX

Посмот­реть инфор­ма­цию о токене, под кото­рым мы заре­ги­стри­ро­ва­лись в систе­ме, мож­но командой:

vault token lookup

А дан­ной коман­дой мы созда­ем поль­зо­ва­те­ля и при­вя­зы­ва­ем его к поли­ти­ке my-policy:

vault token create -policy=my-policy

Если поли­ти­ки нет в систе­ме, то мы полу­чим предупреждение:

WARNING! The following warnings were returned from Vault:

* Policy "my-policy" does not exist

Нас это не долж­но забо­тить х---ъ на сле­ду­ю­щем шаге мы ее создадим.

При необ­хо­ди­мо­сти при­вя­зать токен к несколь­ким поли­ти­кам, пере­чис­ля­ем из в опци­ях policy:

vault token create -policy=my-policy -policy=my-policy2

Работа с политиками

Выше мы созда­ли токен и при­вя­за­ли его к поли­ти­ке my-policy. Созда­дим ее:

* в дан­ной поли­ти­ке мы раз­ре­ша­ем чте­ние всех сек­ре­тов в secret. Для ранее создан­но­го сек­ре­та secret/hello мы раз­ре­шим чте­ние и обнов­ле­ние запи­сей, а для сек­ре­та secret/foo так­же мы раз­ре­ша­ем созда­вать запи­си. Обра­ти­те вни­ма­ние, что на самом деле, дан­ные хра­нят­ся в secret/data

Посмот­реть спи­сок поли­тик мож­но командой:

vault policy list

Посмот­реть инфор­ма­цию о кон­крет­ной поли­ти­ке мож­но командой:

vault policy read my-policy

Проверка политики

И так, мы созда­ли токен, при­вя­за­ли его к поли­ти­ке, созда­ли саму поли­ти­ку. Про­ве­рим, что наши пра­ва работают.

Если нуж­но, мож­но создать еще токен и при­вя­зать его к нашей политике:

vault token create -policy=my-policy

Заре­ги­стри­ру­ем­ся с нуж­ным нам токе­ном (кото­рый при­вя­зан к  про­ве­ря­е­мой политике):

vault login

Попро­бу­ем сна­ча­ла создать сек­рет в вет­ке secret/foo и в нем ука­зать пару ключ-значение:

vault kv put secret/foo/new foo=world

Коман­да долж­на выпол­нить­ся успешно.

Теперь сде­ла­ем то же самое для secret/hello

vault kv put secret/hello/new foo=world

Мы долж­ны полу­чить ошибку

Error writing data to secret/data/hello/new: Error making API request.

URL: PUT http://127.0.0.1:8201/v1/secret/data/hello/new
Code: 403. Errors:

* 1 error occurred:
* permission denied

Теперь логи­ним­ся под токе­ном с пол­ны­ми пра­ва­ми и доба­вим запись:

vault kv put secret/hello/new foo=world

И сно­ва захо­дим под токе­ном с огра­ни­чен­ны­ми пра­ва­ми. Про­бу­ем обно­вить запись:

vault kv put secret/hello/new foo=world2

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

Аутентификация на основе пользователей

Так­же в Hashicorp Vault мы можем создать поль­зо­ва­те­ля с паро­лем и при­вя­зать к нему поли­ти­ку. Адми­ни­стра­тор смо­жем вхо­дить в систе­му под учет­ной запи­сью, а не с помо­щью токена.

Раз­ре­ша­ем метод auth по пути userpass:

vault auth enable userpass

Созда­ем пользователя:

vault write auth/userpass/users/testpassword="test-pass" policies="my-profile"

* дан­ной коман­дой мы созда­ли поль­зо­ва­те­ля testс паро­лем test-pass и при­вя­за­ли его к поли­ти­ке my-profile.

Вой­ти в систе­му мож­но командой:

vault login -method=userpass username=test

Вво­дим пароль и попа­да­ем в систе­му под поль­зо­ва­те­лем test. Мож­но выпол­нить тесты, кото­рые мы дела­ли выше.

Одноразовые SSH пароли

Рас­смот­рим вари­ан­ты хра­не­ния сек­ре­тов для авто­ри­за­ции по SSH с исполь­зо­ва­ни­ем одно­ра­зо­вых паро­лей или One-Time SSH Password (OTP).

Настройка на сервере Vault

Раз­ре­ша­ем меха­низм ssh:

vault secrets enable ssh

Созда­ем роль для созда­ния одно­ра­зо­во­го пароля:

* в дан­ном примере:

  • key_type х---ъ тип созда­ва­е­мо­го клю­ча. Остав­ля­ем otp.
  • default_user х---ъ имя учет­ной записи.
  • cidr_list х---ъ под­сеть, для кото­рой будет раз­ре­шен доступ. Это долж­на быть под­сеть ком­пью­те­ров, на кото­рых мы будем про­хо­дить аутен­ти­фи­ка­цию по одно­ра­зо­во­му паролю.

На сер­ве­ре, пока, все. Пере­хо­дим к настрой­ке клиента.

Настройка на клиенте

На кли­ен­те необ­хо­ди­мо выпол­нить настрой­ку, кото­рая поз­во­лит выпол­нять две задачи:

  1. Созда­вать одно­ра­зо­вые паро­ли на сто­роне Vault.
  2. Осу­ществ­лять про­вер­ку под­лин­но­сти при под­клю­че­нии по SSH.

Дан­ной зада­чей зани­ма­ет­ся vault-ssh-helper. Рас­смот­рим про­цесс его уста­нов­ки и настройки.

Нам пона­до­бит­ся пакет для рас­па­ков­ки zip-архи­вов. В зави­си­мо­сти от систе­мы ста­вим его одной из команд ниже.

а) для Debian / Ubuntu:

apt-get install unzip

б) для CentOS / Red Hat / Fedora:

yum install unzip

Уста­нов­ка vault-ssh-helper выпол­ня­ет­ся про­стым копи­ро­ва­ни­ем бинар­ни­ка. Пере­хо­дим на офи­ци­аль­ный сайт для загруз­ки и выби­ра­ем послед­нюю вер­сию паке­та. На сле­ду­ю­щей стра­ни­цы копи­ру­ем ссыл­ку на нуж­ный вари­ант архи­ва, в зави­си­мо­сти от архи­тек­ту­ры наше­го сервера:

С помо­щью ско­пи­ро­ван­ной ссыл­ки загру­жа­ем архив:

wget https://releases.hashicorp.com/vault-ssh-helper/0.2.1/vault-ssh-helper_0.2.1_linux_amd64.zip

Рас­па­ко­вы­ва­ем его:

unzip vault-ssh-helper_*.zip -d /usr/bin

Созда­дим ката­лог для кон­фи­гу­ра­ци­он­ных фай­лов vault-ssh-helper:

mkdir /etc/vault-ssh-helper

Созда­дим кон­фи­гу­ра­ци­он­ный файл:

vi /etc/vault-ssh-helper/config.hcl

* где:

  • vault_addr х---ъ адрес наше­го сер­ве­ра секретов.
  • ssh_mount_point х---ъ путь на сто­роне Vault, по кото­ро­му будут хра­нить­ся сек­ре­ты. Настра­и­ва­ет­ся при вклю­че­нии меха­низ­ма SSH.
  • tls_skip_verify х---ъ сто­ит ли про­пус­кать про­вер­ку под­лин­но­сти сер­ти­фи­ка­та. Так как у нас еще не настро­ен валид­ный сер­ти­фи­кат, уста­нав­ли­ва­ем зна­че­ние в true.
  • allowed_roles х---ъ на сто­роне сер­ве­ра мож­но созда­вать раз­ным поль­зо­ва­те­лей от раз­ных ролей. В дан­ной настрой­ке мы можем опре­де­лить, поль­зо­ва­те­лям с какой ролью будет раз­ре­шен вход по SSH.

Откры­ва­ем кон­фи­гу­ра­ци­он­ный файл pamd для sshd:

vi /etc/pam.d/sshd

И в самый верх добавляем:

* в дан­ной кон­фи­гу­ра­ции мы, по-преж­не­му, смо­жем авто­ри­зо­вать­ся под учет­ны­ми запи­ся­ми, создан­ны­ми на самом сер­ве­ре. Если необ­хо­ди­мо это отклю­чить, раз­ре­шив вход толь­ко с OTP, ком­мен­ти­ру­ем @include common-auth и меня­ем sufficient на required.

Нако­нец, редак­ти­ру­ем кон­фи­гу­ра­ци­он­ный файл sshd. Откры­ва­ем его:

vi /etc/ssh/sshd_config

Выстав­ля­ем сле­ду­ю­щие зна­че­ния для опций:

* где ChallengeResponseAuthentication раз­ре­ша­ет авто­ри­за­цию с при­ме­не­ни­ем интер­ак­тив­но­го вво­да паро­ля; UsePAM раз­ре­ша­ет исполь­зо­ва­ние моду­ля pam.

Пере­за­пу­стим сер­вис ssh:

systemctl restart sshd

Выпол­ня­ем про­вер­ку нашей настрой­ки командой:

vault-ssh-helper -verify-only -config /etc/vault-ssh-helper/config.hcl

Мы долж­ны полу­чить ответ:

2021/05/18 14:07:14 [INFO] using SSH mount point: ssh
2021/05/18 14:07:14 [INFO] using namespace:
2021/05/18 14:07:14 [INFO] vault-ssh-helper verification successful!

Зна­чит настрой­ка на кли­ен­те выпол­не­на коррекнто.

Созда­ем учет­ную запись на кли­ен­те, под кото­рой будем вхо­дить в систе­му с одно­ра­зо­вым паролем:

useradd test -m

* в нашей поли­ти­ке будет созда­вать­ся пароль для учет­ной запи­си test.

Создаем одноразовый пароль

Вво­дим команду:

vault write ssh/creds/otp_key_role ip=192.168.0.25

* в дан­ном при­ме­ре мы созда­ем одно­ра­зо­вый пароль для ком­пью­те­ра с IP-адре­сом 192.168.0.25.

Мы долж­ны полу­чить, при­ме­ре­но, такой вывод:

* мы полу­чи­ли одно­ра­зо­вый пароль 83a57021-74b0-3ce3-8179-6fb92288c0ce.

Про­бу­ем вой­ти в систему:

ssh test@192.168.0.25

Вво­дим тот пароль, кото­рый нам выда­ла систе­ма (key). Вой­ти мы смо­жем толь­ко один раз, после нуж­но будет уже гене­ри­ро­вать новый пароль.

Настройка SSL

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

Пер­вое, что нам нуж­но, это полу­чить сер­ти­фи­кат. Пра­виль­нее все­го купить сер­ти­фи­кат или запро­сить через Let's Encrypt. После про­пи­сать в кон­фи­гу­ра­ци­он­ном фай­ле vault путь до дан­но­го сер­ти­фи­ка­та. Но мы рас­смот­рим про­цесс полу­че­ния само­под­пи­сан­но­го сер­ти­фи­ка­та, но при этом, кото­рый при­мет систе­ма. Для это­го необ­хо­ди­мо выпол­нить несколь­ко условий:

  • Сер­ти­фи­кат дол­жен быть выдан для hostname, по кото­ро­му мы будем отправ­лять запросы.
  • Для сер­ти­фи­ка­та мы долж­ны ука­зать аль­тер­на­тив­ное имя subjectAltName.

И так, созда­ем ката­лог для хра­не­ния сертификатов:

mkdir /etc/ssl/vault

Про­ве­ря­ем вер­сию openssl:

openssl version

Она долж­на быть 1.1.1 и выше. В про­тив­ном слу­чае, необ­хо­ди­мо выпол­нить обнов­ле­ние OpenSSL. Как пра­ви­ло, дан­ное дей­ствие тре­бу­ет­ся толь­ко на CentOS 7.

Гене­ри­ру­ем сертификат:

openssl req -new -x509 -days 1461 -nodes -out /etc/ssl/vault/cert.pem -keyout /etc/ssl/vault/cert.key -subj "/C=RU/ST=SPb/L=SPb/O=Global Security/OU=IT Department/CN=vault.test.local" -addext "subjectAltName = DNS:vault.test.local"

* в дан­ном при­ме­ре мы сге­не­ри­ру­ем необ­хо­ди­мые клю­чи по пути /etc/ssl/vault; обя­за­тель­но, нуж­но поме­нять зна­че­ния vault.test.local на имя сер­ве­ра, кото­рый исполь­зу­ет­ся у вас.

Если коман­да вер­нет ошиб­ку, про­ве­ря­ем, что у нас обнов­лен­ная вер­сия openssl, кото­рая под­дер­жи­ва­ет ключ addext.

Теперь откро­ем кон­фи­гу­ра­ци­он­ный файл hashicorp vault:

vi /etc/vault.d/vault.hcl

При­ве­дем сек­цию HTTPS listener к виду:

* необ­хо­ди­мо поме­нять пути до фай­лов tls_cert_file и tls_key_file.

Пере­за­пус­ка­ем сервис:

После пере­за­груз­ки сер­ви­са, он ста­нет запе­ча­тан­ным и нам нуж­но будет сно­ва вве­сти 3 части клю­ча (коман­ды vault operator unseal).

systemctl restart vault

Меня­ем в окру­же­нии пере­мен­ную VAULT_ADDR:

export VAULT_ADDR=https://vault.test.local:8200

* мы ука­зы­ва­ем про­то­кол https, обра­ще­ния долж­ны выпол­нять­ся по домен­но­му име­ни, для кото­ро­го мы полу­чи­ли сер­ти­фи­кат; так­же ука­зы­ва­ем порт 8200.

Выпол­ня­ем команду:

vault status

Мы долж­ны полу­чить состо­я­ние систе­мы. Зна­чит запро­сы по https работают.

И послед­нее, сно­ва откры­ва­ем файл:

vi /etc/environment

И так­же меня­ем зна­че­ние для пере­мен­ной VAULT_ADDR:

VAULT_ADDR=https://vault.test.local:8200

Запуск в виде контейнера Docker

В инструк­ции мы рас­смот­ре­ли уста­нов­ку Hashicorp Vault как паке­та. Так­же мы можем уста­но­вить дан­ный сер­вис в виде кон­тей­не­ра Docker из офи­ци­аль­но­го обра­за. Рас­смот­рим вкрат­це дан­ный вопрос.

Для нача­ла, необ­хо­ди­мо уста­но­вить в систе­му Docker. После загру­жа­ем образ

docker pull vault

Для запус­ка vault в режи­ме сер­ве­ра вводим:

docker run --cap-add=IPC_LOCK --name vault -d -p 8200:8200 -e 'VAULT_LOCAL_CONFIG={"backend": {"file": {"path": "/vault/file"}}, "default_lease_ttl": "168h", "max_lease_ttl": "720h", "listener": {"tcp": {"address": "127.0.0.1:8200", "tls_disable": "true"}}}' vault server

После захо­дим внутрь контейнера:

docker exec -it vault sh

Зада­ем систем­ную пере­мен­ную для под­клю­че­ния к vault по http:

export VAULT_ADDR=http://127.0.0.1:8200

Ини­ци­а­ли­зи­ру­ем сервер:

vault operator init

… и так далее.

Установка клиента и удаленное подключение

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

Уста­нов­ка кли­ен­та ничем не отли­ча­ет­ся от уста­нов­ки сер­ве­ра. Толь­ко нам не нуж­но ини­ци­а­ли­зи­ро­вать систе­му и запус­кать ее в каче­стве сер­ви­са. Опе­ра­ции отли­ча­ют­ся в зави­си­мо­сти от уста­нов­лен­ной опе­ра­ци­он­ной системы.

а) для Debian / Ubuntu / Mint:

apt-get install wget apt-transport-https

echo "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main" > /etc/apt/sources.list.d/hashicorp.list

apt-get update

apt-get install vault

б) для CentOS / Red Hat / Fedora:

yum install wget

wget https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo -O /etc/yum.repos.d/hashicorp.repo

yum install vault

После чего зада­ем пере­мен­ную систем­но­го окружения

export VAULT_ADDR=https://vault.test.local:8200

* обра­ти­те вни­ма­ние, что мы под­клю­ча­ем­ся уже по https. Имя наше­го сер­ве­ра долж­но раз­ре­шать­ся в DNS или быть про­пи­са­но в фай­ле hosts на ком­пью­те­ре управления.

Так­же, если у нас само­под­пи­сан­ный сер­ти­фи­кат, вводим:

export VAULT_SKIP_VERIFY=true

* дан­ная систем­ная пере­мен­ная ука­зы­ва­ет систе­ме не про­ве­рять валид­ность сертификата.

Про­бу­ем посмот­реть ста­тус уда­лен­но­го сервера:

vault status

Реги­стри­ру­ем­ся в системе:

vault login -method=userpass username=test

* в дан­ном при­ме­ре мы захо­дим под поль­зо­ва­те­лем test. Так­же мы можем вой­ти с исполь­зо­ва­ни­ем токена.

Мож­но выпол­нять дей­ствия соглас­но разрешениям.