OnCallReady

Lesson 1.17 · First Login · 12 min read

Git identity and an SSH key

In plain words

Imagine a padlock and key, but backwards. You make a key that never leaves your pocket (the private key) and a pile of matching padlocks you can hand out freely (the public key). You give GitHub a padlock. When you connect, GitHub locks a little puzzle with your padlock, and only your pocket key can open it. No password ever travels.

That is ssh-keygen -t ed25519: id_ed25519 stays on oncall-lab, id_ed25519.pub goes to GitHub. The first time you connect, you also write down GitHub's own face (its host key in known_hosts), so next time you would notice an impostor. And git config --global user.name is simply the name written on every page you add to the shared notebook.

Everything you build in this course goes into a git repository on GitHub. The first push from a new machine fails for everyone: git does not know who you are, and GitHub does not know this machine. This lesson sets up both - a name for your commits, and a key that proves the machine is allowed in.

What you need to know already: 1.1 Where you are (SSH), 1.3 The tree (dotfiles, permissions like 600).

git in five words

You probably used git from an editor; here is the vocabulary from the command line.

Git needs to know who you are

Every commit records a name and an email. Git will not guess them:

git config --global user.name  "Learner"
git config --global user.email "[email protected]"

git config sets a git setting. --global writes it to ~/.gitconfig, so it applies to every repo on this box for your user. Without --global it applies only to the repo you are standing in - useful when work and personal identities differ.

Check with git config --list.

A key instead of a password

SSH can log you in with a key pair instead of a password. It is two matching files made together:

You give GitHub your public key. When you connect, GitHub asks your machine to sign a random challenge with the private key and checks the signature with the public key. No password ever travels.

ssh-keygen -t ed25519 -C "[email protected]"

You get two files in ~/.ssh/:

ssh-keygen also asks for a passphrase: a password that encrypts the private key file itself, so a stolen copy is useless. Empty is fine on a throwaway lab VM. On anything real, set one.

Trust on first use

Keys work in both directions: the server has its own key pair too, its host key, so you can check that you reached the real server and not an impostor.

The first ssh to a host prints the host key's fingerprint and asks whether to continue. A fingerprint is a hash of the key: a short string computed from it, which changes completely if even one bit of the key changes. So comparing fingerprints is a quick way to compare keys. The question really means "is this really github.com?". Say yes, and the host key is saved in ~/.ssh/known_hosts; from then on, a different key for that host produces a loud warning instead of silently connecting you somewhere else.

"Yes" is only safe if the fingerprint is right. GitHub publishes its host key fingerprints in its docs ("GitHub's SSH key fingerprints"); the Ed25519 one is SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU (SHA256 is the hash method used). Compare before you type yes.

One Ubuntu surprise: its SSH settings (/etc/ssh/ssh_config) turn on HashKnownHosts yes, so the host name in known_hosts is stored hashed too: |1|salt|hash ssh-ed25519 AAAA.... grep github.com ~/.ssh/known_hosts therefore finds nothing. Ask ssh-keygen instead:

ssh-keygen -F github.com       Find: is this host in known_hosts? (prints the line)
ssh-keygen -R github.com       Remove it (after a legitimate host key change)
ssh-keygen -lf ~/.ssh/id_ed25519.pub     list the fingerprint of a key file

Finally, test the whole chain:

ssh -T [email protected]

[email protected] means "log in as user git on github.com" - everyone uses that same user; GitHub tells you apart by your key. -T means "no terminal, I just want to authenticate". A successful answer is GitHub greeting you by name and then refusing shell access - that refusal is the success.

What you can now do

Why it helps

Every change you make to a shared repository travels over git, and on servers that means SSH keys. The errors you learn here - Permission denied (publickey), "Host key verification failed", an HTTPS push rejected because passwords are no longer accepted - are the ones you will hit on every new machine, and the reasoning to fix them is always the same: which key, which user, which host key.

Knowing why ed25519, why the private key must be readable only by you, and what a "host identification has changed" warning means lets you tell a real attack apart from a server that was simply rebuilt.

Commands in this lesson

git

FAQ

Why ed25519 and not RSA?

ed25519 keys are short (the public key is one short line), fast, and strong by design, with fewer settings to get wrong. RSA is still secure with long enough keys and works almost everywhere, but some old RSA setups stop working against newer servers because an old signing method was retired. For new keys, ed25519 is the default choice; use RSA only for old systems that do not support ed25519.

What happens if I say yes to the host key prompt?

SSH saves the server's public host key in ~/.ssh/known_hosts. On every later connection it compares; if the server shows a different key, SSH refuses loudly with "REMOTE HOST IDENTIFICATION HAS CHANGED". That protects you from someone pretending to be the server, but only if the first answer was right, so compare the fingerprint with the one GitHub publishes. After a legitimate change, remove the old entry with ssh-keygen -R host.

Why did git push over HTTPS fail with my password?

GitHub stopped accepting account passwords for git in 2021. Over HTTPS you need a personal access token (a long generated password); over SSH you need a registered key. On a server, SSH is simplest: switch the remote with git remote set-url origin [email protected]:user/repo.git. The prompt tells you which one you are using: HTTPS asks for a username and password, SSH fails with Permission denied (publickey).

Should I set a passphrase on the key?

On a throwaway lab VM, an empty passphrase is a reasonable trade-off. On a laptop or any machine holding keys to real systems, yes: a passphrase encrypts the private key file, so a stolen disk or copied file does not give away access. A helper called ssh-agent (or the Mac keychain) can hold the unlocked key in memory so you type the passphrase once per session instead of on every push.

Why doesn't git track my empty directories?

Git records files and their paths, not directories on their own. A directory appears in a commit only because some file lives inside it, so an empty directory is never committed. The convention is a placeholder file, usually called .gitkeep - a name with no special meaning to git. In this chapter's mission you add one to every empty lab directory with find ... -empty -exec touch {}/.gitkeep \;.

In an interview Junior

How does SSH key authentication work, and which key goes where?

You make a key pair with ssh-keygen -t ed25519: a private key (~/.ssh/id_ed25519, mode 600, never leaves the machine) and a public key (id_ed25519.pub, safe to give anyone). The public key goes to the server - for GitHub, into your account's settings.

When you connect, the server sends a random challenge; your machine signs it with the private key, and the server checks the signature with the public key. No password travels, and the public key cannot be used to work out the private one.

It works the other way too: the server has a host key, so you can check you reached the real server. The first connection shows its fingerprint; once you say yes it is saved in ~/.ssh/known_hosts, and a different key later gives a loud warning. ssh -T [email protected] tests the whole chain.

Also asked: What is a host key fingerprint, and why compare it before typing yes? · How do you see which remote URL a git repository pushes to? · What does git config --global user.email set, and where is it stored?

Practise this lesson in the terminal Free, in your browser - a real Ubuntu terminal to try it in, with missions that check your work.