2

I've followed Scott Hanselman's instructions found this blog post to setup an open-ssh server

in summary I've done the following:

# in WSL2 - install openssh-server
sudo apt install openssh-server

in WSL2 - check ssh version

ssh -V # -> OpenSSH_8.2p1 Ubuntu-4ubuntu0.4, OpenSSL 1.1.1f 31 Mar 2020

in WSL2 - generate new host keys

ssh-keygen -t ras -b 4096 -f /etc/ssh/ssh_host_rsa_key ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key

The private keys have permissions set to 600, and the public keys are 644

My sshd_config for your reference

#   $OpenBSD: sshd_config,v 1.103 2018/04/09 20:41:22 tj Exp $

This is the sshd server system-wide configuration file. See

sshd_config(5) for more information.

This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin

The strategy used for options in the default sshd_config shipped with

OpenSSH is to specify options with their default value where

possible, but leave them commented. Uncommented options override the

default value.

Include /etc/ssh/sshd_config.d/*.conf

Port 2222 #AddressFamily any ListenAddress 0.0.0.0 #ListenAddress ::

#HostKey /etc/ssh/ssh_host_rsa_key #HostKey /etc/ssh/ssh_host_ecdsa_key #HostKey /etc/ssh/ssh_host_ed25519_key

Ciphers and keying

#RekeyLimit default none

Logging

#SyslogFacility AUTH #LogLevel INFO

Authentication:

#LoginGraceTime 2m #PermitRootLogin prohibit-password #StrictModes yes #MaxAuthTries 6 #MaxSessions 10

#PubkeyAuthentication yes

Expect .ssh/authorized_keys2 to be disregarded by default in future.

@amin: Removed second one AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2

AuthorizedKeysFile .ssh/authorized_keys

#AuthorizedPrincipalsFile none

#AuthorizedKeysCommand none #AuthorizedKeysCommandUser nobody

For this to work you will also need host keys in /etc/ssh/ssh_known_hosts

#HostbasedAuthentication no

Change to yes if you don't trust ~/.ssh/known_hosts for

HostbasedAuthentication

#IgnoreUserKnownHosts no

Don't read the user's ~/.rhosts and ~/.shosts files

#IgnoreRhosts yes

To disable tunneled clear text passwords, change to no here!

PasswordAuthentication no #PermitEmptyPasswords no

Change to yes to enable challenge-response passwords (beware issues with

some PAM modules and threads)

ChallengeResponseAuthentication no

Kerberos options

#KerberosAuthentication no #KerberosOrLocalPasswd yes #KerberosTicketCleanup yes #KerberosGetAFSToken no

GSSAPI options

#GSSAPIAuthentication no #GSSAPICleanupCredentials yes #GSSAPIStrictAcceptorCheck yes #GSSAPIKeyExchange no

Set this to 'yes' to enable PAM authentication, account processing,

and session processing. If this is enabled, PAM authentication will

be allowed through the ChallengeResponseAuthentication and

PasswordAuthentication. Depending on your PAM configuration,

PAM authentication via ChallengeResponseAuthentication may bypass

the setting of "PermitRootLogin without-password".

If you just want the PAM account and session checks to run without

PAM authentication, then enable this but set PasswordAuthentication

and ChallengeResponseAuthentication to 'no'.

UsePAM yes

#AllowAgentForwarding yes #AllowTcpForwarding yes #GatewayPorts no X11Forwarding yes #X11DisplayOffset 10 #X11UseLocalhost yes #PermitTTY yes PrintMotd no #PrintLastLog yes #TCPKeepAlive yes #PermitUserEnvironment no #Compression delayed #ClientAliveInterval 0 #ClientAliveCountMax 3 #UseDNS no #PidFile /var/run/sshd.pid #MaxStartups 10:30:100 #PermitTunnel no #ChrootDirectory none #VersionAddendum none

no default banner path

#Banner none

Allow client to pass locale environment variables

AcceptEnv LANG LC_*

override default of no subsystems

Subsystem sftp /usr/lib/openssh/sftp-server

Example of overriding settings on a per-user basis

#Match User anoncvs

X11Forwarding no

AllowTcpForwarding no

PermitTTY no

ForceCommand cvs server

On WSL2 we don't have systemd so I start SSH with service ssh start

Now if I open up Powershell and ssh into my WSL2 using ssh -p 2222 myuser@wsl2ip I face no problems logging in with my password.

Next I copy over my windows public key from Win into WSL2 by running

type $env:USERPROFILE\.ssh\id_rsa.pub | ssh -p 2222 myUser@wsl2 "cat >> .ssh/authorized_keys"

and the contents there look like

ssh-rsa AAAAB3N************O1s= myWinUser@DESKTOP-AE*****

and the permissions in my WSL2 ~/.ssh look like

-rw------- 1   575 Jan 17 14:32 authorized_keys
-rw------- 1    97 Aug 30 11:17 config
-r-------- 1   411 Dec  2  2020 id_ed25519
-rw------- 1   100 Dec  2  2020 id_ed25519.pub
-rw------- 1  3389 Jan 17  2021 id_rsa
-rw-r--r-- 1   749 Jan 17  2021 id_rsa.pub
-rw-r--r-- 1  4866 Oct  7 16:19 known_hosts

, and turn off PasswordAuthentication by setting it to no in WSL2's sshd_config

Anytime I try to login with my ssh key I get

myuser@wsl2ip: Permission denied (publickey)

The same thing happens if I repeat the same process with RSA, RSA4096, or ED25519 keys.

What gives?

vvMINOvv
  • 133

1 Answers1

5

A few thoughts:

  • First, the most likely reason for it failing is as Ramhound mentioned in the comments -- Key permissions. You just mentioned copying over the private key from Windows to ~/.ssh/authorized_keys, but you didn't mention changing the permissions. Try:

    chmod 600 ~/.ssh/authorized_keys
    
  • Hopefully, that will work, but if it doesn't, try:

    sudo service ssh stop
    sudo mkdir /run/sshd
    sudo chmod 0755 /run/sshd
    sudo /usr/sbin/sshd -d
    

    That will run sshd in the foreground with additional debugging. Hopefully that will tell you why the key is being denied.


Preferred Method of Enabling SSH into WSL2

The page you linked to in your question is the one that says:

DO NOT DO THE INSTRUCTIONS IN THIS POST until you have read the FOLLOW UP THE EASY WAY how to SSH into Bash and WSL2 on Windows 10 from an external machine and made the right decision for YOU!

So I'd be curious why you selected the older, port-forwarding method over the alternative that he proposes for setting the Windows OpenSSH shell to the bash.exe (outdated info, but still works) command.

Regardless, I (and others) feel there's a much better alternative to either of Hanselman's techniques.

Advantages of this method:

  • No port forwarding required
  • Minimal firewall work needed since it relies on Windows services
  • Works even if you have multiple WSL distributions installed
  • Works with sshfs, scp, sftp, Ansible, and any app or service that requires a real SSH connection.

The summary is that:

  • We rely on WSL2's ability to forward "localhost" connections on Windows to WSL (a.k.a. localhost forwarding).
  • We use Windows OpenSSH server as a JumpHost to the WSL2 OpenSSH server.

The initial setup for this is the same as for Hanselman's "easy method". Start by enabling the Windows OpenSSH server on port 22.

  • (Especially for future readers) I recommend simply following the Microsoft docs for the latest information, but I'm copying the relevant commands in here as well. From PowerShell:

    # Sounds like you had the Client already installed, at least
    Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0 
    Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
    

    Start-Service sshd Set-Service -Name sshd -StartupType 'Automatic'

    Confirm the Firewall rule is configured. It should be created automatically by setup. Run the following to verify

    if (!(Get-NetFirewallRule -Name "OpenSSH-Server-In-TCP" -ErrorAction SilentlyContinue | Select-Object Name, Enabled)) { Write-Output "Firewall Rule 'OpenSSH-Server-In-TCP' does not exist, creating it..." New-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22 } else { Write-Output "Firewall rule 'OpenSSH-Server-In-TCP' has been created and exists." }

  • Recommended if you are an Administrator on your Windows install -- Edit C:\Program Data\ssh\sshd_config and comment out the following lines:

    #Match Group administrators
    #       AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys
    
  • While you are editing that, I assume you will want to set:

    PasswordAuthentication no
    
  • By default, Windows OpenSSH looks for C:\Program Data\ssh\administrators_authorized_keys (see this question). By commenting these lines out, you will use your %userprofile%\.ssh\authorized_keys instead.

  • Add your public key to %userprofile%\.ssh\authorized_keys. Make sure that permissions are restrictive per this answer (or related answers).

  • Confirm that you can log to Windows OpenSSH from WSL using your key:

    ssh -i <path_to_private_key> "${HOSTNAME}.local"
    

At this point, you really have terminal access to WSL2 through Windows OpenSSH already.

From any machine on the network:

ssh -t <windows_host_or_ip> wsl

This will simply run the wsl command after the connection to Windows.

That works for shell access, but if you need "real" ssh access to WSL for Andible, sshfs, sftp, scp, etc., then read on ...

Next (for anyone else reading this) configure OpenSSH in WSL. You've done this part already. And port 2222 is a good option.

Copy over your public key to ~/.ssh/authorized_keys (already done for you) and make sure your permissions are correct (as mentioned above).

If you haven't already, add your private key to ssh-agent via:

eval $(ssh-agent) # under Linux
ssh-add <path_to_key

(Note: Windows also supports ssh-add. Just make sure the "OpenSSH Authentication Service" is running).

At this point, you can use the Windows host as your JumpHost like so:

ssh -J <windows_host_or_ip> -p 2222 localhost

This connects to the Windows OpenSSH server (on port 22) which then turns around and connects to localhost:2222, which is your WSL2 instance.

As mentioned, this will now work for scp, sshfs, etc.


Optionally:

This technique has one "side-effect", in that localhost is stored as the same "known host" regardless of which port or jump host you use to connect. So if you do connect to multiple WSL instances in this way, ssh will start complaining about potential man-in-the-middle issues.

The best way to avoid this (and simplify things in general) is to create a Host entry in ~/.ssh/config. Let's say your Windows host name is bubblegum and your WSL distro is ubuntu. Add the following to ~/.ssh/config:

Host bubblegum_ubuntu  # Can be whatever you want
Hostname localhost
User <username> # If needed
Port 2222
ProxyJump bubblegum
UserKnownHostsFile ~/.ssh/known_hosts_bubblegum_ubuntu

That will redirect the known_host entry to a file that is only used for that particular host.

It also means that you can now:

ssh bubblegum_ubuntu
scp bubblegum_ubuntu:/home/username/filename .
sftp bubblegum_ubuntu
sshfs bubblegum_ubuntu:/ /mountpoint
NotTheDr01ds
  • 28,025