Linux: GPG-ключи, менеджер паролей pass и импорт из KeePass

Автор: | 25/04/2019

pass – менеджер паролей для Linux/UNIX, наверно один из старейших.

Хранит данные в древовидной структуре каталогов и файлов, а сами файлы с секретами шифрует с помощью GPG-ключа.

В Arch Linux есть из коробки, в Debian можно установить с помощь apt из дефолтных репозиториев:

[simterm]

$ sudo apt install pass

[/simterm]

В macOS – с помощью Homebrew:

[simterm]

$ brew install pass

[/simterm]

Хотя я сомневаюсь, что Mac-пользователи будут им пользоваться 🙂

Являет собой просто bash-скрипт:

[simterm]

$ head /usr/bin/pass
#!/usr/bin/env bash

# Copyright (C) 2012 - 2018 Jason A. Donenfeld <[email protected]>. All Rights Reserved.
# This file is licensed under the GPLv2+. Please see COPYING for more information.

umask "${PASSWORD_STORE_UMASK:-077}"
set -o pipefail

GPG_OPTS=( $PASSWORD_STORE_GPG_OPTS "--quiet" "--yes" "--compress-algo=none" "--no-encrypt-to" )
GPG="gpg"

[/simterm]

GPG ключи

Создание ключа

Для работы pass потребуется GPG-ключ, создаём его (см. Linux: GnuPG — управление GPG ключами):

[simterm]

$ gpg --full-gen-key
...
Please select what kind of key you want:
   (1) RSA and RSA (default) // оставляем по-умолчанию RSA and RSA
   (2) DSA and Elgamal 
   (3) DSA (sign only)
   (4) RSA (sign only)
Your selection? 
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048)  // оставляем по-умолчанию 2048
Requested keysize is 2048 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0)  // оставляем по-умолчанию 0 - без валиден навеки
Key does not expire at all
Is this correct? (y/N) y

GnuPG needs to construct a user ID to identify your key.

Real name: example
Email address: [email protected]
Comment: 
You selected this USER-ID:
    "example <[email protected]>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
...

[/simterm]

Появится окно с запросом на ввод пароля для доступа к ключу:

Вводим пароль, и завершаем создание ключа:

[simterm]

...
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: key 714F9CBFDA191430 marked as ultimately trusted
gpg: revocation certificate stored as '/home/setevoy/.gnupg/openpgp-revocs.d/E130BB49AAA234F2BE2A7F96714F9CBFDA191430.rev'
public and secret key created and signed.

pub   rsa2048 2019-04-25 [SC]
      E130BB49AAA234F2BE2A7F96714F9CBFDA191430
uid                      example <[email protected]>
sub   rsa2048 2019-04-25 [E]

[/simterm]

Проверяем список публичных ключей:

[simterm]

$ gpg --list-keys
gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   2  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 2u
/home/setevoy/.gnupg/pubring.kbx
--------------------------------
pub   rsa2048 2010-02-11 [SC]
      1C61A2656FB57B7E4DE0F4C1FC918B335044912E
uid           [ unknown] Dropbox Automatic Signing Key <[email protected]>

pub   rsa2048 2011-04-26 [SC]
      FCF986EA15E6E293A5644F10B4322F04D67658D8
uid           [ unknown] FFmpeg release signing key <[email protected]>
sub   rsa2048 2011-04-26 [E]

pub   rsa4096 2018-04-02 [SC]
      ABBAD1CB484F53024CF5868B69332F9203F21F5C
uid           [ unknown] Andrew Richards (cancel) <[email protected]>
sub   rsa2048 2019-01-28 [S]
sub   rsa4096 2018-04-02 [E]

pub   rsa2048 2019-04-25 [SC]
      DEB0D4AD41CC2612B1944D448D22D6610B2F6067
uid           [ultimate] setevoy (my main) <[email protected]>
sub   rsa2048 2019-04-25 [E]

pub   rsa2048 2019-04-25 [SC]
      E130BB49AAA234F2BE2A7F96714F9CBFDA191430
uid           [ultimate] example <[email protected]>
sub   rsa2048 2019-04-25 [E]

[/simterm]

И своих приватных:

[simterm]

$ gpg --list-secret-keys
/home/setevoy/.gnupg/pubring.kbx
--------------------------------
sec   rsa2048 2019-04-25 [SC]
      DEB0D4AD41CC2612B1944D448D22D6610B2F6067
uid           [ultimate] setevoy (my main) <[email protected]>
ssb   rsa2048 2019-04-25 [E]

[/simterm]

Удаление ключа

Что бы удалить ключ – надо удалить его приватную часть, после чего можно удалить публичную.

Удаляем приватный ключ:

[simterm]

$ gpg --delete-secret-key E130BB49AAA234F2BE2A7F96714F9CBFDA191430
gpg (GnuPG) 2.2.15; Copyright (C) 2019 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

sec  rsa2048/714F9CBFDA191430 2019-04-25 example <[email protected]>

Delete this key from the keyring? (y/N) y
This is a secret key! - really delete? (y/N) y

[/simterm]

Аргументом --delete-secret-key можно передать либо отпечаток (fingerprint), либо имя, в данном примере – “example“.

Теперь можно удалить и публичный ключ, используя --delete-key:

[simterm]

$ gpg --delete-key E130BB49AAA234F2BE2A7F96714F9CBFDA191430
gpg (GnuPG) 2.2.15; Copyright (C) 2019 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

pub  rsa2048/714F9CBFDA191430 2019-04-25 example <[email protected]>

Delete this key from the keyring? (y/N) y

[/simterm]

Резервное копирование GPG-ключей

Т.к. ключём будет шифроваться хранилище паролей – то терять этот ключ не хочется.

Забекапить ключи можно либо просто скопировав весь каталог ~/.gnupg (в случае, если используется GnuPG):

[simterm]

$ ll .gnupg/
total 52
drwx------ 2 setevoy setevoy  4096 Jan 22 12:44 crls.d
drwx------ 2 setevoy setevoy  4096 Apr 25 10:04 openpgp-revocs.d
drwx------ 2 setevoy setevoy  4096 Apr 25 10:11 private-keys-v1.d
-rw-r--r-- 1 setevoy setevoy 13732 Apr 25 10:14 pubring.kbx
-rw-r--r-- 1 setevoy setevoy 12317 Apr 25 09:58 pubring.kbx~
-rw-r----- 1 setevoy setevoy   676 Apr 25 09:54 sshcontrol
-rw------- 1 setevoy setevoy  1440 Apr 25 10:14 trustdb.gpg

[/simterm]

Либо экспортировав приватные ключи в отдельное хранилище:

[simterm]

$ gpg --export-secret-keys > ~/Dropbox/Backups/gpg-setevoy-arch-work-secret-backup.gpg

[/simterm]

При экспорте будет запрошен пароль от вашего секретного ключа/ей:

А восстановить его можно с помощью --import.

Удалим имеющийся ключ:

[simterm]

$ gpg --delete-secret-key setevoy

[/simterm]

И восстановим его из бекапа:

[simterm]

$ gpg --import ~/Dropbox/Backups/gpg-setevoy-arch-work-secret-backup.gpg
gpg: key 8D22D6610B2F6067: "setevoy (my main) <[email protected]>" not changed
gpg: key 8D22D6610B2F6067: secret key imported
gpg: Total number processed: 1
gpg:              unchanged: 1
gpg:       secret keys read: 1
gpg:   secret keys imported: 1

[/simterm]

Проверяем:

[simterm]

$ gpg --list-secret-keys
/home/setevoy/.gnupg/pubring.kbx
--------------------------------
sec   rsa2048 2019-04-25 [SC]
      DEB0D4AD41CC2612B1944D448D22D6610B2F6067
uid           [ultimate] setevoy (my main) <[email protected]>
ssb   rsa2048 2019-04-25 [E]

[/simterm]

pass

Создание хранилища

Инициализируем хранилище, используя имя (ID) или почту вашего GPG-ключа:

[simterm]

$ pass init setevoy
Password store initialized for setevoy

[/simterm]

pass создаст файл идентификации – ~/.password-store/.gpg-id:

[simterm]

$ cat .password-store/.gpg-id 
setevoy

[/simterm]

pass Git и Github

Кроме стандартного хранилища – pass может создать его в виде git-репозитория, и вести историю всех изменений.

Если глобальные настройки Git-пользователя ещё не сделаны – выполняем:

[simterm]

$ git config --global user.email [email protected]
$ git config --global user.name "setevoy"

[/simterm]

Создаём git-репозиторий для уже созданного хранилища:

[simterm]

$ pass git init
Initialized empty Git repository in /home/setevoy/.password-store/.git/
[master (root-commit) 7e19ab0] Add current contents of password store.
 1 file changed, 1 insertion(+)
 create mode 100644 .gpg-id
[master 19aaf2c] Configure git repository for gpg file diff.
 1 file changed, 1 insertion(+)
 create mode 100644 .gitattributes

[/simterm]

И теперь доступна вся история, как с обычным Git:

[simterm]

$ cd .password-store/
$ git log
commit d8f791453fd1e8be7cf6126cde7f32df3bd351cc (HEAD -> master)
Author: setevoy <[email protected]>
Date:   Thu Apr 25 11:08:19 2019 +0300

    Configure git repository for gpg file diff.

commit d49c886510221f31268f22cd74d0859965bafb7b
Author: setevoy <[email protected]>
Date:   Thu Apr 25 11:08:19 2019 +0300

    Add current contents of password store.

[/simterm]

Далее можно создать приватный репозиторий в Github или Bitbucket, добавить вашу базу pass в него, и синхронизировать базы между разными компьютерами через единый git-репозиторий, выполняет git push/git pull.

Хотя мысль о том, что бы хранить все свои пароли пусть и в приватном репозитории, пусть в зашифрованных файлах, но в Github – имхо идея очень так себе.

Другой вариант – поднять Git-сервер где-то у себя, и синхронизировать через него.

Тем не менее, для примера – создаём репозиторий в Github:

Копируем его адрес, тут это [email protected]:setevoy2/pass-example.git:

Переходим в каталог хранилища на своей машине:

[simterm]

$ cd ~/.password-store/

[/simterm]

Обновляем настройки репозиторий – добавляем remote:

[simterm]

$ git remote add origin [email protected]:setevoy2/pass-example.git

[/simterm]

Проверяем:

[simterm]

$ cat .git/config 
[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
[diff "gpg"]
        binary = true
        textconv = gpg2 -d --quiet --yes --compress-algo=none --no-encrypt-to --batch --use-agent
[remote "origin"]
        url = [email protected]:setevoy2/pass-example.git
        fetch = +refs/heads/*:refs/remotes/origin/*

[/simterm]

И пушим в Github:

[simterm]

$ git push origin master
...
To github.com:setevoy2/pass-example.git
 * [new branch]      master -> master

[/simterm]

Проверяем:

Добавление пароля

Для добавления используем insert, затем путь в виде каталога(ов) и имя пользователя.

Например, для RTFM добавление могло бы выглядеть так:

[simterm]

$ pass insert rtfm.co.ua/admin/setevoy
mkdir: created directory '/home/setevoy/.password-store/rtfm.co.ua'
mkdir: created directory '/home/setevoy/.password-store/rtfm.co.ua/admin'
Enter password for rtfm.co.ua/admin/setevoy: 
Retype password for rtfm.co.ua/admin/setevoy: 
[master 7ae47c9] Add given password for rtfm.co.ua/admin/setevoy to store.
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 rtfm.co.ua/admin/setevoy.gpg

[/simterm]

Просмотр и получение секретов

Теперь структура хранилища выглядит так:

[simterm]

$ pass
Password Store
└── rtfm.co.ua
    └── admin
        └── setevoy

[/simterm]

Для получения пароля – указываем полный путь к файлу, и вводим пароль GPG-ключа:

[simterm]

$ pass rtfm.co.ua/admin/setevoy
p@ssw0rd

[/simterm]

Можно сразу скопировать его в буфер обмена – добавляем -c:

[simterm]

$ pass -c rtfm.co.ua/admin/setevoy
Copied rtfm.co.ua/admin/setevoy to clipboard. Will clear in 45 seconds.

[/simterm]

И история git:

[simterm]

$ git log
commit 7ae47c9535eabddc64c89df39c7db720a2cd5244 (HEAD -> master)
Author: setevoy <[email protected]>
Date:   Thu Apr 25 11:12:16 2019 +0300

    Add given password for rtfm.co.ua/admin/setevoy to store.
...

[/simterm]

Многострочные записи

Кроме просто пароля – можно добавить различную информацию.

Что бы внести несколько строк в файл – используем -m. При этом сам пароль указывайте первой строкой – -c использует её для копирования в буфер:

[simterm]

$ pass insert -m rtfm.co.ua/admin/setevoy
An entry already exists for rtfm.co.ua/admin/setevoy. Overwrite it? [y/N] y
Enter contents of rtfm.co.ua/admin/setevoy and press Ctrl+D when finished:

p@ssw0rd
Username: setevoy
URL: rtfm.co.ua
[master fc43a4c] Add given password for rtfm.co.ua/admin/setevoy to store.
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 rtfm.co.ua/admin/setevoy.gpg

[/simterm]

Проверяем:

[simterm]

$ pass show rtfm.co.ua/admin/setevoy
p@ssw0rd
Username: setevoy
URL: rtfm.co.ua

[/simterm]

Поиск паролей

Для поиска у pass есть две опции – find, и grep.

find выполняет поиск по именам каталогов и файлов:

[simterm]

$ pass find setevoy
Search Terms: setevoy
├── rtfm.co.ua
    └── admin
        └── setevoy

[/simterm]

А grep – по тексту всех файлов:

[simterm]

$ pass grep rtfm.
rtfm.co.ua/admin/setevoy:
URL: rtfm.co.ua
...

[/simterm]

Удаление пароля

Вызываем pass с опцией rm:

[simterm]

$ pass rm rtfm.co.ua/admin/setevoy
Are you sure you would like to delete rtfm.co.ua/admin/setevoy? [y/N] y
removed '/home/setevoy/.password-store/rtfm.co.ua/admin/setevoy.gpg'
[master 7a23ede] Remove rtfm.co.ua/admin/setevoy from store.
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 rtfm.co.ua/admin/setevoy.gpg

[/simterm]

Для удаления каталога – используйте rm -r:

[simterm]

$ pass rm -r Main
Are you sure you would like to delete Main? [y/N] y
removed '/home/setevoy/.password-store/Main/Work/blabla.com.gpg'
...

[/simterm]

Импорт из KeePass

Собственно, pass я добавил как резервное хранилище паролей.

В основном используется KeePass (точнее – KeePassXC), база хранится в Dropbox и синхронизирует KeePass между разными компьютерами.

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

Используем pass-import, который умеет выполнять импорт из различных хранилищ, в том числе из XML-файла, сгенерированного KeePass.

На Arch Linux можно установить из AUR:

[simterm]

$ yaourt -S pass-import

[/simterm]

Создаём копию (из KeePass – KeePassXC не умеет в XML):

И выполняем импорт: указываем менеджер паролей (тут – keepass) и путь к файлу:

[simterm]

$ pass import keepass ~/Backups/KeePassBKP/KeePass-Main-25-04-2019-bkp.xml
 (*) Importing passwords from keepass
  .  File: /home/setevoy/Backups/KeePassBKP/KeePass-Main-25-04-2019-bkp.xml
  .  Number of password imported: 294
  .  Passwords imported:
       Main/AWS/AWS root user
       Main/AWS/AWS setevoy
       Main/Cards/Aval Credit
...

[/simterm]

Проверяем хранилище pass теперь:

[simterm]

$ pass
Password Store
├── Main
│   ├── AWS
│   │   ├── AWS root user
│   │   └── AWS setevoy
│   ├── Cards
│   │   ├── Aval Credit
│   │   ├── OtherCards
│   │   │   ├── Masha
│   │   │   ├── Stromenko etabak
...

[/simterm]

QtPass

Консоль – хорошо, но иногда хочется UI.

Для pass есть QtPass.

В Arch Linux устаналивается из стандартного репозитория:

[simterm]

$ sudo pacman -S qtpass

[/simterm]

Запускаем:

Готово.