Using OpenSSH Server on Windows

In the past whenever I had to manage a Windows Server, I used RDP (Remote Desktop Protocol) to connect to the server and manually click around to change the necessary settings.

Blank screen with the PowerShell logo in the middle

While working with Ansible to setup a Windows build agent, I realized that starting with Windows 10, Windows does ship with support for OpenSSH as an optional feature. This means, you can SSH into the server, instead of using RDP, and with the right PowerShell scripts set everything up the way you need it to be. That‘s also the way Ansible works; all it needs is an active SSH connection.

To enable OpenSSH there are few things to keep in mind though, as such I decided to write them down.

Manual Steps

First lets look at the manual steps needed to apply all the changes and then later automate everything with a PowerShell script.

Install OpenSSH

  • Search in the start menu for “Add an optional feature” (Windows 11: “Add optional feature”)
  • (Windows 11: Then “View” on “Add an optional feature”)
  • Usually “OpenSSH Client” is already installed, if not, you may want to install it, so you could also use the server as a jump host
  • Click on “Add” and install “OpenSSH Server”
  • Open the “Services” application and set “Start up” for the services “OpenSSH Server” and “OpenSSH Agent” to “Automatic”

Setup Key Authentication

While you could stick to password logins, it’s considered best practice to use private/public key authentication. That way not everyone in the domain can login and no passwords can be brute forced.

Note: If your server is in a domain and you want to use a user of that domain, make sure you’re generating the key with your domain user.

Read the Key-based authentication guide for more details on how to generate keys, here is the basic command for it:

ssh-keygen -t ed25519

This generate a private key (id_ed25519), which you should never give out and a public key (id_ed25519.pub). The public key needs to be stored on the server, as to inform the SSH service that this is an authorized user/key.

Note: If you plan to automate installations you’ll most likely be using an administrative account, which are managed slightly different. The following steps will assume the use of an administrative account and point out difference for a non-administrative account. See also the last paragraph of the Configure SSHd section.

  • Insert the public key on a new line in C:\ProgramData\ssh\administrators_authorized_keys
    • For non-admin accounts the location is: $env:USERPROFILE\.ssh\authorized_keys
  • Ensure the permission of the administrators_authorized_keys is set correctly:

Configure SSHd

Three configuration changes for the SSH server that you may want to consider:

  • Disable password authentication by adding the line PasswordAuthentication no to the C:\ProgramData\ssh\sshd_config
  • Enable key authentication by adding the line PubkeyAuthentication to the C:\ProgramData\ssh\sshd_config
  • Enable PowerShell as default OpenSSH shell by setting the string value of the registry key Computer\HKEY_LOCAL_MACHINE\SOFTWARE\OpenSSH\DefaultShell to C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe

In case you don’t want to manage administrative accounts globally, you can remove the two lines at the end of the C:\ProgramData\ssh\sshd_config file:

Match Group administrators
        AuthrorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys

Don’t forget to restart the sshd service!

Automated

It’s good to know how to do it manually, but if you have to do it more than once, you’ll of course want a PowerShell script, so here it is!

# Install OpenSSH client & server
Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'
Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'

# Configure OpenSSH service
Start-Service sshd
Set-Service -Name sshd -StartupType 'Automatic'

# Enable access for technical user
$authorizedKey = '<insert pub key>'
Add-Content -Force -Path "$env:ProgramData\ssh\administrators_authorized_keys" -Value $authorizedKey
icacls.exe "$env:ProgramData\ssh\administrators_authorized_keys" /inheritance:r /grant "Administrators:F" /grant "SYSTEM:F"
(Get-Content "$env:ProgramData\ssh\sshd_config").Replace('#PubkeyAuthentication yes', 'PubkeyAuthentication yes') | Set-Content "$env:ProgramData\ssh\sshd_config"
(Get-Content "$env:ProgramData\ssh\sshd_config").Replace('#PasswordAuthentication yes', 'PasswordAuthentication no') | Set-Content "$env:ProgramData\ssh\sshd_config"

# Use PowerShell as default OpenSSH shell
New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -PropertyType String -Force

# Apply changes
Restart-Service sshd

Resources

Leave a Comment

Your email address will not be published. Required fields are marked *

 

This site uses Akismet to reduce spam. Learn how your comment data is processed.