34 views
 owned this note
[TOC] # SSH Authentication for Git This is one of those tasks that **everyone does it once and then forgets about**. This also means that you likely do not remember what the exact sequence of commands are or even what their purpose was. Below, I will go over the quick and dirty setup, the traditional setup, and delve into the purpose and pitfalls of each command. :::info TL;DR My recommendation is to instruct the learners to use the following commands ```bash ls -la ~/.ssh # check for any keys ssh-keygen -t ed25519 -C "email@addr.ess" # generate a new key associated with email@addr.ess cat ~/.ssh/id_ed25519.pub # show and copy the public key ``` These generate the key the learners can copy/paste to GitHub. Instruct them to use a _memorable_ passphrase that they feel comfortable typing several times. This is the second lowest tier for connecting to GitHub via the command line and it is as secure as the user's own machine. Tier 1 : SSH Key (no passphrase) Tier 2 : SSH Key + passphrase Tier 3 : SSH Key + passphrase + SSH agent ::: ## What is SSH? SSH means "Secure Shell" and it's one of those acronyms that's really confusing because it's _not_ an acronym -_- SSH is a method of authentication that allows two computers to transmit messages and information securely. To do this, you can generate a "keypair", which is a pair of files on your computer called the "private key" and a "public key". [One way to think about these files is as a key and a padlock](http://blakesmith.me/2010/02/08/understanding-public-key-private-key-concepts.html). The private key represents, well, a key. It should be private to you and no one elese should be able to access it. The public key is a padlock that the private key opens. This can be duplicated many times and given to services that you want to access without using your password. In this model, you can give your public key to both GitHub and GitLab and use the same private key to access your repositories on those accounts even though they have different passwords. The security of the method comes from the fact that the private key is kept private on your computer, so unlike a password, no one can look over your shoulder and gain access to your information. ## Test your SSH setup ``` ssh -T git@github.com ``` If your key is set up and ready to go, you'll see this: :::success ``` Hi <USER>! You've successfully authenticated, but GitHub does not provide shell access. Connection to github.com closed. ``` ::: If it is not set up, you'll see this: ::: danger ``` git@github.com: Permission denied (publickey). ``` :::: ## Quick and dirty SSH setup At the _very least_ these are the commands to get someone up and running with using ssh on their machines. This _should_ work across systems. ```bash ssh-keygen -t ed25519 -C "your_email@example.com" # - Hit <ENTER> _three_ times. # - open ~/.ssh/id_ed25519.pub, # copy the contents, # and paste it in https://github.com/settings/ssh/new ``` This will give you a new ssh key that you can test with `ssh -T git@github.com`. ### Pros This significantly reduces the cognitive load and, by not having a password for the key, ensures that the process for pushing and pulling is seamless. ::: info If the learner sets a password, they will have to type it every pull and push. The good thing is that because the password is only associated with one file on the computer, it _does not have to be complex._ If the password is compromised, it would be relatively useless unless the attacker has access to the user's computer. ::: ### Cons **This is only as secure as the user's own machine.** If there are other users on the same machine, then it's possible for them to use the SSH key to gain access to their accounts. The reason for this is that, by default, the private key is written with `-rw-r--r--` permissions, which means anyone can read it. A fix for this would be to prevent any other user from reading it by setting `chmod -R 600 ~/.ssh`, but that adds to the cognitive load and can have disasterous consequences if done improperly (see the [chmod cheat sheet](https://gist.github.com/juanarbol/c44e736be70279c1fd5d68aa24f9d8be)). ## Traditional SSH setup ```bash ssh-keygen -t ed25519 -C "your_email@example.com" # - Hit <ENTER> _once_ # - Choose and enter a password # - Enter the password again eval "$(ssh-agent -s)" ssh-add ~/.ssh/id_ed25519 # - open ~/.ssh/id_ed25519.pub, # copy the contents, # and paste it in https://github.com/settings/ssh/new ``` ### Pros This method is the most commonly referred and provides the most direct form of security. ### Cons - The number of commands has increased - The number of concepts has _also_ increased - `eval` - command substitution `$()` - background processes - macOS [has a lot of caveats for adding a keypair to the ssh-agent](https://docs.github.com/en/github/authenticating-to-github/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent#adding-your-ssh-key-to-the-ssh-agent) - Git Bash for Windows [will not automatically start ssh-agent](https://docs.github.com/en/github/authenticating-to-github/connecting-to-github-with-ssh/working-with-ssh-key-passphrases), which will lead to these users needing to type their password every time they pull or push if they don't start ssh-agent when the open Git Bash. ## Changing an SSH key passphrase The passphrase for an SSH key is a lot like a passphrase for a protected PDF---it is only associated with that file and it does not have to be complex. If you use the quick and dirty method, then you will have no passphrase, but if you want to add extra security, adding a passphrase is a good idea. To add a new passphrase you can use the following command: ```bash ssh-keygen -p -f ~/.ssh/id_ed25519 ``` ::: info In this command, `-p` means "change passphrase" and `-f ~/.ssh/id_ed25519` is the file associated with the passphrase. ::: The command will ask for the old passphrase and then the new passphrase twice. ## Steps ### `ssh-keygen -t <algorithm> -C <email/comment>` This command is the one that's _absolutely necessary_ as it generates the keypair. It goes through three prompts (everything with a colon at the end): ``` Generating public/private ed25519 key pair. Enter file in which to save the key (~/.ssh/id_ed25519): Enter passphrase (empty for no passphrase): Enter same passphrase again: ``` These prompts, translated: 1. Where should the keypair be stored **(use default)** 2. What's your password **(default: no password)** 3. What's your password again? #### Final output ``` Your identification has been saved in ~/.ssh/id_ed25519 Your public key has been saved in ~/.ssh/id_ed25519.pub The key fingerprint is: SSH256:<RANDOMSTUFF> your_email@example.com The key's randomart image is: +---[RSA 3072]----+ | | | ^_^ | | | +---[SHA 256]-----+ ``` This creates _two files_: 1. Your private key (~/.ssh/id_ed25519), **(keep secret)** 2. Your public key (~/.ssh/id_ed25519.pub) **(share with the world)** As I've demonstrated in the quick and dirty demonstration of the setup, this is the only command you really need if you are comfortable typing your passphrase any time or are comfortable not having a passphrase at all. However, for an extra layer of secruity, you can use the ssh-agent. ### `eval "$(ssh-agent -s)"` This command starts the SSH agent, which is a program that runs in the background and keeps track of your SSH keys for you so that you don't always have to type your passphrase. There are three things going on here, which I will explain: #### 1. `ssh-agent -s` This command starts an ssh agent process in the background. The output of this command looks something like this: ```bash SSH_AUTH_SOCK=/tmp/ssh-77EMLIN9ahKo/agent.41327; export SSH_AUTH_SOCK; SSH_AGENT_PID=41328; export SSH_AGENT_PID; echo Agent pid 41328; ``` These are BASH environment variables that sets up communication channels between your current shell session and the agent. `SSH_AUTH_SOCK` is a communication channel between your computer and the agent while `SSH_AGENT_PID` is the process ID of the agent itself. #### 2. `$()` This is known as command substitution, where `()` runs the command in a separate process and `$` creates a temporary variable. #### 3. `eval` Because we have the environment variables from the ssh-agent command in a temporary variable, we can use `eval` to evaluate these variables in our current session. This is effectively telling our agent that it's okay to talk to the computer through this one specific channel when an SSH request is made. ### `ssh-add <key>` This command adds an SSH key to your agent so that it knows to make sure the key is always avaialable for SSH requests. ## Conclusion The SSH steps are built iteratively and it's perfectly valid to use the `ssh-keygen` function by itself to generate the key. Extra steps that can be taken at any time are for security (passphrase) and convenience/extra security (ssh-agent). The SSH setup can be completed in two steps as long as you can reasonably assume that your learners have sole access to their computers. 1. generate your key (private key) and lock (public key) 2. copy the lock and give it to GitHub This aligns with our principles of "teach the most useful thing first" AND "always learning" because we will encourage the learners to take the extra steps to making the process more automated and secure. You can use the other two steps as well because this is the standard method for generating keypairs and is more secure. It _has_ been done before, but there are more chances for error: https://github.com/swcarpentry/git-novice/issues/778#issuecomment-828867435 ## Special Note for Instructors To make sure your environment best mirrors the environment of the learner who has never authenticated to GitHub before, you should temporarily move your `~/.ssh/known_hosts` to `~/known_hosts`. ```bash ssh -T git@github.com # Hi zkamvar! You've successfully authenticated, but GitHub does not provide shell access. mv ~/.ssh/known_hosts ~/known_hosts ssh -T git@github.com # The authenticity of host 'github.com (140.82.114.3)' can't be established. # RSA key fingerprint is SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8. # Are you sure you want to continue connecting (yes/no/[fingerprint])? yes # Warning: Permanently added 'github.com,140.82.114.3' (RSA) to the list of known hosts. # Hi zkamvar! You've successfully authenticated, but GitHub does not provide shell access. mv ~/known_hosts ~/.ssh/known_hosts ssh -T git@github.com # Hi zkamvar! You've successfully authenticated, but GitHub does not provide shell access. ```