Using execrun with windows instances

execrun step uses SSH to connect and execute commands on remote machine. Because Windows lacks built-in SSH server, a target system should be specifically prepared to do this.

This tutorial provides a solution for that problem on instances, running in Amazon EC2. We will use Cygwin on to allow SSH access on Windows VMs, and Powershell to automate setup and installation.

There are two ways to prepare a machine to be accessed via SSH:

  1. Install and setup Cygwin during VM launch using UserData.
  2. Make an image with pre-set Cygwin.

The second option is the preferred one since it does not slow down the instance setup. You may need to install cygwin on provisioning if you want to support third-party images that you can not customize.

In both cases, you may need to add a wait step after provision, because Cygwin needs some time to start and initialize after VM launch. Typical delay is around 5-7 minutes, and depends on your image and VM type. Note, that authorization failures during provision and execrun typically mean that delay is insufficient.

Installing Cygwin on Each Boot

You should add a policy provisionVms.providerSettings to environment, which contains the Cygwin install and setup script. Note, that dollar $ and braces symbols {} are duplicated in sake of escaping.

userData:
    |
      <powershell>
          $$wc = New-Object System.Net.WebClient
          $$wc.DownloadFile("http://cygwin.com/setup-x86_64.exe", "setup-x86_64.exe")

          .\setup-x86_64.exe --no-desktop --site ftp://mirrors.kernel.org/sourceware/cygwin/ --quiet-mode --local-package-dir C:\cygwin64\local_packages --packages "openssh,curl,util-linux,procps" | Out-Null
          C:\cygwin64\bin\bash.exe --login -c "cp /usr/bin/ps.exe /usr/bin/ps.exe~; cp /bin/ps.exe /bin/ps.exe~; cp /usr/bin/procps.exe /usr/bin/ps.exe; cp /usr/bin/procps.exe /bin/ps.exe"  # required for execrun to work correctly

          C:\cygwin64\bin\bash.exe --login -c "ssh-host-config --yes --user cyg_server --pwd mySecretPassw0rd"

          C:\cygwin64\bin\bash.exe --login -c "mkdir ~/.ssh; curl 169.254.169.254/latest/meta-data/public-keys/0/openssh-key > ~/.ssh/authorized_keys"

          netsh advfirewall firewall add rule name="CYGWIN sshd" dir=in action=allow program="C:\cygwin64\usr\sbin\sshd.exe" enable=yes

          net start sshd
      </powershell>

With this policy in the environment, you will be able to execute execrun step against a windows VM.

Preparing Instance with Installed Cygwin

To start, you need an Amazon account and a base Windows image.

1. Start Windows Image and Login Using RDP

Start an instance using either web console or CLI tools, and acquire Administrator password by clicking Connect button or using tools such as ec2-get-password and get-password-data. Note, that you need private key for this instance to decrypt password.

2. Install Cygwin

Open PowerShell console and repeat these steps:

# install Cygwin
$wc = New-Object System.Net.WebClient
$wc.DownloadFile("http://cygwin.com/setup-x86_64.exe", "setup-x86_64.exe")
.\setup-x86_64.exe --no-desktop --site ftp://mirrors.kernel.org/sourceware/cygwin/ --quiet-mode --local-package-dir C:\cygwin64\local_packages --packages "openssh,curl,util-linux,procps" | Out-Null
C:\cygwin64\bin\bash.exe --login -c "cp /usr/bin/ps.exe /usr/bin/ps.exe~; cp /bin/ps.exe /bin/ps.exe~; cp /usr/bin/procps.exe /usr/bin/ps.exe; cp /usr/bin/procps.exe /bin/ps.exe"  # required for execrun to work correctly

# setup OpenSSH
C:\cygwin64\bin\bash.exe --login -c "ssh-host-config --yes --user cyg_server --pwd mySecretPassw0rd"
netsh advfirewall firewall add rule name="CYGWIN sshd" dir=in action=allow program="C:\cygwin64\usr\sbin\sshd.exe" enable=yes
net start sshd

During installation, Cygwin setup window will appear. You should not interact with it in any way – setup will be completed fully automatedly.

3. Create an Image from Instance

First, you should re-enable password generation and user data execution on VM boot. To do this, run C:\Program Files\Amazon\Ec2ConfigService\Ec2ConfigServiceSettings.exe, set checkbox User Data on General tab, go to Image tab, select Random radiobutton and click Shutdown without Sysprep. After this, instance will shut down. For additional information, please refer official documentation.

When instance stops, image can be created either from EC2 Web Console by clicking Actions - Create Image, either manually using ec2-create-image command.

4. Setup Environment to Get the Keypair on Boot

You should add a policy for provisionVms.providerSettings to the environment, which contains the script that downloads a keypair from the metadata server.

userData:
    |
      <powershell>
          C:\cygwin64\bin\bash.exe --login -c "mkdir ~/.ssh; curl 169.254.169.254/latest/meta-data/public-keys/0/openssh-key > ~/.ssh/authorized_keys"
      </powershell>

As an example image, you can use us-east-1/ami-16b34d7e, that uses Amazon’s Microsoft Windows Server 2012 Base us-east-1/ami-aede32c6.

userData can also be used to change a user password on a VM. To do this, net command can be used:

userData:
    |
      <powershell>
          # ...
          # set password on VM after launch
          net user Administrator "newPassw0rdToUse"
      </powershell>

As always, you can write providerSettings directly in a manifest, and set user-defined password using expressions from a launch parameter or a policy:

parameters:
    password: {type: string, default: qwerty}
steps:
    - provision:
        action: provisionVms
        parameters:
            providerSettings:
                userData:
                  |
                    <powershell>
                        # ...
                        # set password on VM after launch
                        net user Administrator {$.password}
                    </powershell>