sourceless

index about contact

Make your own (free) password manager

Before I say anything else, it should be noted that this solution requires a little bit of background knowledge to set up and use. At the very least you'll need to be comfortable on the command line in linux/osx, especially with installing packages, git, ssh, and a little gpg. Don't worry if you don't know all of that – a little familiarity should be enough.

Why I rolled my own

You might be wondering what the point is of setting up your own password manager is when so many good, paid alternatives exist – and you'd be right!

There is however, some advantage in knowing exactly how your passwords are encrypted and being able to integrate your password store with EVERYTHING.

And it's run at no cost to me.

Standard warnings apply; the UX will not be as good. If you do not back up your GPG keys, you could lose access to your passwords forever. The security of your password manager is only as good as the security of your system.

Features and composition

Our password manager will have the following features:

We'll make it with these components:

Make sure you have all the above installed before continuing!

Steps

1. Generate a gpg key

There's lots of guides on doing this, but here's an example (from 2022, if you're reading this in the future, google it first because best practice has probably changed!).

gpg --default-new-key-algo "ed25519/cert,sign+cv25519/encr" \
    --quick-generate-key "my@email.com"

This will generate a new multi-purpose ed25519 key with no expiration date.

It's up to you if you want to use this to generate subkeys to use for the password store. I would, however, recommend that you make one key per device sou you can revoke access if a device is lost or stolen!

If you've already got a gpg key and want to use it – use that.

**And before anything else - back up your key! On a storage drive, paper, obelisk, yubikey - and in more than one place!**

2. Init the password store

pass init <your gpg key id from step 1>

That's it! If you want to use multiple keys (e.g. one per device), just add any additional IDs after the first.

3. Add your first password

pass generate my-first-password 100

This will generate a random 100-character password for you named my-first-password.

It'll print on the terminal in the first instance, and you probably don't want that, so you can pass the -c flag to send the password directly to your clipboard instead.

pass -c my-first-password

To edit a password, use pass edit:

pass edit my-first password

You'll see that on the first line of this file is your generated password. You can add more lines with notes or key-value pairs, which some clients can use for autofill:

<generated password here>
Url: login.website.com
Username: my-username

For more commands, see the password-store docs.

4. Set up sync

First, init the pass git repository:

pass git init

Then, go to your chosen git hosting provider and create a private repo. Once you have an empty private repo, you can go ahead and add the remote:

pass git remote add origin <repo git url>

Then, do your first push:

pass git push -u origin

Now when you go to view your repo, you'll see an encrypted file called my-first-password.gpg, which can only be read if you have your gpg key to hand.

If you want to auto-sync whenever a password is changed, add a post-commit hook to ~/.password-store/.git/hooks that pushs to your repo.

5. Integrating with other devices

Take a look at the list of compatible clients to find pass clients for your other devices. Most have pretty good docs on how to set them up, and most offer autofill and automatic syncing.

I would suggest creating a new gpg key or sub-key for each device so you can revoke them individually. For an extra layer of security, you can add a password to the keys, but this will impact UX.

6. Migrating from your old password manager

Now the only remaining step is to move your old passwords!

Fortunately there's a plethora of tools available!


Posted 2022-08-16

← Put Ticket IDs in your Commit Messages Programming in Functional Style: Functions →