HashiCorp Vault имеет в своём арсенале SSH secrets engine, который позволяет организовать защищённый доступ к вашим машинам по ssh, через создание клиентских сертификатов и одноразовых паролей. Про последнее – создание одноразовых паролей (OTP) – мы и поговорим в этой статье.
Как это работает?
Клиент генерирует OTP для нужного пользователя и хоста, далее обычным ssh username@host
подключается к серверу. Сгенерировать ключ можно напрямую через vault, используя cli, API или веб-интерфейс, или через вашу внутреннюю систему, которая сама будет дёргать vault API и создавать OTP.
Когда SSH-сервер получает запрос на аутентификацию, он вызывает PAM (Pluggable Authentication Modules) модуль, который в процессе выполняет внешнюю команду. Этой внешней командой является vault-ssh-helper, который, в свою очередь, стучится в ваш Vault-кластер для проверки токена, отправленного клиентом. Если всё ок, то доступ предоставляется, а токен инвалидируется.
Установка и настройка
Вся настройка достаточно быстрая и состоит из двух этапов: необходимые манипуляции внутри кластера Vault и на самом host'е.
Как всё настроить подробно описано в официальной статье от HashiCorp. Инструкция ниже это по сути её перевод. Вы можете это пропустить и перейти сразу к нюансам.
Манипуляции внутри Vault'а
Включаем SSH secrets engine.
vault secrets enable ssh
Создаём роль, которая будет использована для генерации OTP ключей для клиентов. Указываем дефолтного юзера и список разрешённых. А также в cidr_list
задаём список адресов, к которым будут подходить ключи.
Рекомендуется создавать по одной роли для каждого пользователя.
vault write ssh/roles/otp_role \
key_type=otp \
default_user=worker \
allowed_users=worker, worker2 \
cidr_list=10.10.10.10/32
Далее осталось создать policy к нашей роли для генерации ключей и сгенерировать access-token, привязанный к этой policy.
tee test.hcl <<EOF
path "ssh/creds/otp_role" {
capabilities = ["update"]
}
EOF
vault policy write otp-polcy ./test.hcl
Создаём token и сохраняем его, потому что потом запросить его у vault не удастся.
vault token create -policy=otp-polcy
Key Value
--- -----
token hvs.CAESIG1_CrngaECzf6yvTDBgUZz2Lt-mYfdZXogrsiV0ulH1Gh4KHGh2cy4bPmFmN24xNVM5cnBqbFNLTUdpd1JDcTM
token_accessor n76E8Bc8P9SyPLpVZa2EoWGq
token_duration 768h
token_renewable true
token_policies ["default" "otp-polcy"]
identity_policies []
policies ["default" "otp-polcy"]
Манипуляции внутри нужной машины
Скачиваем последнюю версию vaul-ssh-helper с этой ссылки, указанной в этом репозитории.
wget https://releases.hashicorp.com/vault-ssh-helper/0.2.1/vault-ssh-helper_0.2.1_linux_amd64.zip
Распаковываем в директорию /usr/local/bin
.
unzip -q vault-ssh-helper_0.2.1_linux_amd64.zip -d /usr/local/bin
Указываем владельцем root'а и устанавливаем права доступа 0755 (rwxr-xr-x).
sudo chown root:root /usr/local/bin/vault-ssh-helper
sudo chmod 0755 /usr/local/bin/vault-ssh-helper
Создаём файл с конфигурацией vault-ssh-helper в директории /etc/vault-ssh-helper.d
.
sudo mkdir /etc/vault-ssh-helper.d
sudo tee /etc/vault-ssh-helper.d/config.hcl <<EOF
vault_addr = "VAULT_ADDR"
tls_skip_verify = false
ca_path = "CA_CRT_PATH"
ssh_mount_point = "ssh"
allowed_roles = "*"
EOF
Меняем конфигурация для PAM sshd (/etc/pam.d/sshd
).
# на всякий случай бэкапим её
sudo cp /etc/pam.d/sshd /etc/pam.d/sshd.orig
Комментируем строчку include common-auth
и добавляем следующие две: в них для vault-ssh-helper указываем конфиг helper'а и файл, куда будут выводиться логи.
auth requisite pam_exec.so quiet expose_authtok log=/var/log/vault-ssh.log /usr/local/bin/vault-ssh-helper -config=/etc/vault-ssh-helper.d/config.hcl
auth optional pam_unix.so not_set_pass use_first_pass nodelay
Меняем конфигурацию sshd (/etc/ssh/sshd_config
).
# на всякий случай бэкапим её
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.orig
Добавляем вот такие строчки (предварительно проверьте файл, возможно они уже вставлены).
KbdInteractiveAuthentication yes
UsePAM yes
PasswordAuthentication no
Старые версии Ubuntu используют
ChallengeResponseAuthentication
вместоKbdInteractiveAuthentication
.
Так как вы отключаете аутентификацию по паролю, убедитесь, что возможны другие способы доступа к серверу. Например доступ по ssh ключу у root'а.
Перезапускаем sshd.
sudo systemctl restart sshd
Проверка
Авторизуемся в vault с токеном, полученным выше.
vault login $TOKEN
Генерируем OTP ключ для нужного ip-адреса (юзера не указываем – используется дефолтный).
vault write ssh/creds/otp_key_role ip=$IP_ADDRESS
Key Value
--- -----
lease_id ssh/creds/otp_key_role/yZaiE4bRiVUVvc6LetQDtDmS
lease_duration 768h
lease_renewable false
ip 10.10.10.10
key edcf6837-902f-43c6-9e54-c8c26ab80ff3
key_type otp
port 22
username username
Подключаемся к серверу с полученным ключём.
ssh username@10.10.10.10
Нюансы
Чтобы лучше понимать некоторые пункты
Роль в ssh secret engine – это конфигурация для генерации SSH-учетных данных. В рамках OTP она включает в себя такие параметры, как, например: списки разрешённых ip-адресов и пользователей, а также дефолтное имя пользователя, для которого сгенерируется OTP в случае, если имя пользователя не будет передано.Lease в Vault – это метаданные, которые содержат информацию о времени действия, возможности обновления и т.д., связанных с каждым динамическим секретом и токеном.
#1 Генерировать на одного юзера можно сколько угодно ключей
Имея токен с доступом к нужной роли ssh engine, можно создавать сколько угодно одноразовых ключей для всех пользователей и всех машин, которые указаны в роли. И живут они около месяца. Поэтому рекомендуется ограничивать конфигурацию роли одним пользователем на одной машине.
#2 Сгенерированные ключи останутся рабочими после удаления роли
Пока валиден lease созданного ключа, не важно, существует роль, которой его выдали, или нет – ключ останется валидным.
#3 Узнать, сколько сейчас неиспользованных ключей для пользователя, невозможно
В принципе узнать, сколько было выдано на роль ключей, можно, посмотрев, сколько у этой роли lease'ов, привязанных к ключам.
curl -s -X LIST -H "X-Vault-Token: ${VAULT_TOKEN}" ${VAULT_ADDR}/v1/sys/leases/lookup/ssh/creds/$ROLE_NAME
Но понять, какой lease указывает на валидный ключ, а какой нет, вы не сможете.
#4 Инвалидировать ключ можно только отозвав привязанный к нему lease
Так как ключи живут даже после удаления роли, единственный способ их убить, это отозвать lease.
Можно точечно:
vault lease revoke ssh/creds/otp-role/lease-id
А можно отрубить сразу lease'ы всех ключей роли:
vault lease revoke -prefix ssh/creds/otp-role
#5 По дефолту логи использования access-token'ов в HashiCorp Vault не ведутся
Чтобы узнать какие access-token'ы, когда и для чего использовались, нужно включить запись логов обращения к API.
vault audit enable file file_path=ПУТЬ_ДО_ФАЙЛА_КУДА_БУДУТ_СОХРАНЯТЬСЯ_ЛОГИ
Файл с логами будет очень жирным.
Все token'ы и их accessor'ы в логах будут захешированы. Чтобы как-то найти строчки использования нужного вам token'а, вам придется сначала прогнать его через ту же хеш-функцию, которую использует audit. И дальше по полученному хешу искать в лог-файле.
vault write sys/audit-hash/file input="<TOKEN ACCESSOR>"
Автоматизация получение OTP
Автоматизировать этот процесс очень легко благодаря Vault API и гибкой настройке прав доступа через ACL. По сути просто создаёте пользователя или сразу token с необходимой policy, и можете использовать нужные вам роли для генерации OTP ключей.
Пример с Ansible
Самый, наверное, простой способ – это создать Ansible Playbook, запрашивающий OTP у vault напрямую модулем community.hashi_vault.vault_write
.
- name: Play
hosts: localhost
gather_facts: false
tasks:
- name: Get OTP
community.hashi_vault.vault_write:
auth_method: token
url: https://vault.service
token: YOUR_TOKEN
path: ssh/creds/otp_role
data:
ip: HOST_IP
register: ssh
- name: Setting ssh vars
ansible.builtin.set_fact:
hashi_host_ip: '{{ ssh.data.data.ip }}'
hashi_host_username: '{{ ssh.data.data.username }}'
hashi_host_port: '{{ ssh.data.data.port }}'
hashi_host_key: '{{ ssh.data.data.key }}'
- name: DBG
ansible.builtin.debug:
msg:
- 'ip: {{ hashi_host_ip }}'
- 'port: {{ hashi_host_port }}'
- 'username: {{ hashi_host_username }}'
- 'password: {{ hashi_host_key }}'
Пример с использованием API запросов
curl --location 'https://vault.service/v1/ssh/creds/otp_role' \
--header 'X-Vault-Token: TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"ip": "10.10.10.10"
}' | jq '.data'
Спасибо за чтение! :)
Комментарии (12)
Hooverphonic
08.01.2024 18:47+4Ничего не понимаю в инфосеке, будьте добры объяснить за hashivault. Я не понимаю его ценности в плане обеспечения безопасности. Чем это лучше чем раздавать ключи пользователям? Это же дополнительный вектор атаки.
Вместо того чтобы отдать пользователю ключ для машины, вы ему отдаете токен с которым он может все ключи забрать и так. И если сценарий использования ключа вы еще можете спрогнозировать, куда пользователь засунет токен никому не известно.
Для примера, сколько людей в организации вместо curl --location 'https://vault.service/ по ошибке пульнут в http://. И ваши токены будут текстом лежать на ваших проксях и бог знает где еще.
Если вы боитесь что ключи могут "украсть" с рабочей машины, то ваш токен совершенно так же скорее всего лежит в домашней директории в виде скрипта ~/vaultssh.sh, и никто вам не намекнет тут что права у него должны быть 600.Или дело просто в удобстве использования? Я не очень вижу удобства тут, и это все кому то надо поддерживать и не ломать слишком часто, когда есть готовые решения типа SSSD или просто нативный доступ aws/gcp/azure.
Davydoff33 Автор
08.01.2024 18:47+4Ценность HashiCorp Vault в том, что он позволяет централизовано хранить секреты и удобно управлять доступом к ним. И соответственно позволяет минимизировать появление таких ситуаций, когда секреты лежат в plain text'е, например, в каком-нибудь гит репозитории.
В случае с OTP ключами к ssh, Vault это не единственное решение, и не факт, что самое эффективное, но в случае если вы, к примеру, уже в инфраструктуре своего проекта храните секреты в кластере HashiCorp Vault (что сейчас совсем не редкость), то при необходимости внедрения системы одноразовых паролей для ваших машин, вам будет легче использовать Vault.
По поводу кражи токенов. Токен может утечь куда-нибудь, да. Для борьбы с такими ситуациями токену можно задать время жизни и кол-во использований. И в случае, если уже понятная утечка, то инвалидировать его.
В открытом виде генерацию OTP через API Vault лучше не отдавать сотрудникам на пользование. Лучше такое прятать за внутренний корпоративный сервис, где ты уже под своей корп учёткой запрашиваешь генерацию OTP к нужной машине. Соответственно access-token к vault'у хранится у сервиса.
Лично я предполагаю, что подобный генератор OTP для ssh будет полезен для автоматизации каких-либо работ на удалённых хостах, когда worker'у нужно один раз к чему-то подключиться, выполнить свои действия и потухнуть.
atshaman
08.01.2024 18:47point примерно в том, что ключ - сущность "долгоживущая", и rekeying\revoking в масштабах организации может быть дорогим. Нужен ли для решения этой задачи именно vault - вопрос. КМК скорее "нет" (Лишняя инфраструктурная сложность очень часто именно "лишняя") - SSSD (Опционально - с хранением открытого ключа в аттрибуте LDAP-схемы, если нужен второй фактор), GSSAPI\kerberos или SSH-сертификаты с коротким сроком жизни скорее всего будут лучшим выбором при проектировании "с нуля", но если Vault уже есть, а всего остального нет - то пуркуа бы не па?
Bagatur
08.01.2024 18:47+1Ну, HashiCorp + OTP, это, конечно, здорово, но для крупных организаций PAM (Priviledged Access Management) система всё же желательна. И у некоторых типа CyberArk есть свои собственные сейфы (vault), но при этом ещё и сохраняется информация о том, что делал админ на сервере.
domix32
08.01.2024 18:47+2Стоит отметить, что они планировали сменить лицензию.
atshaman
08.01.2024 18:47Тогда уж надо начинать с того, что с "1\6 частью суши"(ТМ) они работать не желают...
domix32
08.01.2024 18:47Как грится, это вы потом следователю рассказывать будете. Дело ваше.
atshaman
08.01.2024 18:47Ну, я к облачным провайдерам услуг отношения не имею - так что на смену лицензии мне настолько "пофиг" что просто "пофиг" - а вот объяснять случись чего "какого рожна продукты компании, официально ушедшей из России и не желающей работать с ней используются в КИИ-сегменте" и впрямь, не хочется.
mpa4b
Хороший способ нахаляву получить логины в кучу чужих машин по ssh.