Growing up in Northern Canada I heard “Don’t forget to close the door on your way out!” many times a day for about 9 months of the year. Leaving a door open on your home wastes energy - leaving a door open in your computing environment can lead to downright mayhem. Many windows remote orchestration tools (e.g. Packer) instruct you to open up winrm permissions in a way that is not safe for (nor intended for) use in production. (e.g. https://www.packer.io/docs/builders/ncloud.html#requirements-for-creating-windows-images)
Generally there is no guidance on how to re-secure it nor even a reminder to do so. The assumption most likely being that you would handle proper winrm re-configuration as a part of provisioning a machine from the template image your making. However, in many organizations, system image preparation may be the only use of WinRM - so it is forgotten. Or maybe whatever is used to re-configure WinRM on first boot does not actively reset one or more of the permissive settings used during machine provisioning.
Reverting to a Pristine State
It is important to know that Sysprep does not revert WinRM configuration to a pristine state. I checked with contacts at Microsoft and there are not any API calls to revert WinRM to a pristine state.
Keep in mind that disabling WinRM is not the goal - but rather returning it to a pristine state (or as close as possible). This allows it to be reconfigured using conventional instructions on the first boot of the template image - including the possibility that subsequent system preparation automation (like packer) will be used to prepare a new template image based on a previously prepared image template.
Leaving WinRM in a preconfigured open state is not a least privileged approach for several reasons:
- sysprep does not automatically deconfigure WinRM.
- it is not secure at rest.
- it is not secure upon first boot up.
- image templates are generally used to create hundreds or thousands of live machine instances - so they propagate any embedded settings.
- it is unlikely the next user of the image template would think that WinRM has been preconfigured and running with permissive settings and that they would need to deal with it.
- it is unlikely that the next user of the image template, who needs to configure WinRM, would examine the existing WinRM configuration to understand if it has permissive settings from previous configuration usage - we tend to think of images as having a pristine first boot state.
- even if you actively disable, but not reset WinRM - the next usage of WinRM can inherit very permissive settings just by being re-enabled.
- even if your company has GPOs that manage WinRM settings, machine templates may not always join the domain before being used for extended lifetimes in development environments or for other non-domain joined usage scenarios.
Depending on how big your company is and how widely your image templates are used - this is a disaster waiting to happen. So reconfiguring it to default to a pristine state is the safest and most responsible approach.
Constraints on Possible Solutions
So it’s easy right? Just reset WinRM and you are done!
There is actually need for an engineered solution such as Undo-WinRMConfig:
- There is no API to reset WinRM to a pristine state, so a standardized approach to attempting this reversion is helpful.
- If you attempt to revert WinRM configuration as your last step in automation that is using WinRM to access the machine - you slam the door on your own fingers and the automation will most likely exit with an error.
- Due to imprecise timing, startup tasks that disable winrm could conflict with a subsequent attempt to re-enable it on the next boot for additional configuration steps or to create a new image.
The Undo-WinRMConfig Solution
This Undo-WinRMConfig solution has the following design attributes:
- attempts to approach the problem in the simplest possible way that also…
- allows community contribution to covering all the OS variations and improving the code quality
- All code is in a single script file to facilitate running from Github and to ensure the solution does not require placement of other files in order to be used. (in many deployment automation systems, sending and executing a single script file is much simpler than any automation task requiring additional files to be sent along with the code)
- Configures a self-deleting shutdown task which performs the disable on the first shutdown and deletes itself.
- Utilizes a .REG file exported from a pristine system to reset the WSMAN portion of the registry (on a per-major OS basis)
- Will error out if it does not have a pristine WSMAN .Reg export for your OS variant - but you can contribute the pristine key on github for inclusion in the script.
- It can also take a switch to run immediately - which only works if you are not using WinRM to run it.
- It can be called directly from Github or downloaded to a template image or called using chocolatey.
This code is engineered by reversing the commands required to configure winrm to be used for system preparation by Packer from many examples found on the internet. In that regard it results in returning WinRM configuration to a state similar to, but possibly not identical to pristine defaults.
This code was engineered and tested on Server 2012 R2 / PowerShell 4 and Server 2016 / PowerShell 5.
This code is in alpha.
It grieves my soul to have to integrate copies of pristine registry keys for each OS variation - hence my “Hey Microsoft” shout out in this article. I did it anyway because this issue is too important not to have something trying to fill this gap.
Helping Out With The Undo-WinRMConfig Open Source Project
The Contributing Guide tells what engineering is needed to request the inclusion of a new OS version not currently covered. It also points you to a fast, simple snapshot tool if you are wanting to understand if the overall solution is missing any settings reversals that should be included.
Ways to Run It
Direct Run From GitHub
Run Undo Process At Shutdown (default)
Invoke-Expression (invoke-webrequest -uri 'https://raw.githubusercontent.com/DarwinJS/Undo-WinRMConfig/master/Undo-WinRMConfig.ps1')
Run Immediately (Careful!)
Caution: If you run this command while remoting in, you will slam the remoting connection closed and have a non-zero exit code.
Invoke-webrequest -uri 'https://raw.githubusercontent.com/DarwinJS/Undo-WinRMConfig/master/Undo-WinRMConfig.ps1' -outfile $env:public\Undo-WinRMConfig.ps1 ; & $env:public\Undo-WinRMConfig.ps1 -immediately
Place On Image Template Without Running
Invoke-webrequest -uri 'https://raw.githubusercontent.com/DarwinJS/Undo-WinRMConfig/master/Undo-WinRMConfig.ps1' -outfile $env:public\Undo-WinRMConfig.ps1
Chocolatey Package (Pre-release - does not show up publicly)
Run At Shutdown (default)
choco install undo-winrmconfig-at-shutdown -pre -confirm
Run Immediately (Careful!)
choco install undo-winrmconfig-at-shutdown -pre -confirm -params '"/RunImmediately"'
Hey Microsoft - How About Developing With “Revert to Pristine” as a First Class Design Citizen?
Many years ago Microsoft shifted their development focus for operating system tooling to “automation enabled” interfaces being developed FIRST - followed by GUI tooling (even encouraging that GUI tooling be built on the CLI tooling). The impact was nothing short of phenomenal for tooling. It seems like a similar approach to configuring the operating system in areas with security implications could benefit from a simliar principle.
I would like to submit the idea that with critical security configurations like this, that “Revert to Pristine” API calls should be engineered as the first thing - or a persistent thing throughout development. If this concept is in the development cycle from the beginning, then it is more likely that each technology with security implications would be self-aware of how to return itself to an out of box state.