Summary: switch from pwstore to password-store for (and only for) TPA passwords
Background
TPA has been using a password manager called pwstore for a long time now. It's time to evaluate how it has served us. An evaluation of all password needs is being performed in issue 29677 but this proposal discusses only standalone passwords managed by TPA.
That specifically excludes:
- passwords managed by other teams or users
- moving root or LUKS password out of the password manager (could be accomplished separately)
Current problems
In any case, during a recent offboarding process (tpo/tpa/team#41519), it became very clear that our current password manager (pwstore) has major flaws:
-
key management: there's a separate keyring to manage renewals and replacement; it is often forgotten and duplicates the separate
.usersmetadata that designates user groups -
password rotation: because multiple passwords are stored in the same file, it's hard or impossible to actually see the last rotation on a single password
-
conflicts: because multiple passwords are stored in the same file, we frequently get conflicts when making changes, which is particularly painful if we need to distribute the "rotation" work
-
abandonware: a pull request to fix Debian bookworm / Ruby 3.1 support has been ignored for more than a year at this point
-
counter-intuitive interface: there's no command to extract a password, you're presumably supposed to use
gpg -dto read the password files, yet you can't use other tools to directly manipulate the password files because the target encryption keys are specified in a meta file -
not packaged: pwstore is not in Debian, flatpak, or anything else
-
limited OTP support: for sites that require 2FA, we need to hard-code a shell command with the seed to get anything working, like
read -s s && oathtool --totp -b $s
Proposal
The proposal is to adopt a short-term solution to some of the problems by switching to passwordstore. It has the following advantages:
-
conflict isolation: each password is in a separate file (although they can be store all in one file), resolving conflict issues
-
rotation support extensions like pass-update make it easier to rotate passwords (ideally, sites would support the change-password-url endpoint and pass would too, but that standard has seen little adoption, as far as we know)
-
OTP support: pass-otp is an extension that manages OTP secrets automatically, as opposed to the command-line cut-and-paste approach we have now
-
audit support: pass-audit can review a password store and look for weak passphrases
Limitations
Pass is not without problem:
-
key management is also limited: key expiry, for example, would still be an issue, except that the keyid file is easier to manage, as its signature is managed automatically by
pass init, provided that thePASSWORD_STORE_SIGNING_KEYvariable is set -
optional store verification: it's possible that operators forget to set the
PASSWORD_STORE_SIGNING_KEYvariable which will make pass accept unsigned changes to thegpg-idfile which could lead a compromise on the Git server be leveraged to extract secrets -
limited multi-store support: the
PASSWORD_STORE_SIGNING_KEYis global and therefore makes it complicated to have multiple, independent key stores -
global, uncontrolled trust store: pass relies on the global GnuPG key store although in theory it should be possible to rely on another keyring by passing different options to GnuPG
-
account names disclosure: by splitting secrets into different files, we disclose which accounts we have access to, but this is considered a reasonable tradeoff for the benefits it brings
Issues shared with pwstore
Those issues are not specific to pass, and also exist in pwstore:
-
mandatory client use: if another, incompatible, client (e.g. Emacs) is used to decrypt and re-encrypt the secrets, it might not use the right keys
-
GnuPG/OpenPGP: pass delegates cryptography to OpenPGP, and more specifically GnuPG, which is suffering from major usability and security issues
-
permanent history: using git leverages our existing infrastructure for file-sharing, but means that secrets are kept in history forever, which makes revocation harder
-
difficult revocation: a consequence of having client-side copies of passwords means that revoking passwords is more difficult as they need to be rotated at the source
Layout
This is what the pwstore repository currently looks like:
anarcat@angela:tor-passwords$ ls
000-README entroy-key.pgp external-services-git.pgp external-services.pgp hosts-extra-info.pgp hosts.pgp lists.pgp ssl-contingency-keys.pgp win7-keys.pgp
I propose we use the following layout in the new repository:
dns/- registrars and DNS providers access keys: joker.com, netnod, etchosting/- hosting providers: OSUOSL, Hetzner, etclists/- mailing list passwords (eventually deprecated by Mailman 3)luks/- disk encryption passwords (eventually moved to Arver or Trocla)misc/- whatever doesn't fit anywhere elseroot/- root passwords (eventually moved to Trocla)services/- external services: GitHub, Gitlab.com, etc
The mapping would be as such:
| pwstore | extra | pass |
|---|---|---|
entropy-key | misc/ | |
external-services-git | @gitadm | services/ |
external-services | dns/ hosting/ services/ | |
hosts-extra-info | dns/ hosting/ luks/ services/ | |
hosts | root/ | |
lists | @list | lists/ |
ssl-contingency-keys | misc/ | |
win7-keys | misc/ |
The groups are:
@admins = anarcat, lavamind, weasel
@list = arma, atagar, qbi, @admins
@gitadm = ahf
Affected users
This only concerns passwords managed by TPA, no other users should be affected.
Alternatives considered
The following were previously discussed or considered while writing this proposal.
Bitwarden
Bitwarden is the obvious, "larger" alternative here. It was not selected for this project because we want a short-term solution. We are also not sure we want to host the more sensitive TPA passwords alongside everyone else's passwords.
While Bitwarden does have an "offline" mode, it seems safer to just keep things simple for now. But we do keep that service in mind for future, organisation-wide improvements.
Alternative pass implementations
Pass is a relatively simple shell script, with a fairly simple design:
each file is encrypted with OpenPGP encryption, and a .gpg-id lists
encryption keys, one per line, for files inside the (sub)directory.
Therefore, other implementations have naturally crept up to provide
alternative implementations. Those are not detailed here because they
are mostly an implementation detail: since they are compatible, they
share the same advantages and limitations of pass, and we are not
aware of any implementation with significant enough differences to
warrant explicit analysis here. We'll just mention gopass and
ripasso as alternative implementations.
OpenPGP alternatives
Keepass, or probably more KeepassXC is an obvious, local-first alternative as well. It has a number of limitations that make it less usable for us: everything is stored in a single file, with not built-in mechanism for file-sharing. It's strongly geared towards a GUI usage as well. It is more suitable to individual than teams.
Another alternative is Age encryption, which is a "simple, modern and secure encryption tool (and Go library) with small explicit keys, no config options, and UNIX-style composability". It uses X25519 keys for encryption and is generally compatible only with other Age clients, but does support encryption to SSH keys (RSA and ED25519). Their authors have forked pass to provide a password manager with similar features, but lacking authentication (as age only provides encryption). Minisign might be somehow integrated in there but that that point, you're wondering what's so bad about OpenPGP that you're reinventing it from scratch. Gopass has an experimental age backend that could be used to transition to age, if we ever need to.
In theory, it's possible to use SSH keys to encrypt and decrypt files, but there are not, as far as we know (and apart from Age's special SSH mode), password managers based on SSH.
Alternative synchronisation mechanisms
The "permanent history" problem mentioned above could be solved by using some other synchronisation mechanism. Syncthing, in particular, could be used to synchronise those files securely, in a peer-to-peer manner.
We have concerns, however, about the reliability of the synchronisation mechanism: while Syncthing is pretty good at noticing changes and synchronising things on the fly, it can be quirky. Sometimes, it's not clear if files have finished syncing, or if we really have the latest copy. Operators would need to simultaneously be online for their stores to keep updating, or a relay server would need to be used, at which point we now have an extra failure point...
At that point, it might be simpler to host the password manager on a more "normal" file sharing platform like Nextcloud.
This issue is currently left aside for future considerations.
Approval
This has already been approved during a brief discussion between lavamind and anarcat. This document mostly aims at documenting the reasoning for posterity.
References
- issue 29677 discusses password management more broadly
- issue 41522 aims at implementing this proposal