Published on 5 September 2019 by

At Puppet, we manage the infrastructure that our development teams use for testing new features. Recently a team needed a bare-metal Hyper-V server for testing containers on windows. This was our first venture managing Hyper-V on windows, and we wanted to share with our customers the code we wrote, and some of the best core windows modules we have on the forge for configuring those servers.

Enabling WinRM with SSL

WinRM is windows native remote management solution, similar to SSH on Linux. We of course wanted to ensure that we were connecting to this windows server securely, so we needed a way to manage an SSL certificate.

There are a few existing modules on the forge, but we decided to open source a new module, that more natively handled the importing of the Windows Certificates, without having to manage the passphrase in Puppet. This open-source module, built and tested by Puppet engineers and used internally by multiple teams, is available now.

Get the module: PuppetLabs Windows Puppet Certificates.

Practical Uses for the Windows Puppet Certificate Module include:

  • Client certificate based authentication in EAP in 802.1x
  • Automatically trusting the PE Console in web browsers
  • Encrypting secrets for the client to consume, for example Hiera eYaml
  • Encrypting secrets for the server to consume, for example encrypting Bitlocker keys
  • For example, you could use it to manage the certificates for SSL winrm

We enabled winrm, using the installed puppet certificate.

mod 'nekototori-winrmssl',                        '0.1.0'
mod 'puppetlabs-windows_puppet_certificates'      '0.1.0'

class profile::os::windows::winrm {
  class { 'windows_puppet_certificates':
    manage_master_cert => true,
    manage_client_cert => true,
  }

  unless $facts['puppet_cert_paths']['ca_path'] {
    fail('The "puppet_cert_paths/ca_path" fact from the "puppetlabs-windows_puppet_certificates" module is missing')
  }

  winrmssl { $facts['puppet_cert_paths']['ca_path']:
    ensure  => present,
    issuer  => $facts['puppet_cert_paths']['ca_path'],
    require => Windows_puppet_certificates::Windows_certificate['puppet_master_windows_certificate'],
  }

Here we’re creating winrm, using the certificates installed by the “windows_puppet_certificates” module. Additionally, in order to catch the removal of the module without the removal of the custom fact, we check to ensure that the fact is defined and fail if it is not.

NIC Teaming

The server we were working on had four network interfaces, and one of our requirements was to create two bonded interfaces, each comprised of two of the regular interfaces. Along with this requirement, we needed to assign a static IP and gateway for just one of the bonded interfaces (the other one is used internally by Hyper-V). This part was accomplished with the puppetlabs-dsc_lite Puppet module, the “NetworkingDsc” Powershell module and some defined types.

We added these modules to our Puppetfile:

mod 'hbuckle-powershellmodule',                   '2.0.1'
mod 'puppetlabs-dsc_lite',                        '1.2.0'

We needed a class to install some dependencies:

class profile::network::windows_install_dsc_modules {

  pspackageprovider {'Nuget':
    ensure   => 'present',
    provider => 'windowspowershell',
    before   => Package['NetworkingDsc'],
  }

  package { 'NetworkingDsc':
    ensure   => latest,
    provider => 'windowspowershell',
    source   => 'PSGallery',
  }
}

...and a profile to configure the IPaddress and gateway (it uses the class above as a requirement):

define profile::network::windows_interface (
  Array[Stdlib::IP::Address]    $ipaddress,
  String[1]                     $interfacealias,
  Enum['IPv4','IPv6']           $addressfamily = 'IPv4',
  Optional[Stdlib::IP::Address] $gw_address = undef,
){

  include profile::network::windows_install_dsc_modules

  dsc {"${name}-ip-address":
    resource_name => 'IPAddress',
    module        => 'NetworkingDsc',
    properties    => {
      ipaddress      => $ipaddress,
      interfacealias => $interfacealias,
      addressfamily  => $addressfamily,
    },
    require       => Class['profile::network::windows_install_dsc_modules'],
  }

  if $gw_address {

    dsc {"${name}-default-gw":
      resource_name => 'DefaultGatewayAddress',
      module        => 'NetworkingDsc',
      properties    => {
        address        => $gw_address,
        interfacealias => $interfacealias,
        addressfamily  => $addressfamily,
      },
      require       => Class['profile::network::windows_install_dsc_modules'],
    }
  }
}

Another defined type would configure the network bond and optionally set an IPaddress using the class above:

define profile::network::windows_nic_team (
  String[1]                                                                  $nic_name,
  Array[String]                                                              $teammembers,
  Enum['SwitchIndependent','LACP','Static']                                  $teamingmode = 'SwitchIndependent',
  Enum['Dynamic','HyperVPort','IPAddresses','MacAddresses','TransportPorts'] $loadbalancingalgorithm = 'HyperVPort',
  Enum['IPv4','IPv6']                                                        $addressfamily = 'IPv4',
  Optional[Array[Stdlib::IP::Address]]                                       $ipaddress = undef,
  Optional[Stdlib::IP::Address]                                              $gw_address = undef,
){

  include profile::network::windows_install_dsc_modules

  dsc {$name:
    resource_name => 'NetworkTeam',
    module        => 'NetworkingDsc',
    properties    => {
      name                   => $nic_name,
      teamingmode            => $teamingmode,
      loadbalancingalgorithm => $loadbalancingalgorithm,
      teammembers            => $teammembers,
    },
    require       => Class['profile::network::windows_install_dsc_modules'],
  }

  if $ipaddress {

    profile::network::windows_interface { "set-ip-${name}":
      ipaddress      => $ipaddress,
      gw_address     => $gw_address,
      interfacealias => $nic_name,
      require        => Dsc[$name],
    }
  }
}

Putting these all together, we just needed to add this to our main profile class which configures both bonded interfaces:

 profile::network::windows_nic_team { 'nic_team1-HyperV':
    nic_name    => 'Team1 - HyperV',
    teammembers => ['NIC1', 'NIC2'],
  }

  profile::network::windows_nic_team { 'nic_team2-Vlan22':
    nic_name    => 'Team2 - VLAN 22',
    teammembers => ['NIC3', 'NIC4'],
    ipaddress   => ['10.32.22.11/23'],
    gw_address  => '10.32.22.1',
  }

Enabling Hyper-V

In order to install hyperv, we need to be able to manipulate Windows features. To do this we’ll use the puppet-windowsfeature module from the Puppet Forge. This module was also created by engineers at Puppet in collaboration with the Vox Pupuli module writing collective.

class profile::windows::hyperv {
 windowsfeature { 'Hyper-V':
   ensure => present,
 }

 reboot {'after_Hyper_V':
   when      => pending,
   subscribe => Windowsfeature['Hyper-V'],
 }
}

Learn more and try it for yourself

We provided this example because it showcased a lot of the core modules you will need in order to manage your windows servers, since some of the concepts in Windows will be fundamentally different from what you use in a Unix environment. These included:

  • puppet-windowsfeature: A module that will turn windows features on or off for Windows Server 2008 and above.
  • hbuckle-powershellmodule: Allows PowerShell repositories to be registered as package sources and PowerShell modules to be installed using the Puppet Package type.
  • puppetlabs-dsc_lite: The Puppet dsc_lite module allows you to manage target nodes using Windows PowerShell DSC (Desired State Configuration) Resources.
  • nekototori-winrmssl: Setup WinRM over HTTPS and control some basic, essential settings. Also supports Puppet CA issued certificates.
  • puppetlabs-windows_puppet_certificates: A Puppet module to import the puppet certificates into the machine certificate store in Windows.
Share via:
Posted in:
The content of this field is kept private and will not be shown publicly.

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.