When working with a remote git repository, typing the password every single pull/push is quite tiresome.
A good way would be to store the credentials locally, however the most common way of doing so is just wrong from a security point of view.
The problem
Most people will search online for “how to store git credentials” and resort to this “solution”:
$ git config credential.helper store
This “trick” will actually create a plain text file ~/.git-credentials
with the password, when it’s typed the next time with git pull
or git push
commands.
Here’s what this file usually looks like:
https://<username>:<password>@<url>
This file gets 0600 permission by default, so only the current user can see it.
But that’s not good enough.
The solution
It starts with a simple command:
$ shred -u ~/.git-credentials
This command makes sure to remove the file and overwrite where it was stored on the drive, making it impossible to recover even if someone physically got hold of the machine.
Once we made sure nobody will ever be able to recover our password again, we’re left with two main options for encrypting the credentials.
The GNOME way: libsecret
This solution simply uses GNOME’s libsecret
for encrypting and storing the credentials. However, even though it’s GNOME, it should work on basically any UNIX system.
- Get and install
libsecret
which presents in any modern Linux distribution’s software repository.
Debian-based distributions:libsecret-1-0
andlibsecret-1-dev
packages. - Configure git to use
libsecret
(mind the--global
flag):$ git config --global credential.helper libsecret
This will effectively create a file
~/.gitconfig
with the following content (or append to the existing one):[credential] helper = libsecret
-
On the next
pull
orpush
commands, a popup should come up asking for a password:
This password will be used for encrypting what’s called a “keyring” which is used for encrypting the git password.
All keyrings are stored in~/.local/share/keyrings
.
With the default settings it’s required to type in the password only once per login session, which is much more convenient compared to each git
command.
Encrypting using GnuPG
For people who use pass, this should be the preferred option.
- Create a new password file (the name doesn’t matter):
$ pass add -m <name>
Note: The
-m
switch allows typing multi-line credentials. - Here’s the content that should be inside:
machine <domain> protocol <http|https|ssh> login <username> password <password>
machine
→ The repository’s domain name. (Ex: GitHub:github.com
, Bitbucket:bitbucket.org
)
protocol
→ Whatever fits the repository:http
,https
orssh
login
/password
→ The username and password for the service
Note: It’s possible to store multiple service’s credentials. Simply add another paragraph for each service. - Optional: By default, the credentials file is stored at
pass
main directory (usually~/.password-store
) but I recommend linking it to$HOME
for convenience:$ ln -s $HOME/.password-store/<file-name> $HOME/.git.gpg
Note: When linking files it’s usually safer to use
$HOME
instead of~/
to indicate the home directory. - Next, configure
git
accordingly, to use thenetrc
script:$ git config --global credential.helper "netrc -v -f <path-to-file>"
Encrypting manually using GnuPG (without pass
)
Those who don’t use pass
can still use this option, however it requires (a little bit of) extra work:
- Create a file with the content mentioned in step 2 above.
- Generate a new GPG key (if there’s none already):
$ gpg --gen-key
- Encrypt the file:
$ gpg -e -r <recipient> <path-to-file>
Note:
<recipient>
is usually the email address (of yourself). Usegpg --list-keys
to confirm. - Continue to step 4 above.
Troubleshooting
“Not a git command” error
When running git pull
or git push
for the first time, the following error might show up:
git: 'credential-<libsecret|netrc>' is not a git command. See 'git --help'.
It happens because on some distribution the required binary is not in $PATH
or even compiled.
To fix this, we need to find a file named git-credentials-libsecret
for libsecret
or git-credentials-netrc
for GnuPG.
Distribution | Path |
---|---|
Debian | /usr/share/doc/git/contrib/credential/ |
Arch | /usr/lib/git-core/ |
Then, choose one of the following:
- Copy
git-credentials-<libsecret|netrc>
to any directory in$PATH
. - Direct
git
to usegit-credentials-<libsecret|netrc>
from this location. Simply re-run the config command:$ git config --global credential.helper $PWD/git-credentials-<libsecret|netrc>
Note: We’re using
$PWD
that indicates the current path. This should be where thegit-credentials-<libsecret|netrc>
file is.
Notes:
- If the target file is in
$PATH
,git-credentials-
prefix will be automatically prepended tolibsecret
ornetrc
. git-credentials-netrc
supports--help
for more information (when running the script directly) and-d
for debugging.
For libsecret
only
If only a file named git-credentials-libsecret.c
is present, it means we have to compile it.
Make sure basic build packages are present on the system (build-essential
on Debian-based systems, for example):
$ sudo make
Note: The sudo
part is essential since we’re inside /usr
which is probably not owned by the current user.
This process should end in a fraction of a second on any machine.
“lookup failed” error
On Arch, the following error may show up:
** (process:6182): CRITICAL **: 22:10:58.547: lookup failed: GDBus.Error:org.freedesktop.DBus.Error.ServiceUnknown: The name org.freedesktop.secrets was not provided by any .service files
It can be fixed by installing the gnome-keyring
package which provides the necessary service for libsecret
to run.
Plain text ~/.git-credentials
keeps coming back
Some repositories might have been configured to use the store
plugin locally and those settings override the global ones.
To reset this setting, simply run inside the suspected repository:
$ git config --unset credential.helper
By the way, it’s possible to confirm (or change) those settings manually by editing .git/config
in every repository.
Can’t type in GnuPG password on a headless machine
GnuPG assumes that it runs inside an Xserver environment and tries to launch a window asking for a password. However, on a headless machine it’s not the case.
There’s a global variable $GPG_TTY
that can be set to fix this:
$ export GPG_TTY=$(tty)
Note: This line can be added to .bashrc
/.zshrc
for convenience.
Extra: GUI for credentials management
The Seahorse GUI utility can be used for managing all passwords stored by libsecret
or the keys for GnuPG.
It can even manage SSH keys and do a lot more.