Managing certificates with Chef and Windows

Managing stuff on windows with Chef can be tough.. Especially compared to Linux systems. I’ve been doing it like this:

pfx.each do |pfx|
    s3_file 'c:/chef/' + pfx do
        remote_path '/' + pfx
        bucket 'chef'
        aws_access_key_id node['iis']['aws_key']
        aws_secret_access_key node['iis']['aws_secret']
        action :create
        not_if {::File.exists?("c:/chef/#{pfx}.zip")}
    end
    execute 'import pfx' do
        command "c:/chef/importpfx.exe -f c:/chef/#{pfx} -t MACHINE -s MY -p \"#{pass}\""
    end
end
cert_map = pfx.zip(cert, ip)
cert_map.each do |pfx, cert, ip|
    powershell_script 'bind cert' do
        code <<-EOH
        $var = dir cert:\\LocalMachine\\my | grep #{cert}
    $pos = $var.IndexOf(" ")
    $sub = $var.Substring(0,$pos)
    netsh http add sslcert ipport=#{ip}:443 certhash=$sub appid={ab3c58f7-8316-42e3-bc6e-771d4ce4b201}
    EOH
    not_if {"$var = dir cert:\\LocalMachine\\my | grep #{cert} ;; $pos = $var.IndexOf(\" \") ;; $sub = $var.Substring(0,$pos) ;; netsh http show sslcert | grep $sub -i"}
    end
end

I’ve not yet found a better way to do it. This lets me download the cert and bind it to a certain interface. My personal use case is ssl bindings for IIS, but this should work for any other use as well.

Update:

I’ve since updated this a little bit -

if node['iis']['manage_ssl'] == true
    if node.chef_environment == 'prod-windows'
      `powershell.exe -Command (invoke-webrequest http://169.254.169.254/latest/meta-data/network/interfaces/macs -UseBasicParsing -DisableKeepAlive).content.trim()`.split("\n").each do |mac|
        ip = `powershell.exe -Command (invoke-webrequest http://169.254.169.254/latest/meta-data/network/interfaces/macs/#{mac}local-ipv4s -UseBasicParsing -DisableKeepAlive).content.trim()}.delete("\n")`
      end
      pfx = %w(star.example.com.pfx star.example.com.pfx)
      cert = %w(*.example.com *.example.com)
      pass = %w(T00lb0x! T00lb0x!)
    else
      pfx = %w(_.example.com.pfx)
      cert = %w(*.example.com)
      pass = %w()
      ip = %w(0.0.0.0)
    end

    cert_map = pfx.zip(cert, pass, ip)
    cert_map.each do |pfx, cert, pass, ip|
      s3_file 'c:/chef/' + pfx do
        remote_path '/' + pfx
        bucket 'chef'
        aws_access_key_id node['iis']['aws_key']
        aws_secret_access_key node['iis']['aws_secret']
        action :create
        not_if { ::File.exist?("c:/chef/#{pfx}") }
      end
      execute 'import pfx' do
        command "c:/chef/importpfx.exe -f c:/chef/#{pfx} -t MACHINE -s MY -p \"#{pass}\""
      end

      powershell_script 'bind cert' do
        code <<-EOH
        $var = dir cert:\\LocalMachine\\my | grep #{cert}
        $pos = $var.IndexOf(" ")
        $sub = $var.Substring(0,$pos)
        netsh http add sslcert ipport=#{ip}:443 certhash=$sub appid={ab3c58f7-8316-42e3-bc6e-771d4ce4b201}
        EOH
        not_if { "$var = dir cert:\\LocalMachine\\my | grep #{cert} ;; $pos = $var.IndexOf(\" \") ;; $sub = $var.Substring(0,$pos) ;; netsh http show sslcert | grep $sub -i" }
      end
    end
  end

The idea behind this method is that it should be able to automatically parse through the aws metadata service to get the IP’s assigned to a certain instance, and then assign certificates to them.

 
4
Kudos
 
4
Kudos

Now read this

Require MFA, but not for programmatic access

If you are looking for a way to enforce MFA for users when they log in to the console without limiting their programmatic access, look no further! Attach this policy to users to cut off all their access until they have logged in with... Continue →