Skip to content

Commit

Permalink
initial check in
Browse files Browse the repository at this point in the history
  • Loading branch information
new23d committed Dec 8, 2015
1 parent 4e632a8 commit 58665c8
Show file tree
Hide file tree
Showing 4 changed files with 343 additions and 1 deletion.
37 changes: 36 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,37 @@
# puppet-winrmSSL
# winrmSSL

Setup WinRM over HTTPS and control some basic, essential settings. Also supports Puppet CA issued certificates.

### Parameters

`issuer` can be set to either the value of the "Issued By" field of the certificate to utilise, or the path to the certificate issuer's/authority's .PEM public certificate file.

`port` (default 5986) This is for HTTPS only.

`maxmemoryshellpermb` (default 1024) As per the WinRM setting. You may need to apply Microsoft KB2842230 for this to take effect.

`maxtimeoutms` (default 60000) As per the WinRM setting.

`auth_basic` (default true) Since you are HTTPS secured now, no harm in allowing Basic Auth.

`disable_http` (default true) Removes the HTTP listener completely from WinRM so that plaintext transport is simply not available.

### Examples

Note that the following example uses the `new23d-puppetpem2p12` module for the `puppet_config_localcacert` fact.

```
# read the path to the Puppet CA's .PEM file into a variable
$ca_to_trust = $::puppet_config_localcacert
winrmSSL {$ca_to_trust:
ensure => present,
issuer => $ca_to_trust,
#port => 5986,
#maxmemorypershellmb => 1024,
#maxtimeoutms => 60000,
#auth_basic => true,
#disable_http => true
}
```

249 changes: 249 additions & 0 deletions lib/puppet/provider/winrmSSL/ruby_openssl.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
require 'openssl'
require 'open3'

Puppet::Type.type(:winrmssl).provide(:ruby_openssl) do
## confines
confine osfamily: 'windows'

## helpers
def _thumbprint
# is the namevar/issuer a Filesystem Path, or a Distinguished Name (DN)?
var_issuer_in_file = File.exist?(@resource[:issuer])

if var_issuer_in_file
issuer_pem = File.read(@resource[:issuer])

issuer_openssl_cert = OpenSSL::X509::Certificate.new(issuer_pem)
issuer_subject = issuer_openssl_cert.subject.to_s
else
# assuming it's a DN
issuer_subject = @resource[:issuer]
end

# remove leading slash if found
issuer_subject.gsub!(%r{^(\/)(.*)$}, '\2')

# var_cmd = "powershell @(get-childitem certificate::localmachine/my ^| where-object { $_.issuer -eq '#{issuer_subject}' -and $_.dnsnamelist -contains '#{Facter['fqdn'].value}' -and $_.hasprivatekey -and $_.enhancedkeyusagelist.friendlyname -contains 'Server Authentication'} ^| sort-object -property notafter -descending} )[0].thumbprint"
# var_cmd = "powershell @(get-childitem certificate::localmachine/my ^| where-object { $_.issuer -eq '#{issuer_subject}' -and $_.dnsnamelist -contains '#{Facter['fqdn'].value}' -and $_.hasprivatekey -and $_.enhancedkeyusagelist.objectid -contains '1.3.6.1.5.5.7.3.1'} ^| sort-object -property notafter -descending)[0].thumbprint"
var_cmd = "powershell @(get-childitem certificate::localmachine/my ^| where-object { $_.issuer -eq '#{issuer_subject}' -and $_.subject -eq 'CN=#{Facter['fqdn'].value}' -and $_.hasprivatekey} ^| sort-object -property notafter -descending)[0].thumbprint"
stdin, stdout, stderr, wait_thr = Open3.popen3(var_cmd)
stdin.close
var_rc = wait_thr.value.exitstatus
var_stdout_raw = stdout.read
var_stdout_raw.strip!

if var_stdout_raw.empty?
var_thumbprint = ''
fail Puppet::ResourceError, "Could not find a valid certificate for '#{Facter['fqdn'].value}' issued by '#{issuer_subject}'."
else
var_thumbprint = var_stdout_raw
end

var_thumbprint
end

## getters
def certificatethumbprint
var_cmd = 'winrm.cmd enumerate winrm/config/listener'
var_rgx = %r{CertificateThumbprint = ([0-9A-F]{40,40})$}

stdin, stdout, stderr, wait_thr = Open3.popen3(var_cmd)
stdin.close
var_rc = wait_thr.value.exitstatus
var_stdout = stdout.read

rgx_mth = var_rgx.match(var_stdout)
if !rgx_mth.nil?
var_state = rgx_mth[1]
else
var_state = ''
end

var_state
end

def disable_http
var_cmd = 'winrm.cmd enumerate winrm/config/listener'
var_rgx = %r{Transport = HTTP$}

stdin, stdout, stderr, wait_thr = Open3.popen3(var_cmd)
stdin.close
var_rc = wait_thr.value.exitstatus
var_stdout = stdout.read

rgx_mth = var_rgx.match(var_stdout)
var_state = (rgx_mth.nil?)

var_state = var_state.to_s.intern

var_state
end

def port
var_cmd = 'winrm.cmd enumerate winrm/config/listener'
var_rgx = %r{Transport = HTTPS\n[ ]{1,}Port = ([0-9]{1,5})$}

stdin, stdout, stderr, wait_thr = Open3.popen3(var_cmd)
stdin.close
var_rc = wait_thr.value.exitstatus
var_stdout = stdout.read

rgx_mth = var_rgx.match(var_stdout)
if !rgx_mth.nil?
var_state = rgx_mth[1]
else
var_state = ''
end

var_state
end

def auth_basic
var_cmd = 'winrm.cmd get winrm/config/service/auth'
var_rgx = %r{Basic = true$}

stdin, stdout, stderr, wait_thr = Open3.popen3(var_cmd)
stdin.close
var_rc = wait_thr.value.exitstatus
var_stdout = stdout.read

rgx_mth = var_rgx.match(var_stdout)
var_state = (!rgx_mth.nil?)

var_state = var_state.to_s.intern

var_state
end

def maxmemorypershellmb
var_cmd = 'winrm.cmd get winrm/config/winrs'
var_rgx = %r{MaxMemoryPerShellMB = ([0-9]{1,})$}

stdin, stdout, stderr, wait_thr = Open3.popen3(var_cmd)
stdin.close
var_rc = wait_thr.value.exitstatus
var_stdout = stdout.read

rgx_mth = var_rgx.match(var_stdout)
if !rgx_mth.nil?
var_state = rgx_mth[1]
else
var_state = ''
end

var_state
end

def maxtimeoutms
var_cmd = 'winrm.cmd get winrm/config'
var_rgx = %r{MaxTimeoutms = ([0-9]{1,})$}

stdin, stdout, stderr, wait_thr = Open3.popen3(var_cmd)
stdin.close
var_rc = wait_thr.value.exitstatus
var_stdout = stdout.read

rgx_mth = var_rgx.match(var_stdout)
if !rgx_mth.nil?
var_state = rgx_mth[1]
else
var_state = ''
end

var_state
end

## setters
def disable_http=(var_param)
if var_param == :true
var_cmd = 'winrm delete winrm/config/listener?Address=*+Transport=HTTP'
else
var_cmd = 'winrm create winrm/config/listener?Address=*+Transport=HTTP'
end

stdin, stdout, stderr, wait_thr = Open3.popen3(var_cmd)
stdin.close
var_rc = wait_thr.value.exitstatus
end

def port=(_var_param)
destroy
create
end

def auth_basic=(var_param)
var_cmd = "winrm set winrm/config/service/auth @{Basic=\"#{var_param}\"}"
stdin, stdout, stderr, wait_thr = Open3.popen3(var_cmd)
stdin.close
var_rc = wait_thr.value.exitstatus
end

def maxmemorypershellmb=(var_param)
var_cmd = "winrm set winrm/config/winrs @{MaxMemoryPerShellMB=\"#{var_param}\"}"
stdin, stdout, stderr, wait_thr = Open3.popen3(var_cmd)
stdin.close
var_rc = wait_thr.value.exitstatus
end

def maxtimeoutms=(var_param)
var_cmd = "winrm set winrm/config @{MaxTimeoutms=\"#{var_param}\"}"
stdin, stdout, stderr, wait_thr = Open3.popen3(var_cmd)
stdin.close
var_rc = wait_thr.value.exitstatus
end

def certificatethumbprint=(_var_param)
# ignore the passed-in value

var_thumbprint = _thumbprint

var_cmd = "winrm create winrm/config/listener?Address=*+Transport=HTTPS @{Hostname=\"#{Facter['fqdn'].value}\";CertificateThumbprint=\"#{var_thumbprint}\";Port=\"#{@resource[:port]}\"}"
stdin, stdout, stderr, wait_thr = Open3.popen3(var_cmd)
stdin.close
var_rc = wait_thr.value.exitstatus
end

## implements
def create
var_properties2ignore = [caller_locations(1, 1)[0].label]

@resource.properties.each do |var_property|
next unless self.respond_to? "#{var_property}=".intern

# don't recurse into the caller!
next unless (!var_properties2ignore.include? var_property.to_s) && (!var_properties2ignore.include? "#{var_property}=")

next unless send("#{var_property}") != @resource["#{var_property}".intern]

send("#{var_property}=", @resource["#{var_property}".intern])
end
end

def destroy
var_cmd = 'winrm.cmd invoke restore winrm/config @{}'
stdin, stdout, stderr, wait_thr = Open3.popen3(var_cmd)
stdin.close
var_rc = wait_thr.value.exitstatus
end

def exists?
@resource[:certificatethumbprint] = _thumbprint

var_cmd = 'winrm.cmd enumerate winrm/config/listener'
var_rgx = %r{Transport = HTTPS\n[ ]{1,}Port = #{@resource[:port]}\n}

stdin, stdout, stderr, wait_thr = Open3.popen3(var_cmd)
stdin.close
var_rc = wait_thr.value.exitstatus
var_stdout = stdout.read

rgx_mth = var_rgx.match(var_stdout)
var_rc = (!rgx_mth.nil?)

var_rc
end

def self.instances
fail 'Not implemented.'
end
end
32 changes: 32 additions & 0 deletions lib/puppet/type/winrmSSL.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
Puppet::Type.newtype(:winrmSSL) do
ensurable

newparam(:issuer, namevar: true) do
end

newproperty(:disable_http) do
newvalues(:true, :false)
defaultto :true
end

newproperty(:port) do
defaultto '5986'
end

newproperty(:auth_basic) do
newvalues(:true, :false)
defaultto :true
end

newproperty(:maxmemorypershellmb) do
defaultto '1024'
end

newproperty(:maxtimeoutms) do
defaultto '60000'
end

newproperty(:certificatethumbprint) do
defaultto ''
end
end
26 changes: 26 additions & 0 deletions metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "new23d-winrmSSL",
"version": "0.0.1",
"author": "new23d",
"summary": "Setup WinRM over HTTPS and control some basic, essential settings. Also supports Puppet CA issued certificates.",
"license": "Apache-2.0",
"source": "https://github.com/new23d/puppet-winrmSSL.git",
"project_page": "https://github.com/new23d/puppet-winrmSSL",
"issues_url": "https://github.com/new23d/puppet-winrmSSL/issues",
"operatingsystem_support": [
{
"operatingsystem": "Windows",
"operatingsystemrelease": [
"Server 2008",
"Server 2008 R2",
"Server 2012",
"Server 2012 R2",
"7",
"8"
]
}
],
"dependencies": [],
"tags": ["winrm", "https", "tls", "ssl"]
}

0 comments on commit 58665c8

Please sign in to comment.