The usage of passwords is a common practice to authenticate users, but it becomes also a weak point when it comes to password distribution and management of a large number of servers, like for example in an OpenStack cloud (or any type of cloud, for the sake of it).
Background: password-less Linux image deployments
On Linux and other Posix operating systems (OS X, BSD, etc) this issue has been solved since a long time by using solutions like SSH with pairs of public and private keys, courtesy of asymmetric cryptographic algorithms like the ubiquitous RSA.
The main idea is that the private key is kept secret by the user, while the public key can be accessed by anyone.
OpenStack guest authentication is commonly based on this model, with keypairs managed by Nova and easily handled via the Horizon dashboard or the command line.
When a guest boots, the public key belonging to a given keypair is shared between the OpenStack environment and the guest via metadata, which is simply a json encoded dictionary and some additional files accessible by the guest via HTTP or other means.
Although it is possible (and unfortunately common) to provide passwords in clear text inside of the metadata, this is definitely not a good idea. On the other side, putting an SSH public key has no security implications, as by definition the key is public. Once the key has been deployed inside of the guest by cloud-init or other tools, the user can authenticate with her/his private key.
WinRM: Windows native alternative to SSH
Most Windows users probably never heard about it, but Windows contains a little jewel called Windows Remote Management (WinRM), included with every version of the OS since Windows Server 2008 / Windows Vista and also available as a free additional download for Windows Server 2003 and Windows XP.
WinRM is considered as the Windows equivalent of SSH in most scenarios. The communication between clients and servers is based on the WS-Management (WSMan) open standard (a SOAP protocol), which means that it is not limited to Windows only. We are actually using it a lot to automate OpenStack deployments from Linux on Hyper-V, just as an example.
When used together with a remote PowerShell session, you’ll see that not only it is possible to manage a Windows host remotely, but it’s also a great experience once you see what PowerShell is capable of.
WinRM supports various forms of authentication (Basic, Digest, Kerberos and Certificate) and various transport protocols, including HTTP and HTTPS.
So, why isn’t WinRM hugely popular today, like, for example, SSH? My two cents here are that it’s notoriously complicated to configure, on both servers and clients, to the point that it remained matter for initiated sysadmins…
… until we released the solution described below. 🙂
Cloudbase-Init and WinRM
The main idea behind the development of cloudbase-init, was to bring the approach commonly available on Linux with cloud-init to Windows (you can learn more about it here). This means that once a guest Windows instance gets deployed in a cloud, cloudbase-init takes care of all the configuration details: setting the hostname, creating users and setting passwords, expanding file systems, running custom scripts, deploying heat templates and more.
The great news is that we just added two new features that automate completely the WinRM configuration, without a single action required from the user side.
You can get the Cloudbase-Init directly from here and we provide also official Windows Server 2012 R2 Evaluation images ready to be deployed in OpenStack.
WinRM HTTPS Listener
The ConfigWinRMListenerPlugin configures a WinRM HTTPS listener with a self signed certificate generated on the spot and enables (optionally) basic authentication, which means that a secure communication channel can be established between any client and the server being provisioned, without the requirement of having both the client and the server in the same domain. A firewall rule is added by cloudbase-init in the Windows firewall for TCP port 5986.
A this point you can login into your server. To begin with, don’t forget to add a rule to your security groups in OpenStack!
1 |
nova secgroup-add-rule default tcp 5986 5986 0.0.0.0/0 |
Get the admin password for the instance:
1 |
nova get-password yourinstance ~/.ssh/your_ssh_rsa_key |
On your client connect to your instance as shown in the following PowerShell snippet:
1 2 3 4 5 6 |
$ComputerName = "yourserveraddress" # Provide your username and password (by default "Admin" and the password you just obtained) $c = Get-Credential $opt = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck $session = New-PSSession -ComputerName $ComputerName -UseSSL -SessionOption $opt -Authentication Basic -Credential $c Enter-PSSession $session |
What about Linux and OS X clients?
First download wsmancmd.py, and install pywinrm, a great and simple open source Python WSMan implementation. Now just run any remote Windows command from Linux or OS X:
1 |
wsmancmd.py -U https://your_host:5986/wsman -u your_user -p your_password 'powershell -Command Get-NetIPConfiguration' |
At this point you’ll be connected to the remote host and all the commands will be executed remotely. You can change your user’s password, create additional users, configure the server, etc.
Here’s a snapshot showing a PowerShell command executed remotely from an Ubuntu client:
We still have one issue: we needed a password to authenticate. How to avoid it altogether?
WinRM HTTPS certificate authentication
Unlike the simple public / private keypairs used by SSH in OpenStack, WinRM uses X509 certificates for authentication.
Certificates are also associated with a keypair. The “public” certificate (without the private key) is part of the X509 certificate, in our case distributed in a base64 encoded format (PEM).
The private key and the certificate are typically packaged in a password protected #PKCS12 file (.pfx or .p12 extension).
The following Bash script, available here, generates a self signed certificate and both pem and pfx files for you. It will ask for a password which is used to protect the pfx file. Take note of it, you’ll need it on the client to import the certificate.
1 |
./create-winrm-client-cert.sh "cloudbase-init-example" your_cert |
At this point you have two certificate files: your_cert.pfx and your_cert.pem.
The certificate provisioning on the Windows guest is done by the ConfigWinRMCertificateAuthPlugin in the Cloudbase-Init service, all we need is to pass a public X509 PEM file to it. How can we do that? There are two options today:
The first one consists in passing the PEM file as user_data script to the Nova boot command.
You can do it in Horizon by pasting the PEM file contents as shown in the following snapshot:
Or with the command line equivalent:
1 2 |
nova boot --flavor 2 --image your_windows_image --key-name key1 vm1 \ --user_data=your_cert.pem |
Although this is very simple and effective, it might become a problem if you already need to employ the user_data for other reasons, e.g. running a custom script or deploying a Heat template.
In that case we can use the custom metadata option, but since custom metadata fields can be maximum 255 characters long, we need to split the certificate in multiple fields. It’s clearly a bit cumbersome, so expect hopefully some new options in the upcoming OpenStack releases!
1 2 3 4 5 6 7 8 9 |
declare -a CERT=(`openssl x509 -inform pem -in your_cert.pem -outform der | \ base64 -w 0 | sed -r 's/(.{255})/\1\n/g'`) nova boot --flavor 2 --image "your_windows_image" --key-name key1 vm1 \ --meta admin_cert0="${CERT[0]}" \ --meta admin_cert1="${CERT[1]}" \ --meta admin_cert2="${CERT[2]}" \ --meta admin_cert3="${CERT[3]}" \ --meta admin_cert4="${CERT[4]}" |
We’re almost done. On your client you need to install the certificate, including the private key. Since the pfx file is password protected, you can transfer it on any media, including HTTP, email or else.
Here’s a PowerShell script to simplify the process. It will ask for your pfx file password to import the certificate in your “Personal” X509 store. Take note of the certificate subject shown in output, you’ll need it in the next step.
1 |
.\ImportPfx.ps1 -path your_cert.pfx |
Now you’re ready to connect! Use the following PowerShell script to get a remote PowerShell session using your certificate:
Et voilà, you’re in a password-less remote session on your Windows instance. 🙂
Great work on Hyper-V, greate work on Windows-based applications!
Thanks! 🙂
Yes Kudos Alessandro et al. Nice bit of work. -dave