gpg, ssh & git
the ugh
i was having some issues with using multiple accounts in git while managing ssh and pgp keys with gpg-agent. gpg-agent picked ssh keys based on fixed priority, so the selected didn't always have access to my current repository. pinentry-curses, which i otherwise like, doesn't show the name or email of the identity when prompting for ssh key. pinentry frequently prompted for a password of a key that didn't have access to the remote repository.
i needed to ensure that ssh key always corresponds to the repository.
what's working.
a login script searches for gpg keys based on any identifier, enables ssh for those keys with gpg-agent and exports the public ssh keys for use in the ssh configuration.
if command -v gpg-agent > /dev/null; then
gpg-connect-agent updatestartuptty /bye > /dev/null 2>&1
sshs_location="$GNUPGHOME/sshs"
key_directory="$HOME/.ssh/public"
if [[ -f "$sshs_location" ]]; then
while IFS= read -r line; do
keygrip=$(gpg --list-secret-keys --with-keygrip --with-colons "$line" 2>/dev/null | awk -F: '
BEGIN { found_auth = 0 }
($1 == "sub" || $1 == "ssb") {
if (index($12, "a") > 0) {
found_auth = 1
} else {
found_auth = 0
}
}
$1 == "grp" && found_auth == 1 {
print $10
exit 0
}
')
if [[ -n "$keygrip" ]]; then
gpg-connect-agent "keyattr $keygrip Use-for-ssh: true" /bye > /dev/null
if [[ ! -f "$key_directory/$line.ssh" ]]; then
gpg --export-ssh-key "$line" > "$key_directory/$line.ssh"
fi
fi
done < "$sshs_location"
fi
fithis improves on the deprecated but convenient sshcontrol file that requires a list of keygrips. instead sshs can use any identifier as long as it results in one key.
si@mmmeon
n@users.noreply.github.com
0x30FDAS89S1K50finally, the ssh configuration needs to use these ssh keys. fake hosts specify a unique host & identity file combination. the configuration doesn't need this when each provider maps has one account.
+Host mmm.sr.ht
+ HostName git.sr.ht
+ User git
+ IdentityFile ~/.ssh/public/si@mmmeon.ssh
+ IdentitiesOnly yes
-Host git.sr.ht
- User git
- IdentityFile ~/.ssh/public/si@mmmeon.ssh
- IdentitiesOnly yes
in the multi-account setup git clone git@git.sr.ht:~mmmeon/dot intuitively becomes git clone mmm.sr.ht:~/mmmeon/dot.
similarly, for already cloned repositories, git remote remove origin && git remote add origin mmm.sr.ht:~/mmmeon/dot does the same.