Github, ssh keys and 2FA
Avg. 5 minute(s) of readingI recently found myself setting up 2FA on my GitHub account and for that I started using the ssh protocol instead of the default https protocol. This is a quick guide explaining how and why you'd want to do that too.
Introduction
I have a little project going on where I use a
raspberry pi zero as a
dedicated password manager. It could more accurately be described as a secrets
keeper/manager, but I use it mostly for passwords.
Anyway, I wanted to set up 2FA for as many services as I could (I'm currently using
FreeOTP+ on android
and it has everything I need/want), so I started setting them up. Both my raspberry
pi and my android have the OTPs for redundancy.
At some point, I set up 2FA on my Github account and all seemed well, until I tried pushing to one of my GitHub repositories from the command line.
2FA and the command line
It seems like 2FA and git from the command line don't play well together. For example, if you try to clone a private repository, your credentials will not be accepted. You'll get an "invalid username or password" error message. This happens because GitHub uses the https protocol by default and recommends it for its users, because it usually works out of the box.
If you want to use 2FA (you should) with git on the command line, you'll have to use one of these solutions.
Solution 1: Create a personal access token
You should do this if you intend to keep using the https protocol for your GitHub operations. GitHub has a nice step-by-step guide on their help page explaining how to do this, but the tl;dr is:
- Go to your account settings;
- Go to the Developer settings tab;
- Go to the Personal access tokens tab;
- Press the Generate new token button;
- Give it a name and the permissions you want/need (e.g.: repo);
- Copy the token and keep it safe like you would for your password (the token isn't recoverable).
Now to use the token, you just need to provide it during the authentication process instead of your password.
I don't like this solution because you have to keep track of 2 different passwords (more vulnerable) and this new "token password" defeats the purpose of 2FA (since it bypasses the 2FA temporary code). You can mitigate these problems by limiting how much power the access token has (give it fewer permissions), but it still isn't optimal.
Solution 2: Use the ssh protocol
To use the ssh protocol, you'll need an ssh key pair. While browsing the web, I came across this amazing tutorial, which helped me understand the subject better and quickly set everything up correctly.
I advise you to read it, but if you're in a hurry and on Linux, you can just copy the commands below (which were taken from the tutorial linked above) and follow the on-screen instructions:
# this will ask for a filename and an optional passphrase for the key (you should
# provide it one)
ssh-keygen -t rsa -b 4096 -C "USEFUL-COMMENT"
# this makes sure the ssh-agent is running
eval "$(ssh-agent -s)"
# add your key to the ssh-agent (change the path to the key if you didn't use
# the default)
ssh-add ~/.ssh/id_rsa
After generating your key, you just need to associate the generated public key
with your GitHub account. To do this, you need to go to your GitHub account
settings, access the SSH and GPG keys tab, and copy the contents of your
public key to a new ssh key, e.g. using:
xclip -sel clip < ~/.ssh/id_rsa.pub
to insert the key contents into your
clipboard.
Now that you have associated your ssh key with your account, you just need to start using the ssh protocol versions of your remote links.
Imagine you have the following repository:
https://github.com/leereilly/games.git
. It is using the https protocol.
The equivalent ssh protocol link is: [email protected]:leereilly/games.git
.
As you can see, it is really easy to convert from one protocol to another. I
even found a small bash script to make
the conversion of your repository's remotes to the ssh protocol.
#/bin/bash
#-- Script to automate https://help.github.com/articles/why-is-git-always-asking-for-my-password
REPO_URL="$(git remote -v | grep -m1 '^origin' | sed -Ene's#.*(https://[^[:space:]]*).*#\1#p')"
if [ -z "$REPO_URL" ]; then
echo "-- ERROR: Could not identify Repo url."
echo " It is possible this repo is already using SSH instead of HTTPS."
exit
fi
USER="$(echo $REPO_URL | sed -Ene's#https://github.com/([^/]*)/(.*).git#\1#p')"
if [ -z "$USER" ]; then
echo "-- ERROR: Could not identify User."
exit
fi
REPO="$(echo $REPO_URL | sed -Ene's#https://github.com/([^/]*)/(.*).git#\2#p')"
if [ -z "$REPO" ]; then
echo "-- ERROR: Could not identify Repo."
exit
fi
NEW_URL="[email protected]:$USER/$REPO.git"
echo "Changing repo url from "
echo " '$REPO_URL'"
echo " to "
echo " '$NEW_URL'"
echo ""
git remote set-url origin "$NEW_URL"
echo "Success"
This is the solution that I went with. I believe the only problem you can have while using the ssh protocol is having the connection to port 22 (ssh port) blocked is in your network. I've never had that problem, but GitHub suggests that you may still be able to use ssh over the https port if you ever find yourself in such a situation.
Conclusions
This was mostly a quick PSA to get more people to use the ssh protocol and
2FA on github. It's easy and it'll keep your accounts more secure.
Stay safe :P