GoogleCloudPlatform / compute-image-windows

Windows agents and scripts for Google Compute Engine images.
Apache License 2.0
104 stars 63 forks source link

Install and run OpenSSH-win32? #164

Open petemounce opened 5 years ago

petemounce commented 5 years ago

I've had positive experience with https://github.com/PowerShell/openssh-portable on Windows Server 2016

I would love a world where I didn't have to deal with WinRM (can elaborate, but on request - want to keep this concise) and instead could use ssh to communicate to each of my remote fleet.

I was wondering at which point GCE might start to create base images that have it installed and, if not running, at least ready to go via a metadata-script nudge? I appreciate that one could install it via those means too, at the cost of extra time during either baking or boot.

Would you welcome a PR that added it, and if so, would you mind outlining what you might, vs might not, accept?

adjackura commented 5 years ago

I have been toying with this for a while now, just not sure how big of a customer ask it is, I even have some very slick integrations working (see current state of ssh access on Linux for an idea).

You mention a simple process for the installation would be OK, even if it isn't baked into the base image right? We will have to discuss this more before we commit to anything but any more feedback on your use case would be great.

petemounce commented 5 years ago

I even have some very slick integrations working (see current state of ssh access on Linux for an idea).

Please link me?

We will have to discuss this more before we commit to anything but any more feedback on your use case would be great.

My own use-case is basically that I want to unify onto ssh. I use packer & ansible to create golden images (Linux/Ubuntu and Windows within GCE, macOS within another provider (choice unfinalised, but looking like macstadium via anka)) that are then used for CI infrastructure. I have a strong requirement that builds be reproducible several years later, for long-term support of games development.

Where I work (https://improbable.io) has only a small number of people with Windows infrastructure experience; that's another motivation for wanting to unify onto ssh, it's more widely familiar. We use bazel extensively with various languages including C++, so controlling the build environment is very important to avoid poisoning the remote cache via differing machine setups.

The ansible project is working to support a Windows openssh connection plugin (https://github.com/ansible/ansible/issues/25344 -> https://github.com/ansible/ansible/pull/47732). I'm hoping that by adding support (baked or recipe) into a major cloud provider's Windows offering, that work will get wider adoption, quicker.

There are a few options for installation described at https://github.com/DarwinJS/ChocoPackages/tree/master/openssh#install-scenario-2-non-chocolatey-using-psh-5-packagemanagement.

One that would probably work fine inside windows-startup-script-ps1: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/DarwinJS/ChocoPackages/master/openssh/InstallChoco_and_win32-openssh_with_serverPS5.ps1')). At that point, I'm going to make the assumption that the existing google cloud agent would need only small changes to deal with

adjackura commented 5 years ago

See the linux section here: https://cloud.google.com/compute/docs/instances/connecting-to-instance

I'm still debating the best way to handle this if we decide to support it. Either a custom package we maintain for the ssh server install or just pulling straight from Microsoft (have you tried following https://docs.microsoft.com/en-us/windows-server/administration/openssh/openssh_install_firstuse?). I'm also not sure how I want to update the agent, the simplest is as you described (that's how we do it on linux, and how I had it working in my POC), but using AuthorizedKeysCommand would be much cleaner and allow us to potentially integrate with oslogin (https://cloud.google.com/compute/docs/oslogin/)

petemounce commented 5 years ago

I haven't tried the first-use setup yet; I only just noticed Server 2019 has an improved experience. Except they seem to have changed the Powershell cmdlets for managing Windows features again.

One of our use-cases is to allow people (via their gcloud auth) to remotely connect to instances that match a particular regex in their instance-names. People can remote into canary instances to poke around, but not production instances, basically.

cc @shenson for thread.

(I'm about to be away for a couple of weeks)

petemounce commented 5 years ago

@adjackura I did a thing.

I tell packer to launch the instance with metadata:

This is the windows-startup-script-ps1:

Get-GceMetaData -Path instance/attributes/bootstrap-base64 > c:/windows/temp/bootstrap.b64 ; certutil -decode c:/windows/temp/bootstrap.b64 c:/windows/temp/bootstrap.ps1 ; c:/windows/temp/bootstrap.ps1 -username totally-not-telling-you-the-username

This is the bootstrap.ps1 that I arrange into bootstrap-base64:


param(
    [string] $username = "tweeter",
    [string] $open_ssh_version = "v7.9.0.0p1-Beta"
)
$ErrorActionPreference = 'Stop'; # stop on all errors
$log_stamp = get-date -format 'yyyyMMdd-HHmmss'
Start-Transcript -Path "$(pwd)/bootstrap.$($log_stamp).log" -IncludeInvocationHeader

# Make the administrator user that we'll be provisioning with during packer run
$Count = Get-Random -min 24 -max 32
$TempPassword = -join ((65..90) + (97..122) + (48..57) | Get-Random -Count $Count | % {[char]$_})
New-LocalUser -Name $username -PasswordNeverExpires -Password ($TempPassword | ConvertTo-SecureString -AsPlainText -Force) | out-null
Add-LocalGroupMember -Group "Administrators" -Member $username | out-null

# Install openssh
# https://github.com/PowerShell/Win32-OpenSSH/wiki/Install-Win32-OpenSSH
$url = "https://github.com/PowerShell/Win32-OpenSSH/releases/download/$($open_ssh_version)/OpenSSH-Win64.zip"
$output = "$($env:TEMP)/OpenSSH-Win64.zip"
# github went TLS 1.2 only from 2018
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12;
(New-Object System.Net.WebClient).DownloadFile($url, $output)
Expand-Archive -Path $output -DestinationPath "$($env:PROGRAMFILES)"
. "$($env:PROGRAMFILES)/OpenSSH-Win64/install-sshd.ps1"

# Set default shell for sshd connections to powershell to avoid legacy cmd nonsense
# https://github.com/PowerShell/Win32-OpenSSH/wiki/DefaultShell
[System.Environment]::SetEnvironmentVariable("PATH", "$($env:PATH);c:\Program Files\OpenSSH-Win64", [System.EnvironmentVariableTarget]::Machine)
New-Item -path "HKLM:\SOFTWARE\OpenSSH" -force
New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -PropertyType String -Force
New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShellCommandOption -Value "/c" -PropertyType String -Force

# An sshd_config that's basically the stock one but
# * allows public key authentication (which is commented by default)
$sshd_config = "$($env:PROGRAMDATA)/ssh"
New-Item "$($sshd_config)" -Type Directory -Force
$sshd_config_file = "$($sshd_config)/sshd_config"
$sshd_config_base64 = get-gcemetadata -path "instance/attributes/sshd-config-base64"
$sshd_config_text = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($sshd_config_base64))
Set-Content -Path "$($sshd_config_file)" -Value "$($sshd_config_text)"

# Put the public key in the system-wide config location to avoid needing to programmatically create user profile. Sigh.
$public_key_base64 = get-gcemetadata -path "instance/attributes/public-key-base64"
$public_key = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($public_key_base64))
$system_authorized_keys_file = "$($sshd_config)/administrators_authorized_keys"
if (Test-Path "$($system_authorized_keys_file)") {
  Remove-Item -Path "$($system_authorized_keys_file)" -force
}
Set-Content -Path "$($system_authorized_keys_file)" -Value "$($public_key)"

# Ensure access control on authorized_keys meets the requirements
# https://stackoverflow.com/questions/16212816/setting-up-openssh-for-windows-using-public-key-authentication
# https://github.com/jen20/packer-aws-windows-ssh/blob/master/files/configure-source-ssh.ps1#L99-L114
$acl = Get-ACL -Path $system_authorized_keys_file
$acl.SetAccessRuleProtection($True, $True)
Set-Acl -Path $system_authorized_keys_file -AclObject $acl
$acl = Get-ACL -Path $system_authorized_keys_file
$ar = New-Object System.Security.AccessControl.FileSystemAccessRule( `
    "NT Authority\Authenticated Users", "ReadAndExecute", "Allow")
$acl.RemoveAccessRule($ar)
$ar = New-Object System.Security.AccessControl.FileSystemAccessRule( `
    "BUILTIN\Administrators", "FullControl", "Allow")
$acl.RemoveAccessRule($ar)
$ar = New-Object System.Security.AccessControl.FileSystemAccessRule( `
    "BUILTIN\Users", "FullControl", "Allow")
$acl.RemoveAccessRule($ar)
Set-Acl -Path $system_authorized_keys_file -AclObject $acl

Restart-Service sshd
Set-Service sshd -StartupType Automatic

# lastly, open up the firewall port
New-NetFirewallRule -Name sshd -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22

Stop-Transcript

This is working well so far against Windows 2016 Server desktop edition. Haven't tried it elsewhere so far. I imagine/hope that the only bit necessary to change for Windows 2019 is the 'install openssh' bit.

petemounce commented 1 year ago

Just checking in - this script and setup continue to serve well through Windows versions 2019 and 2022.

cidrbl0ck commented 1 year ago

Super excited about this, especially since Winrm is hot garbage. But also fighting weird issues with PSRP ontop of Winrm. since your last comment is ~a year old. Have you toyed with the newer support MS mentioned with SSH? https://learn.microsoft.com/en-us/powershell/scripting/learn/remoting/ssh-remoting-in-powershell-core?view=powershell-7.3

Mufabo commented 4 days ago

To whomever is still ending up here:

You can easily install OpenSSH on GCP Windows VMs using Metadata

https://cloud.google.com/compute/docs/connect/windows-ssh