Insights Key-based Authentication for OpenSSH on Windows

Key-based Authentication for OpenSSH on Windows

This is a follow up to a previous post: Getting Started with SSH on Windows Server 2019.  If you haven’t yet installed and configured SSH, start by reading that first.

Key-Based Authentication Overview

The previous post leaves off with SSH enabled and working with username and password authentication.  If you want to enable key-based auth instead, you have to go through some additional steps to generate the keys and place them in the correct locations.  If you are familiar with key-based auth for SSH to Linux servers, this process is very similar.

In case you aren’t already familiar with key-based authentication, it is a way of authenticating to remote servers without using a password.  Instead, a private key stored on the client is paired with a public key stored on the server.  When the client attempts to connect, the client and server communicate to ensure the private key that the client has matches an allowed public key on the server side.  Since the private key is considerably more complex than a password, this offers greater security over basic username/password authentication.

Configuring the Client and Generating a Key Pair

The first step to using key-based authentication is to generate a key pair – a set of matching public and private keys.  The OpenSSH client capability in Windows includes the tools required to do so.  Follow this process using PowerShell from the client computer you will be connecting from

First, if not already installed, install the OpenSSH client.  This will need to be done with a PowerShell window run as AdministratorAdd-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0

Next, switch to a regular (non-admin) PowerShell session and use the ssh-keygen command to generate a new key pair.  When prompted, you can press enter to accept the defaults, or enter a custom path and name for the key files.  You can also protect the private key with a passphrase.  If you choose to use a passphrase, you’ll be prompted to enter it to decode the private key every time you connect to the server with SSH.  This provides an additional layer of security.ssh-keygen

By default, the ssh-keygen command will create two files in the user’s .ssh folder: id_rsa and id_rsa.pub.  Id_rsa (without an extension) is the private key file, while id_rsa.pub contains the public key.

With the key created, next you must start the SSH Agent service which manages private keys locally and coordinates their usage in authentication.  Once the service is started, use the ssh-add component to add the new key into the local key store.Start-Service ssh-agent ssh-add <path to new private key file>

Configuring the Server

Finally, the public key of the key pair must manually be placed onto the server you will SSH to.  This is easiest to do via copy/paste into a Remote Desktop session.  The public key should be named authorized_keys and copied into the .ssh folder inside the profile folder of the user you are setting up.  For example, c:\users\myuser\.ssh\authorized_keys.  Note, if the user is in the local Administrators group on the server, the key must be placed in a different path.  See the next section for more details.

  1. Open the public key file in Notepad.  If using default path, it is C:\Users\myuser\.ssh\id_rsa.pub
  2. Copy the contents of the file to clipboard.  Ensure you get the entire file.
  3. Connect to the server with Remote Desktop.
  4. Open Explorer and navigate to your profile folder on the server, such as C:\Users\myuser\
  5. Look for a .ssh folder.  If one doesn’t exist, create it.
    1. Note, Windows Explorer won’t let you create the folder with the name “.ssh”.  Instead, use “.ssh.” with an extra dot at the end.  The extra dot will be removed, and you’ll have a folder correctly named .ssh
  6. In the .ssh folder, create a new text document named “authorized_keys” and open it with Notepad.  If the file already exists, just open it.
    1. Note, this file has no extension.  You may need to make file extensions visible to ensure you remove the .txt extension
  7. In Notepad, paste the key you copied earlier and save the file.  If there was already a key in this file, paste your key onto a new line below the existing one.

With all the pieces in place, you should be able to SSH to the server with no password required.  If you configured a passphrase on your private key, you will have to enter that before you can connect.  The SSH Agent service will automatically attempt to use the private key you added to the key stored during the connection attempt.ssh username@domain@servername #For example, to connect to a server named cntsapp01 as adminuser on the contoso.com domain, use: ssh adminuser@contoso.com@cntsapp01

Here, I got connected to my remote server without being prompted for a password.  The hostname command verifies that my PowerShell window is connected to it via SSH.

Admin Users

If the user account on the server you are connecting to is in the local Administrators group, the public key must be placed in the C:\ProgramData\ssh\administrators_authorized_keys instead of the user’s .ssh folder.  Additionally, only the Administrators group and SYSTEM account can have access to that file, for security purposes.  After copying your key into the file and saving it, you can use this script to set the correct permissions on it.  Here are the complete steps:

  1. Open the public key file in Notepad.  If using default path, it is C:\Users\myuser\.ssh\id_rsa.pub
  2. Copy the contents of the file to clipboard.  Ensure you get the entire file.
  3. Connect to the server with Remote Desktop.
  4. Open Notepad as administrator
  5. In Notepad, paste in the key you copied earlier
  6. Save the file as C:\ProgramData\ssh\administrators_authorized_keys with no extension.  You may need to make file extensions visible to ensure you can remove the .txt extension.
  7. Use the below PowerShell script to set the correct permissions on the file

$acl = Get-Acl C:\ProgramData\ssh\administrators_authorized_keys $acl.SetAccessRuleProtection($true, $false) $administratorsRule = New-Object system.security.accesscontrol.filesystemaccessrule(“Administrators”,”FullControl”,”Allow”) $systemRule = New-Object system.security.accesscontrol.filesystemaccessrule(“SYSTEM”,”FullControl”,”Allow”) $acl.SetAccessRule($administratorsRule) $acl.SetAccessRule($systemRule) $acl | Set-Acl

If you don’t do this, and instead only place the file in the .ssh folder for the user, you’ll either get prompted for your password (instead of using the key file), or your connection will fail with “Too many authentication attempts”.