Интеграция Bitwarden CLI с fzf и буфером обмена

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

Самым удобным, внезапно, оказался клиент для Android, который не заставляет меня каждый раз вводить 12+ знаков мастер-пароля (такую длину требуют Bitwarden и здравый смысл), а может быть разблокирован с помощью биометрии. Похожего удобства захотелось достичь и на Linux.

Дикий CLI

На ноутбуке я использую Bitwarden CLI. Это powerful, fully-featured tool, которым на практике оказалось не слишком удобно пользоваться, если ты человек.

Ключи от ключей

You are responsible for maintaining your session key.

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

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

Пароли в stdout

The get command can only return one result, so you should use specific search terms. If multiple results are found, the CLI will return an error.

Где-то в этот момент чтения документации я окончательно начал подозревать, что официальный CLI предназначен для скриптов: всё строго, никакого автодополнения, никакого интерактивного поиска, а пароли лаконично вываливаются в стандартный вывод терминала, откуда их ещё нужно как-то переправить в место назначения.

Приручение CLI

Может показаться, что я ругаюсь, но отсутствие удобств и излишеств в официальном CLI — это хорошо:

Идея сделать Bitwarden CLI удобнее, разумеется, пришла в голову не только мне, так что на GitHub предсказуемо быстро нашёлся скрипт-обёртка от @loeschzwerg. Этот ZSH-скрипт менее требователен к пользователю и позволяет в случае, когда под пользовательский поисковый запрос подходит несколько аккаунтов, выбрать нужный из списка с помощью fzf и автоматически скопировать логин, пароль и даже TOTP в буфер обмена.

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

«Безопасное» хранение сессионного ключа

Как я писал выше, мне нравится подход Android-клиента: нужно один раз ввести свой невероятно длинный мастер-пароль, после чего можно разблокировать хранилище отпечатком пальца. В ходе непродолжительных размышлений я решил, что самое простое и надёжное подобие для приложения в терминале — один раз получить сессионный ключ и сохранить его в файл, который будет доступен для чтения только пользователю root и недоступен любым другим приложениям, запущенным от имени текущего пользователя.

Приятный бонус для владельцев биометрических сканеров: они отлично интегрируются с утилитой sudo.

В результате скрипт обогатился двумя функциями и одной проверкой:

local sessionfile="$HOME/.bitwarden_session"

get_saved_sessionkey () {
  sudo touch $sessionfile
  echo $(sudo cat $sessionfile)
}

save_sessionkey () {
  local sessionkey=$1
  sudo chmod 600 $sessionfile
  sudo sh -c "echo $sessionkey > $sessionfile"
} 
local sessionkey=$(get_saved_sessionkey)

if [[ -z $sessionkey ]] ; then
  # Get and save a new session key
  sessionkey=$(bw unlock --raw)
  save_sessionkey $sessionkey
else
  echo "Using the existing session key from '$sessionfile'."
fi

При первом запуске сессионный ключ, полученный после ввода мастер-пароля, записывается в файл, который после выполнения команды chmod 600 становится недоступен для чтения никому, кроме суперпользователя:

~ » ls -lah
...
-rw-------. 1 root root   89 Jul 24 22:15 .bitwarden_session
...

~ » less .bitwarden_session 
.bitwarden_session: Permission denied

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

Деактивировать сохранённый ключ можно с помощью команды bw lock. К сожалению, я так и не понял, как с помощью утилиты bw можно проверить, валиден ли ключ, так что после деактивации придётся удалить файл ~/.bitwarden_session вручную, иначе скрипт так и будет подставлять протухший сохранённый ключ, а bw будет каждый раз игнорировать его и настойчиво спрашивать мастер-пароль.

Применять с осторожностью

Взаимодействие с менеджером паролей выглядит для меня теперь примерно так:

~ » bwc github 
[sudo] password for $USER: 
Using the existing session key from '/home/$USER/.bitwarden_session'.
Searching for 'github'...

abcdefgh-ijkl-mnop-qrst-uvwxyz123456
github.com

Username 'Username' copied to clipboard.
Press any key to copy the password...
Password copied to clipboard.

Финальный вариант скрипта можно найти в репозитории He4eT/fuzzy-bitwarden-clipboard.

Настоятельно рекомендую читать любой код перед тем, как запускать его. Особенно в тех случаях, когда речь идёт о настолько чувствительных данных.

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

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

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

Пользуйтесь с осторожностью и/или храните свои пароли в надёжных местах =)