My migration from keepassxc to pass (password store)

marceloandrade profile image Marcelo Andrade R. Originally published at marceloandrader.github.io ・7 min read


My initial way to keep my long list of passwords/secrets safe in my computer was using the password manager keepassxc it served well, the way to share this with my mobile was putting the kdbx file in Dropbox and use KeePassDroid app to be able to use my passwords on the go.

Why the migration?

Well I've started to have a couple of issues with my current setup, the main issue I was having was I have to keep a window open for the password manager, where I have to go search and copy/paste the data or ask to perform an auto type for me, I started to dislike this because as a developer I normally work only in 2 windows: the browser and a terminal, so that is why I started to look for an alternative. The second issue was that when I tried to configure gmail with mutt I had to put my password in plain text in a file.

The chosen one

When I was setting up my mutt/mbsync/msmtp to use gmail from the terminal (topic for another post), I've found that you have to enter your credentials in a plain text config file, I didn't want to do that, and some other people also didn't do that and they have a solution: pass with this simple cli utility I no longer have to write passwords in config files, it can be automated to consume the password from my store without intervention.

Advantages of pass

  • It follows the Unix philosophy, it does one thing well and can be composable.
  • Each password lives inside a gpg encrypted file that can be organized using standard unix commands cp, mv, rm
  • It has the feature to copy to clipboard built-in
  • It tracks password changes using git this is supe awesome because this way I can distribute my passwords to other devices without much hassle.
  • Before the migration I checked that it support the import from other password managers and indeed has an extension with support for 25 different managers pass-import
  • Also has nice list of compatible clients, I'll use Android-Password-Store for my mobile.
  • And it has a couple of browser extensions to fill/submit on sites really easy without having another window open

Initial setup

All the setup was done in a linux machine with Pop!OS 18.10.

Configure GPG

First we need to create a gpg key that pass will use to encrypt/decrypt the password files.

% gpg --gen-key

It will ask for a real name of the key and an email, and also a passphrase that should be at least 8 characters and have a digit.

⏚ [marcelo:~] % gpg --gen-key

gpg (GnuPG) 2.2.8; Copyright (C) 2018 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.

Note: Use "gpg --full-generate-key" for a full featured key generation dialog.

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

Real name: Pass Migration
Email address: pass.migration@gmail.com
You selected this USER-ID:
    "Pass Migration <pass.migration@gmail.com>"

Change (N)ame, (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.
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 B9E32CDD4190FC22 marked as ultimately trusted
gpg: revocation certificate stored as '/home/marcelo/.gnupg/openpgp-revocs.d/23434EEF535B0E7C702E36A9B9E32CDD4190FC22.rev'
public and secret key created and signed.

pub   rsa3072 2019-04-11 [SC] [expires: 2021-04-10]
uid                      Pass Migration <pass.migration@gmail.com>
sub   rsa3072 2019-04-11 [E] [expires: 2021-04-10]

Check that the gpg key exists:

% gpg -k

pub   rsa3072 2019-04-11 [SC] [expires: 2021-04-10]
uid           [ultimate] Pass Migration <pass.migration@gmail.com>
sub   rsa3072 2019-04-11 [E] [expires: 2021-04-10]

Init the store

The command to init the store in pass is the following, you need the key id created in the previous step as the parameter:

% pass init "Pass Migration"

This will create a directory in your ~/.password-store/ and will write a .gpg-id so pass know what key to use to encrypt/decrypt from now on.

mkdir: created directory '/home/marcelo/.password-store'
Password store initialized for Pass Migration (migration)

Init git in the store

To track all your password changes with git, you just need to init the repo on the directory:

% pass git init

Initialized empty Git repository in /home/marcelo/.password-store/.git/

This allows you to keep the history of your passwords, and it helps with the distribution of the store to other devices and to keep them in sync.

Add a git remote

In order to backup/distribute your passwords you can set a remote for the .password-store repository, you need to change the data between <>

% pass git remote add origin git@github.com:<your-user>/<your-repo>.git
% pass git push -u master

After that when anything happens in pass, it will create a commit for each change automatically, you just need to do a push/pull to sync it

% pass git push
% pass git pull

Day to day use of the password store

Add new passwords

The insert command allows you to manually enter the password to be saved.

% pass insert Personal/testing
Enter password for Personal/testing:******
Retype password for Personal/testing:******
[master bf1bc88] Add given password for Personal/testing to store.
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 Personal/testing.gpg

As you can see pass created the testing.gpg file and committed to the repo.

If you want that pass generate a password for you, use the generate command:

% pass generate Personal/testing2
[master 8b0da79] Add generated password for Personal/testing2.
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 Personal/testing2.gpg
The generated password for Personal/testing2 is:

Given that pass encrypt all the file, you can add some other metadata to the file like usernames, urls, secret question answers, etc. For that you should use insert in multiple lines, the only thing you need to remember is that the first line is always the password.

% pass insert -m Personal/testing-multiline
Enter contents of Personal/testing-multiline and press Ctrl+D when finished:

url: http://example.com
login: marceloandrade

question1: xhdjahdfasdjfkasjdfaks
question2: fjasdkfj9dfas0dfa9d8f7
[master 3a133ec] Add given password for Personal/testing-multiline to store.
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 Personal/testing-multiline.gpg

Consume passwords

To use a password just do pass Personal/testing that will echo your password, if you don't want to show the password in your terminal, pass the -c parameter to copy to clipboard pass -c Personal/testing that will keep your password in the clipboard for 45 seconds, enough to paste it where you need it.

Update a password

You can use pass edit Personal/testing-multiline that will open the decrypted content in a temporary file with your default editor, you can do changes and save & exit.

[master fa72ec0] Edit password for Personal/testing-multiline using nvim.
 1 file changed, 0 insertions(+), 0 deletions(-)
 rewrite Personal/testing-multiline.gpg (100%)

Having a diff in password changes directly in git

After you have edited a password you can check directly with git what the change was:

% pass git log

To copy the sha1 of the commit where you did the change

% pass git show fa72ec0a9e51459e8223a6872647f3388ff8a96f
commit fa72ec0a9e51459e8223a6872647f3388ff8a96f (HEAD -> master)
Author: Marcelo Andrade R
Date:   Thu Apr 11 12:11:11 2019 -0500

    Edit password for Personal/testing-multiline using nvim.

    diff --git a/Personal/testing-multiline.gpg b/Personal/testing-multiline.gpg
    index 1c957b8..7dfa9a4 100644
    --- a/Personal/testing-multiline.gpg
    +++ b/Personal/testing-multiline.gpg
    @@ -1,4 +1,4 @@
     url: http://example.com
     login: marceloandrade

Removing a password

To delete use pass rm Personal/testing and will be removed from the store.

Are you sure you would like to delete Personal/testing? [y/N] y
removed '/home/marcelo/.password-store/Personal/testing.gpg'
[master 151f502] Remove Personal/testing from store.
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 Personal/testing.gpg

Specific migration from keepassxc

Install pass-import

Go to the pass-import github repo and install it the way best suit your needs and environment, I cloned it, make and then sudo make install

Generate file.csv from keepassxc

From KeePassXC application, open your database with your master password, and then go to menu Database/Export to CSV file... that will write the file to disk, make sure it's secured because all your passwords are written in plain text in that file.

Run the pass import keepassxc file.csv

The tool to import is really easy to use:

% pass import keepassxc /path/to/file.csv

That command will insert each entry to the store, and do a commit on each one.

Shred the file

Because the file.csv is really unsecure way to save your passwords make sure to delete it securely:

% shred -u file.csv


It became a bit of a long post, let me know if something is not clear, I'll be happy to answer. Also maybe I'll do another post about the android app configuration to use the git repo.


  1. pass
  2. pass import extension


Editor guide
tarialfaro profile image
Tari R. Alfaro

I honestly prefer to stick to KeePassXC. While you're still secure using your method, you're essentially putting all of your eggs under one basket. I mean you already are by "one password for all your passwords" kinda thing.

However if you want to be more secure, you need to isolate things. Of course the whole point of a password manager is to provide some convenience by using one passphrase(the only one you have to remember) to encrypt your secure randomly generated passwords, and it does.

But you're also using PGP to sign GitHub commits(or maybe you don't do that) or encrypting messages and signing them as well. I still recommend to use KeePassXC over PGP because:

  1. The the algorithm. Argon2 is very good these days.

  2. It can be a lot more secure(at least in my mind) with all the settings you can set.

  3. If you want more convenience you can integrate it into your browser of choice. (Although, I recommend not doing so if you're paranoid)

So, generally you want to separate your baskets. PGP for communication. KeePassXC for credentials. AndOTP for OTP.

To take over your entire digital life, someone would need your passphrase, key file or both to gain access to your KeePassXC database. Then they also have to get your passphrase for your AndOTP backups. And to break your communications they would have to get your PGP keys.

All of which, I'm saying that you're still possibly secure doing this. But putting everything under one basket is a bit dangerous.

It's all about how much convenience you willing to gain by taking away security.

But hey! Great article.

marceloandrade profile image
Marcelo Andrade R. Author

Thanks for your insight, well I'm not that paranoid, I don't use PGP too much so it will be just for encrypting password. Like everything in life all goes down to the trade offs, and for my use case are Ok.