While working on a new web application recently I came across a a problem with quite an interesting solution. We have a Windows network of virtual machines that run applications which clients access via a web based control panel that generates an .rdp for them. Authentication is done via Active Directory using LDAP. The problem came when we started working on the accounts pages, how does a Linux web server tell a Windows domain controller that a user has changed their display name? The answer is to install an SSH server on the Windows machine for the Linux server to connect to and execute PowerShell commands, a very powerful combination of tools!

We’ll be referring to something called Cygwin a lot so it would be a good idea to understand what it actually is before installing it on your companies primary domain controller. Cygwin is essentially a collection of Linux-y tools for Windows, most importantly for us as the bash shell and SSH.

Test Network

We’ll be using a small Windows network in a virtual environment to demonstrate the setup, in total there are 5 machines shown here in VirtualBox.

VMs in the test network

I’ll briefly run through the purpose of each one, we won’t go in to the details of building a Windows network.

Router

A small Linux server configured as a router with two virtual network interfaces, one on the internal virtual network and one on the same LAN as my desktop. This keeps the Windows domain controllers isolated from the network while still allowing them access to the internet.

DC1

The primary domain controller which runs AD, DNS, DHCP and SSHd.

DC2

The secondary domain controller which runs; AD, DNS and SSHd.

Windows Desktop

A Windows desktop on the domain to use for testing.

Linux Desktop

A Linux desktop on the network but not a member of the domain. This will take the role of the web server in connecting to the domain controller via SSH.

Installing Cygwin

This should be done on all servers that you’ll want to connect to or from with SSH, probably all domain controllers and maybe your personal desktop. In our test network I’ll be doing this on DC1 and DC2.

First run the 64-bit installer from the Cygwin website. Something to note about the installer is that it’s also the package manager so if you want to add more Linux tools later you just have to run the installer again.

During the installation it will ask a few questions, the defaults are mostly fine for this stage although I changed the local package directory to C:\cygwin64_packages instead of the users home folder which seemed like a weird default.

Cygwin installer option to select package directory

The last step of the installer will ask you to select a mirror, this is the location that will be used for the packages, just pick one that sounds close to you – it doesn’t really matter.

You’ll then be presented with a gigantic page listing all of the available packages, we only want a few things so the search box is your best friend here.

First search for ssh and select the most recent versions of _libssh2_1 and openssh.

Cygwin package selection screen showing SSH results

Next search for ssl and select the most recent versions of libopenssl100 and openssl.

Cygwin package selection showing SSL results

Now just let the installer do it’s stuff with the packages and their dependencies. You should end up with a desktop shortcut for Cygwin64 Terminal which opens a bash shell. Exciting stuff!

Cygwin bash terminal after the default install

Installing SSH Service

The openssh package in Cygwin comes with a script to help set up the SSHd, this has a few steps and will need to be run on every machine that you want to connect to. In our test network this will be done on both DC1 and DC2.

Open up the new terminal and enter ssh-host-config to start the script.

The first screen of the ssh-host-config command

It will then start asking a series of questions

Should StrictMode be used?

For our simple single user environment we don’t care that much about StrictMode being enabled.

Should privilige seperation be used?

Again for our single user setup we may as well just keep things simple here and say no.

Do you want to install SSHd as a service?

We do want it to start by itself, so say yes here.

Enter the value of CYGWIN for the daemon

Getting technical! This can just be left blank to keep the default. Phew.

At this point you’ll get a whole bunch of information about the need for a special account to be created and how it has to be a domain account. It also claims that you can share an account across all servers. I found that not to work super well so would recommend picking a unique name for each server, cyg_server_dc1 and cyg_server_dc2 seem like acceptable choices.

Enter the user name

Obviously for other servers enter a different name.

Confirm user should be created

It gets a little paranoid at this point, just confirm everything.

Enter a password for the new user

The new account needs a password, I just used the domain admin password here but you should probably generate a random secure one. It should never be used anyway. Watch out though, whatever you do enter here is about to appear in plain text on the screen.

That should be the end of the questioning, all done!

This does just mean the service is ready, there is a bit more to do before we can connect to it from the outside.

The service needs starting with net start sshd.

Output of the net start command

For some reason the home folder is created with weird file permissions, that can be corrected with the ssh-user-config command. We may as well create a private key with an empty passphrase since it offers.

Output of the ssh-user-config command showing a private key being created

The /etc/passwd and /etc/group files are for some reason incorrect too, they need to be corrected with the commands

mkpasswd -l > /etc/passwd
mkgroup -l > /etc/group

We also need to add a rule in Windows Firewall to allow incoming connections on port 22. Open up Windows Firewall with Advanced Security and add a new inbound port rule.

It will ask for the protocol type and port number, select TCP and enter 22.

Windows Firewall dialog for adding new rules

For a bit of added security you can untick the Public box on the last page if you don’t need that.

Finally name it something meaningful, like SSHd.

That’s everything so we’re ready to test from another machine. On the Linux desktop trying to connect gives some encouraging output.

Output from the SSH command attempting to connect to the Windows host.
Attempting an SSH connection to the Windows host.

Be careful with the usernames, they are case sensitive for SSH despite not being for Windows login.

Now just repeat this for each server you want to connect to.

Bonus 1 – Key Based Authentication

Just like on a Linux server you can authenticate using a key instead of the password, something that will be useful for the second bonus.

First create a new key on the machine that will be connecting to the server if it doesn’t already have one with ssh-keygen -t rsa -b 4096. The default options are all fine and the passphrase can be left blank.

Output from the ssh-keygen command

This will create a public and private key file in ~/.ssh, we need to copy the public key to the server so it can be used for authentication. The contents of ~/.ssh/id_rsa.pub need to be copied into C:\cygwin64\home\Administrator\.ssh\authorized_keys on the server, it’s probably simplest to do that with remote desktop and notepad.

Try to connect to the server again, it should not prompt for the password.

The same public key can be copied on to all of the servers.

Bonus 2 – Rsync

Rsync is an incredible folder synchronisation tool for Linux often used as part of backup or code deployment scripts. There is no native Windows version as it does all transfers via SSH.

Rsync can be installed With Cygwin, just run the installer again and add the package for it.

Cygwin package manager showing rsync results

You’ll now be able to rsync from a Linux machine, very useful for backup servers!

Output of the rsync command copying files from a Windows machine