OpenSSH for Windows
Setup procedure for using OpenSSH client/server on Windows.
Client
PowerShell | |
---|---|
Server
Key based authentication
https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh_keymanagement
Generate key for client
- "comment" = comment for user friendly listing via
ssh-add -l
and/or use with git (see below) - "filepath" = path to key file (eg. in powershell,
$env:USERPROFILE\.ssh\my-key
)
REMEMBER TO SET PASSPHRASE TO THE KEY FILE!!!
PowerShell | |
---|---|
Allow key on server
Manually
-
client side: copy the public key contents to clipboard (manually or via
type "c:\users\username\.ssh\my-key.pub" | clip
) -
server side: add public key to server's authorized keys by editing
C:\ProgramData\ssh\administrators_authorized_keys
and appending your public key - server side: grant permissions to
Administrators
group andSYSTEM
user for theadministrators_authorized_keys
file
Via script
Execute this script on the client, after adjusting the variables values.
SSH Agent setup
- setup the agent service to automatically start with Windows (see above); start the service
- add every key to the agent, one by one, via
ssh-add
; eg. in powershell:ssh-add $env:USERPROFILE\.ssh\my-key
(private keys don't have ".pub" extension) (passphrase will be required) - list added keys via:
ssh-add -l
Test connection
Test connection via ssh -T <ssh-host>
(replace "ssh-host" with your server's ip or URI).
If you wish you can add a welcome banner to the server so that you see a custom message every time you log onto it. Just edit the server's config (c:\ProgramData\ssh\sshd_config
on the server's filesystem) and add/uncomment the Banner
line specifying a path to a text file (eg. Banner c:\my_sshd_banner.txt
). Then restart the ssh server to apply the new setting, and test the connection again; you will see your banner upon connecting.
Github setup
Common setup
- !!! When installing git for windows, remember to select "Use external OpenSSH" !!!
- create keys for the client (see above)
- for authentication, create a key with comment containing "git-auth", eg. in powershell
ssh-keygen -C git-auth -f "$env:USERPROFILE\.ssh\git-auth"
- for signing, create a key with comment containing "git-signing", eg. in powershell
ssh-keygen -C git-signing -f "$env:USERPROFILE\.ssh\git-signing"
- add keys to your profile @ https://github.com/settings/keys (copy-paste both the public keys contents)
Authentication (cloning / pulling / pushing / etc)
Test auth via: ssh -T git@github.com
, it should print: "Hi username! You've successfully authenticated, but GitHub does not provide shell access.". If that's not the case and you get the error git@github.com: Permission denied (publickey).
, debug with the -v
or -vvv
switches ("verbose"): ssh -vvvT git@github.com
. See the Troubleshooting section for more help.
Now you should be able to clone a repository via: git clone git@github.com:violinminds/knowledgebass.git
(get link in the repository page on Github by clicking the "<> Code" button and and selecting "SSH" in the clone section).
Visual Studio config
Thanks to the global git settings, Visual Studio should be already working correctly.
Visual Studio Code config
To configure vscode to use SSH instead of HTTPS, add "github.gitProtocol": "ssh", "remoteHub.gitProtocol": "ssh"
to your settings.json file.
Commits signing
Configure git to always sign Github commits with your ssh key identified by the comment containing "git-signing" (run all commands in powershell):
OPTIONAL (not recommended): if you want, you can use a custom config file only for host "git@github.com":
git config --global "includeIf.hasconfig:remote.*.url:git@github.com**/**.path" .github.gitconfig
. If you do so, run the following commands replacing--global
with--file $env:USERPROFILE/.github.gitconfig
. PLEASE NOTE: if you do so, commits will be signed only after the "git@github.com" remote has been added, so initializing new repositories and immediately committing to them will create non-signed commits!
- instruct git to use ssh instead of gpg:
git config --global gpg.format ssh
- force signing of all commits:
git config --global commit.gpgsign true
- force signing of all tags:
git config --global tag.gpgsign true
- command to retrieve public key from agent:
git config --global gpg.ssh.defaultKeyCommand 'cmd /c "C:\\Windows\\System32\\OpenSSH\\ssh-add.exe" -L | findstr git-signing'
Now you can commit as usual, or by explicitly signing the commit via the -S
parameter (git commit -S -m "message"
); commits will always be signed by default.
Signature verification
You can (and should) verify whether your commits have been correctly signed or not.
On Github
Open the repository commits history (<repo url>/commits
, eg. https://github.com/aetonsi/pwsh__Utils/commits/). If a commit is signed correctly with your registered signing key, you will see a green "Verified" label for the commit:
Locally
Run: git log --show-signature
. You will see that the commits appear as unverified and you will get an error:
Just as Github knows a signature is valid by checking in its list of authorized keys, you also have to make a list of authorized keys for your local git installation. To do so, run the following commands (powershell):
PowerShell | |
---|---|
The file structure is simple: it simply contains a list of <email> <public key>
rows, each one representing an authorized user.
Then you can verify your commits' signatures again and you will get "Good git signature for ...":
Visual Studio config
Thanks to the global git settings (gpg.ssh.defaultKeyCommand
and core.sshCommand
in particular), Visual Studio should be already working correctly.
Visual Studio Code config
If you want to be sure to enforce commit signing in vscode, add "git.enableCommitSigning": true
to your settings.json file.
Enforce SSH transport protocol for git
To disallow any transport protocol except SSH (recommended for consistency), run:
PowerShell | |
---|---|
Please note: some platforms (eg. Heroku) allow access only via a single protocol (eg. HTTPS). For those repositories, you have to allow the protocol you need: git config protocol.https.allow always
. You will never be able to do a "clone" operation; instead, you will have to init an empty repository, run the aforementioned config command, add the remote, fetch, then checkout the branch you need with git checkout -b
. You could create a git alias to simply this procedure, for example (powershell):
Setup SSH Banner
Add/uncomment the Banner
line in C:\ProgramData\ssh\sshd_config
:
Troubleshooting tips
- verify that git is also loading the Github config file, by running
git config -l --show-origin
in a Github working copy - if you get the warning "@ WARNING: UNPROTECTED PRIVATE KEY FILE! @" when trying to use the keys, fix the private key(s) file(s) permissions to allow FULL CONTROL to the current user,
SYSTEM
and theAdministrators
group - if a repository was already cloned via HTTPS and you want to start working via SSH, change its remote via:
git remote set-url origin git@github.com:violinminds/knowledgebass.git
. To verify the current remotes, run:git remote -v
-
if you get an error, eg. "Permission denied (publickey). fatal: Could not read from remote repository.", to debug, you can add the
-v
switch tocore.sshCommand
setting in the git config to be more verbose (use-vvv
to be even more verbose) -
a possible problem might be that, for some reason, ssh is not using the agent's keys. In the verbose debug log, ssh reports a list of the keys it tries to use when connecting to an ssh host, which should also include the agent's keys. If the agent keys are missing, see the following Troubleshooting tips. Example of correct debug log:
- if by debugging with a verbose
core.sshCommand
or simply by trying the authentication withssh -vT git@github.com
you see that ssh is not trying the agent's keys, it might be that the agent service is not running. Start it viasc start ssh-agent
and try again - If the agent is running but the problem is still present, it might be that git is not using the system's OpenSSH suite. This might happen if you didn't select "Use external OpenSSH" during git setup. To verify this, you can either set
core.sshCommand
towhere.exe ssh > ~/sshlocation.txt && notepad ~/sshlocation.txt && rm ~/sshlocation.txt
then run a git command again (eg. git clone), or you can to runwhich ssh
in git Bash; both are ways to determine which ssh binary git is trying to run. If it's not the OpenSSH binary (located in C:/WINDOWS/System32/OpenSSH), fix yourPATH
environment variable. If git is using its internal ssh (C:\Program Files\Git\usr\bin), reinstall git for windows and select "Use external OpenSSH"