Secure Shell is a command line login service typically used for command line programs communicating with remote servers such as. A common use case is git communicating with GitHub. It is an alternative to using HTTPS. Rather than saving a basic password to windows credential manager, you instead save a private-key and public-key text file to the ~\.ssh directory(i.e. the C:\Users\<username>\.ssh directory).

The public key; you copy-paste onto the server website via the browser. The private-key, is used by the ssh-agent program, almost always OpenSSH, to gain access to the server. This system is more secure than HTTPS as it does not require user input to enter a password and the pre-generated password is mathematically un-crackable.

But unlike HTTPS, an SSH key pair is only used for authentication during the initial handshake, not to encrypt and decrypt incoming and outgoing data. OpenSSH is integrated into Windows, Mac and Linux.

Everyone is familiar with HTTP URLs such as:

  • https://github.com/user/repo.git
  • in the format: <protocol>://<nth-level-domain>….<2nd-level-domain>.<top-level-domain>/<file_path or query or fragment>,

But, SSH URLs are simpler and less flexible. They only find a use in the command line. They can also only include a file-path, not queries and fragments, like in HTTP URLs. This is the sort of SSH URL you will need to add to a git repository:

  • git@github.com:user/repo.git
  • in the format <User>@<Host>/<file_path>

Unfortunately, knowledge of SSH is assumed and it is generally poorly explained.

Getting SSH on Windows

OpenSSH is an ‘optional feature’ in Windows 10. Check there is a path assigned in Powershell with the command: (gcm ssh).path. It should be in: C:\WINDOWS\System32\OpenSSH.

Under this folder, in addition to ssh.exe, there should also be :

  • scp.exe - remote copy over port 22 - faster but cannot pause and resume.
  • sftp.exe - remote copy, view, create, and delete over port 22 -equal security
  • ssh-add.exe and ssh-agent.exe - holds keys ready for use.
  • ssh-keygen.exe- generates the private and public keys used in SSH.
  • ssh-keyscan.exe - scans a list of hosts from the config file and collects the public keys.

If you don’t have these OpenSSH programs aleady, search Manage optional features from the start menu and make sure you have Open SSH Client in the list. If not, you should be able to add it.

Automatic ssh-agent activation

Git windows installation also installs start-ssh-agent.cmd and start-ssh-pageant.cmd following to C:\Program Files\Git\cmd. Git should use these to start the ssh-agent each time a git remote command is called.

I use MinGit, and it doesn’t add the SSH agent necissarily.

But if SSH is not working with git:

  • search Services from the start Menu Scroll down to OpenSSH Authentication Agent > right click > properties. Change the Startup type from Disabled to any of the other 3 options. I have mine set to Automatic (Delayed Start).
  • Or, use in PowerShell, opened as Administrator: Get-Service ssh-agent | Set-Service -StartupType Automatic

In bash use ; https://stackoverflow.com/questions/18880024/start-ssh-agent-on-login https://unix.stackexchange.com/questions/322124/ssh-add-add-all-private-keys-in-ssh-directory

Installing in WSL

I find it is simpler to make a host of new keys when you login to WSL rather than figure out a way to reference the ones in your windows mount.

Using SSH with GitHub

Unlike logging in with HTTPS, which is self explanatory, for SSH to work with a GitHub account, you need:

  • SSH private key files saved in ~\.ssh and registered with ssh-add.
  • SSH public keys (….pub extension) text registered on your GitHub account.
  • SSH Host, Hostname, User and IdentityFile parameters added to your ~\.ssh\conf file
  • SSH address added as the remote location to your local GitHub repo in the format: User@Host:GitHubUserName/repo
  • Your user.name and user.email configured in git.

And there are lots or errors which can mess things up.

Delete all existing GitHub HTTPS credentials in windows credential manager:

  • Type credential into start (Control Panel\All Control Panel Items\Credential Manager),
  • Find git:http://github.com. These are the HTTPS keys. Delete them.

Delete existing SSH keys from the OpenSSH register:

ssh-add -d

Make a new key with OpenSSH called for example name_key and saved in the ~\.ssh directory. On the next line you should name the key for future reference, using. You have to enter full file path using / file separators: e.g.: .ssh/name_key.. You will reference this file later in the ~\.ssh\config file.

Note: Whatever people say, / has been a valid file separator on Windows PowerShell since about 2008, so mix and match all you like.

Note: the email is not important. Also, you must explicity write ‘yes’ or ‘y’ at each stage to progress. -t RSA is the least secure -t DSA -t ECSDA -t ed25519 is the most secure option

ssh-keygen -t ed25519 -f $HOME/.ssh/id_name -C "youremail@whatever.com" 

Add the private key (the one without the .pub file extension) to OpenSSH:

ssh-add $HOME/.ssh/id_name

Check the key is registered in OpenSSH:

ssh-add -l

Add the text in the .ssh/name_key.pub file to your GitHub account.

Create, or open a text file called config in the .ssh directory and enter the details for the given account.

  • Host: your custom handle for the service. If you have only 1 account, you can make it the same as HostName
  • HostName: The IP address or HTTP URL of the server in question.
  • IdentityFile: The path to the private key which you just generated.
  • IdentitiesOnly: When you have uniquely named Host for each account on the same service, you can add the IdentitiesOnly yes command which tells the ssh-agent will only try sending the private key corresponding to that particular Host.

I recommend naming the Host yourself. This custom Host name is what you will need to write into the git remote repo URL. It is possible to leave the default, but it can become confusing if you have multiple accounts with the Host called github.com. I prefer to name the host explicitly. That way you can also test access to each host individually with ssh -T git@<Host>, and you can drill down to the culprit. For example:

Host name_it
  User git
  HostName github.com
  IdentityFile C:\Users\Seb\.ssh\name_key
  IdentitiesOnly yes

Check your access is successful 🤞:

ssh -T git@name_it

Another way to test individual keys is to use the ssh command with the -i flag. This way you don’t even need a config file. But you must still check that the the response comes back with the right username i.e. Hi sebanalysis..., as although it tries that key first, if tries all the others too!

ssh -i $HOME/.ssh/id_sebanalysis -T git@github.com

Sometimes, in existing repos, you don’t need to have a different host name. But if you leave the IdentitiesOnly yes flag, you need to have separate host names, as for a given session, the first key it sees in the conf file, it will lock to that account exclusively.

Because you have changed the host from the default github.com to name_it, you will have to modify the default SSH address for the repo on the website as below. Clone with the repo using the format <User>@<Host>:<GitHubUserName>/<repo>:

git clone git@name_it/someuser/somerepo.git

Or change the address of an existing repo from HTTPS to SSH by first removing the existing URL, and then adding the new SSH URL:

git remote remove origin
git remote add origin git@name_it/someuser/somerepo.git

Check you have successfully added the new SSH URL:

git remote -v

If you have multiple accounts, you have to add the the git username and git email which you want to use for that repo. These are the names which appear on the git commits, both local and on GitHub. It is unrelated to SSH, but can be confusing and make you think that you’re connected to that repo via the wrong SSH details. Navigate to the repo and run:

git config user.name yourname
git config user.email youremail@whatever.com

The values will then be stored in in the .git/config for that repo rather than your global configuration file.

You are finally done!

Common issues:

  1. Check the correct SSH URL is attached to the repo. Importantly, that it is not an HTTPS URL.
  2. The previously saved HTTPS keys are being used when they shouldn’t. Delete all existing credentials in windows credential manager
  3. Check SSH program is active.

n Windows PowerShell (run as admin):

  1. Check the current status of ssh-agent:

    Get-Service | ?{$_.Name -like '*ssh-agent*'} | select -Property Name, StartType, Status

  2. Enable the Service if it is disabled:

    Set-Service -Name ssh-agent -StartupType Manual

  3. Start the Service:

    Start-Service ssh-agent

  4. Add your key as before:

    ssh-add <path to the key>

Using SSH in Powershell on Linux

Powershell 7 can be used on linux. A Linux BASH shell profile contains the line: eval “$(ssh-agent -s)”, which assigns two environment variables: ‘SSH_AGENT_PID’ and ‘SSH_AUTH_SOCK’.

In Powershell on linux, there is no eval command. The Invoke-Expression command replicates the functionality but environment variables are written and set differently. Instead they must be set as: $env:variable=’value’. Therefore the string returned by ssh-agent cannot be executed directly by Powershell. The following script captures the process ID’s and sets the relevant environment variables. Add it to your PowerShell profile.

# Start the ssh-agent daemon.

ssh-agent -s > ssh-env.txt

# Read the environment variables from the ssh-env.txt file into an array

$sshEnv = Get-Content ssh-env.txt

# Split the Array and set the environment variables

$env:SSH_AUTH_SOCK = $sshEnv[0].Split(';')[0].Split('=')[1]

$env:SSH_AGENT_PID = $sshEnv[1].Split(';')[0].Split('=')[1]

# Remove the ssh-env.txt file

Remove-Item ssh-env.txt

Errors

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:lsjfl;sdjl;jf;lsdjfl;dsjlfj.
Please contact your system administrator.
Add correct host key in C:\\Users\\seb/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in C:\\Users\\seb/.ssh/known_hosts:6
ECDSA host key for 172.18.6.4 has changed and you have requested strict checking.
Host key verification failed.

GO in to the .ssh/known_hosts file and delete the line with the IP address referenced

Even when yoy have different host names , it still wont connect with the right key

In this case, the only way is to remove all the keys fromm ssh-add:

ssh-add -D

Then re-add the one(s) you need, making sure each is a different hostname.