Linuxissa palomuurina - tai tarkemmin pakettisuodattimena - käytetään netfilteriä, jota hallitaan yleensä iptables (IPv4) ja ip6tables (IPv6) komennoilla. Iptables-sääntöjen määritys Puppetissa onnistuu helpoiten puppetlabs/firewall -moduulilla. Tyypillinen käyttötapaus on portin avaaminen palomuuriin; tästä tyypillisenä esimerkkinä Puppet-Finland-projektin ::snmp::packetfilter -luokka, jossa avataan pääsy UDP-portiin 161 määritetyistä IPv4 ja IPv6-osoitteista.

Myös Windowsin palomuurisääntöjä voi muokata Puppetilla käyttämällä puppet/windows_firewall -moduulia. Kyseinen moduuli on melko yksinkertainen kääre "netsh advfirewall"-komennon ympärillä, mutta se hoitaa hommansa hyvin.

Linuxissa koko palomuurisäännöstö on helppo pitää ruodussa Puppetilla (ks. esim. puppetfinland/packetfilter moduuli), mutta Windowsissa on pitkälti tyytyminen sääntöjen kevyeen lisäämiseen ja muokkaamiseen. Tämä käy ilmeiseksi, kun listaa tuoreen Windows-koneen palomuurisäännöt:

PS> netsh advfirewall firewall show rule name="all"|more

Sääntöjä on valtava määrä ja niitä ovat luoneet ties mitkä sovellukset ja automatisoidut järjestelmät. Yllä oleva komento putkitetaan "more"-komennolle, jotta sääntöjä ehtisi ylipäätään lukea. Joka tapauksessa sääntöjen täydellinen hallinta Puppetilla olisi vähintäänkin haastavaa jos minkään ei haluttaisi rikkoutuvan. Tämä ei kuitenkaan mitenkään estä yksittäisten lisäsääntöjen luontia Puppetilla - alla hieman muokattu esimerkki puppetfinland/windows_snmp -moduulin palomuurisäännöistä:

 ::windows_firewall::exception { 'windows_snmp':
 ensure => 'present',
 direction => 'in',
 action => 'Allow',
 enabled => 'yes',
 protocol => 'UDP',
 local_port => '161',
 remote_ip => '10.50.10.15',
 display_name => 'SNMP-in from 10.50.10.15',
 description => "Allow SNMP connections",
 }

Display-name-parametrin oletusarvona on resurssin nimi ($title) ja siihen kannattaa lisätä säännöstä niitä parametreja, joiden voidaan olettaa muuttuvan, esimerkiksi remote_ip. Tämä siksi, että Puppet tajuaisi luoda uuden säännön, jos kyseinen parametri muuttuu.

Aivan kuten Linuxissakin pitää Puppetin luomia sääntöjä aika ajoin tarkistaa tai debugata. Puppetin luoman säännön saa esille antamalla name-parametriksi ::windows_firewall-resurssin parametrin display_name arvon:

PS> netsh advfirewall firewall show rule name="SNMP-in from 10.50.10.15"
 
 Rule Name: SNMP-in from 10.50.10.15
 ----------------------------------------------------------------------
 Enabled: Yes
 Direction: In
 Profiles: Domain,Private,Public
 Grouping:
 LocalIP: Any
 RemoteIP: 10.50.10.15/32
 Protocol: UDP
 LocalPort: 161
 RemotePort: Any
 Edge traversal: No
 Action: Allow
 Ok.

Mikäli Puppetin luomassa säännössä on jotakin vikaa, voidaan se poistaa helposti:

PS> netsh advfirewall firewall delete rule name="SNMP-in from 10.50.10.15"

Puppet on jo pitkään tukenut Windowsia. Monet natiivit Puppet-resurssit, kuten File, Package ja Service ovat jo pitkään toimineet sekä *NIX-käyttöjärjestelmissä että Windowsissa. Lisäksi osa natiiveista Puppet-resursseista, kuten Registry on suunniteltu pelkästään Windows-käyttöön.

Puppetin käyttömukavuus Windows-järjestelmien ylläpidossa on parantunut mutkan kautta muutamien uusien teknologioiden myötä:

  1. Powershell DSC
  2. Chocolatey
  3. Powershell Exec provider

Powershell DSC perustuu resurssien tilan hallintaan, aivan kuten Puppetkin. Mikä parasta, Puppet-koodissa voi käyttää natiivien Puppet-resurssien lisäksi Powershell DSC-resursseja. Puppetlabsin blogikirjoitus on hyvä alustus tähän aiheeseen. DSC vaatii toimiakseen Powershell 5.0:n, joka tulee Windows Management Framework 5.0:n mukana.

Chocolatey on pakettienhallintajärjestelmä sekä julkinen pakettivarasto Windowsille. Se perustuu Nuget-teknologiaan, jolla ohjelmistokehittäjät ovat perinteisesti asentaneet .NET-sovellusten kirjastoriippuvuuksia. Chocolatey siis laajentaa Nugetista, ohjelmistokehittäjien työkalusta, järjestelmäylläpitäjien työkalun. Käytännössä Chocolatey mahdollistaa Windows-sovelluksien asentamisen komentoriviltä samaan tapaan kuin apt-get Ubuntuissa ja Debianeissa. Hyödyllisimmillään Chocolatey on silloin, kun sitä käytetään Puppetista käsin niin sanottuna Package providerina.

Viimeisenä tulee Powershell Exec provider, jolla voidaan ajaa Powershell-skriptejä Puppetin natiivilla Exec-resurssilla.

Kaikkien kolmen käyttö Puppetissa on varsin yksinkertaista. Alla oletetaan, että Puppetserver on toimintakunnossa ja Windows-kone on liitetty siihen. Aluksi lisätään tarvittavat Puppet-moduulit Puppetserverin modules-hakemistoon:

$ git clone https://github.com/chocolatey/puppet-chocolatey chocolatey
 $ git clone https://github.com/puppetlabs/puppetlabs-dsc.git dsc
 $ git clone https://github.com/puppetlabs/puppetlabs-powershell powershell
 $ git clone https://github.com/Puppet-Finland/puppet-wmf wmf

Moduuleista viimeinen asentaa Windows Management Framework 5.0:n Chocolateyllä.

Tämän jälkeen Windows-koneen yaml-tiedostoon Hierassa lisätään luokka "wmf":

classes:
 - wmf

Seuraavan Puppet-ajon jälkeen Powershell DSC, Chocolatey Package provider ja Powershell Exec provider ovat valmiita käytettäväksi. Niiden toiminnan voi varmistaa luomalla yksinkertaisen Puppet-moduulin Puppetmasterin modules-kansioon:

$ cd <modules-dir>
 $ mkdir -p windowstest/manifests

Sitten luodaan tekstitiedosto dsctest/manifests/init.pp, jonka sisältö voi olla vaikka seuraavanlainen:

#
 class windowstest {
 
 dsc_file { 'test':
 dsc_ensure => 'present',
 dsc_destinationpath => 'C:dsc_testfile.txt',
 dsc_contents => 'foobar',
 }
 exec { 'testexec':
 provider => 'powershell',
 command => 'Add-Content -Path C:exec_testfile.txt
 -Value foobar',
 creates => 'C:exec_testfile.txt',
 }
 package { 'notepadplusplus':
 ensure => 'present',
 provider => 'chocolatey',
 }
 }

Sitten muokataan Windows-koneen yaml-tiedostoa Hierassa:

classes:
 - wmf
 - windowstest

Lopuksi Windows-koneelta voidaan tarkistaa onko Notepad++ asentunut ja onko Puppet luonut tekstitiedostot DSC:llä ja Powershell Exec providerilla:

> Test-Path 'C:Program FilesNotepad++'
 True
 > Get-Content C:dsc_testfile.txt
 foobar
 > Get-Content C:exec_testfile.txt
 foobar

Vagrant on erittäin kätevä työkalu kehitys- ja testausympäristöjen rakentamiseen. Sillä voidaan helposti ja toistettavasti luoda virtuaalikoneita, joiden asetukset säädetään halutunlaisiksi provisioning-vaiheessa esimerkiksi skripteillä (shell, powershell) tai konfiguraationhallintatyökaluilla kuten Puppetilla. Vagrantin taustalla on yleensä käytössä Oraclen Virtuabox, mutta myös muita virtualisointialustoja tuetaan ns. providerien avulla.

Vagrantilla luodut virtuaalikoneen on myös helppo verkottaa keskenään. Vagrant toimiikin siten hyvin palvelinympäristöjen testauksessa; hyvänä esimerkkinä käy puppet-ipa -moduuli, jossa Vagrantilla luodaan FreeIPA multi-master -palvelinympäristö sekä useita asiakaskoneita eri käyttöjärjestelmillä. Toinen hyvä esimerkki on puppet-bacula -moduuli, jossa Vagrantilla luodaan täydellinen Bacula-varmuuskopiointiympäristö.

Koska virtuaalikoneet asentuvat ja konfiguroituvat automaattisesti, voidaan ne tuhota ja rakentaa uudelleen jos ne pääsevät soseutumaan. Lisäksi kullakin kehittäjällä tai sysadminilla voi olla oma testiympäristönsä, jonka rikkominen ei vaikuta kehenkään muuhun, saati tuotannossa oleviin palveluihin, millä onkin todistetusti stressiä alentava vaikutus. Vagrant onkin hyvä ottaa esimerkiksi työnkulun osaksi esimerkiksi Puppet-moduuleja kehitettäessä - etenkin silloin, kun moduulit ovat erityisen monimutkaisia, kuten yllä mainitut puppet-ipa tai puppet-bacula.

Vagrant luo virtuaalikoneita ns. boxeista eli virtuaalikonekuvista. Vaikka julkisia boxeja onkin saatavilla suuri määrä, on toisinaan tarpeen luoda myös omia boxeja. Työkaluna tähän käytetään Packeria, jonka käyttöä voi helpottaa valmiilla Boxcutter-templateita.

Esimerkiksi Windows-boxin luonti WIndows Server 2012r2:n evaluointiversion pohjalta 64-bittisessä Linuxissa onnistuu melko helposti. Ensin asennetaan Packer:

$ wget https://releases.hashicorp.com/packer/1.1.3/packer_1.1.3_linux_amd64.zip
 $ unzip packer_1.1.3_linux_amd64.zip
 $ chown john:john packer
 $ chmod 755 packer
 $ mv packer /usr/local/bin
Nyt packer on asennettu. Packerin versionumero epäilemättä vaihtuu ajan saatossa, mutta tällä hetkellä tämä 1.1.3 on uusin versio. Seuraavaksi ladataan Windowsin Boxcutter-tiedosto:
$ git clone https://github.com/boxcutter/windows boxcutter-windows
 $ cd boxcutter-windows
Tässä hakemistossa on lukuisia Packerin json-muotoisia template-tiedostoja. Kustakin templatesta voidaan luoda boxeja eri Vagrant providereille (esim. Virtualbox ja VMWare).
Tämän jälkeen Windows-boxin luonti onkin hyvin suoraviivaista:
$ make virtualbox/eval-win2012r2-standard
Lopputuloksena syntyy Vagrant box:
$ ls box/virtualbox
 eval-win2012r2-standard-nocm-1.0.4.box
Tähän boxiin voidaan sitten viitata Vagrantfile-tiedostossa. Tästä lisää myöhemmin.

Windowsissa voidaan käyttää hosts-tiedostoa ip-osoitteiden ja nimien liittämiseen toisiinsa, aivan kuten Linuxissakin. Linuxissa tiedoston sijainti on /etc/hosts, Windowsissa se on c:windowssystem32driversetchosts, tai oikeastaan $env:windirsystem32driversetchosts.

Hosts-tiedoston käyttäminen tulee ajankohtaiseksi silloin kun sovellus tarvitsee DNS-nimen, eikä DNS-palvelinta ole käytettävissä, tai sitä ei voida jostakin syystä käyttää.

Jos Puppet agentille ei ole määritetty palvelinta, se yrittää oletuksena yhteyttä palvelimeen jonka DNS-nimi on 'puppet', eli jos palvelimelle on määritetty domain 'example.com', agent hakee palvelinta jonka DNS-nimi on 'puppet.example.com' Määrittämällä server-asetuksella palvelimen DNS-nimi, voidaan Puppet agent osoittaa haluttuun palvelimeen. Tämä määritetään Linuxeissa tyypillisesti uusimmissa puppet-versioissa tiedostossa /etc/puppetlabs/puppet/puppet.conf osiossa main tai agent.

servername = puppet.example.com

Olemassa olevan Windowsin hosts-tiedoston muokkaaminen esim. Notepad-ohjelmassa sujuu yleensä ongelmitta. Hosts-tiedoston muokkaaminen tai rakentaminen Powershell-koodilla sen sijaan ei välttämättä suju. Muokkaamisen tai rakentamisen jälkeen saatetaan todeta että Puppet agent ei löydä palvelinta koska palvelimen oletusnimi (puppet) tai määritetty nimi eivät käänny ip-osoitteiksi. Seuraava koodi aiheuttaa tämänkaltaisen ongelman.

$hostsFile = "$env:windirSystem32driversetchosts"
 
 if (!(Test-Path "$hostsFile")) {
 New-Item -path $env:windirSystem32driversetc -name hosts -type "file"
 Write-Host "Created new hosts file"
 }
 
 # Remove any lines containing our puppetservername
 $tempfile = $env:temp + "" + (get-date -uformat %s)
 New-Item $tempfile -type file -Force | Out-Null
 Get-Content $HostsFile | Where-Object {$_ -notmatch "$puppetServerName"} | Set-Content $tempfile
 Move-Item -Path $tempfile -Destination $HostsFile -Force
 
 # Insert name, address of puppetserver separated by a tab 
 [email protected]($puppetServerAddress,$puppetServerName)
 $myString=[string]::join("`t", (0,1 | % {$fields[$_]}))
 $found = Get-Content $hostsFile | Where-Object { $_.Contains("$myString") }
 if ([string]::IsNullOrEmpty($found)) {
 [string]::join("`t", (0,1 | % {$fields[$_]})) | Out-File -encoding ASCII -append $hostsFile
 }

Eli ensin määritetään hosts-tiedoston sijainti. Jos tiedostoa ei ole olemassa, se luodaan. Seuraavaksi luodaan väliaikainen tiedosto, jonka sisältö haetaan olemassa olevasta hosts-tiedostosta, samalla poistaen nykyiset rivit jotka sisältävät palvelimen nimen (saatu parametrina). Muokattu tiedosto siirretään sitten oikeaan paikkaan. Tämän jälkeen tiedostoon lisätään palvelimen nimi ja ip-osoite (jotka saatu parametreinä).

Jos nyt tarkastellaan hosts-tiedostoa silmämääräisesti, se vaikuttaa olevan ok. Vaikka Puppet-palvelin on käytettävissä, agentin (ensimmäinen) ajo manuaalisesti tuottaa virheen.

Error: Could not request certificate: getaddrinfo: No such host is known.
 Exiting; failed to retrieve certificate and waitforcert is disabled

Samoin ping tuottaa virheen.

Ping request could not find host puppet.example.com. Please check the name and try again.

Tämä johtuu siitä että nimi puppet.example.com ei ratkea ip-osoitteeksi vaikka se on asianmukaisesti määritetty hosts-tiedostossa. Mistä on kyse?

Windows hosts-tiedoston ongelmat eivät ole aivan harvinaisia, ja näiden ongelmien etsiminen Googlella tuottaa paljon hakutuloksia, esim. tämän. Tarkistettavina asioina esitetään nimien resoluution välimuistia, enkoodausta, ylimääräisiä sarkaimia tai välilyöntejä jne.

Koska tässä artikkelissa on kyse Powershellistä, haluamme selvittää mistä ongelmassa on kyse, ja myös korjata ongelman Powershell-koodilla.

Ongelman syy on siinä että muokkaamalla hosts-tiedostoa edellä mainitulla Powershell-koodilla sen käyttöoikeudet, 'security descriptorit' jäävät vajaiksi. Muokkaamalla oikeudet asianmukaisiksi powershell-koodilla nimet ratkeavat oikein ip-osoitteiksi.

# Create access rule
 $userName = "Users"
 $rule = New-Object System.Security.AccessControl.FileSystemAccessRule("$userName", 'Read', 'Allow')
 
 # Apply access rule
 $acl = Get-ACL $hostsFile
 $acl.SetAccessRule($rule)
 Set-Acl -path $hostsFile -AclObject $acl

Annetaan siis ryhmälle 'Users' lukuoikeus tiedostoon. Tämä oikeus puuttuu, jos hosts-tiedostoa muokataan aiemman Powershell-koodin mukaan. Tämän lukuoikeuden antaminen riittää saattamaan nimiresoluution toimivaksi.

Tässä kokonainen toimiva funktio.

function SetupHostsFile {
 
 param(
 [IPADDRESS]$puppetServerAddress,
 [String]$puppetServerName
 )
 
 if ($debug) {
 write-host ("Now in function {0}." -f $MyInvocation.MyCommand)
 }
 
 
 If (-Not [BOOL]($puppetServerAddress -as [IPADDRESS])) {
 write-host ("{0} is not an IP address" -f $puppetServerAddress)
 break
 }
 
 $fqdnRe='(?=^.{4,253}$)(^((?!-)[a-zA-Z0-9-]{1,63}(?<!-).)+[a-zA-Z]{2,63}$)'
 
 If ($puppetServerName -notmatch $fqdnRe) {
 write-host ("{0} is not a fully qualified name" -f $puppetServerName)
 break
 }
 
 write-host "Setting up hosts file..."
 
 $hostsFile = "$env:windirSystem32driversetchosts"
 
 if (!(Test-Path "$hostsFile")) {
 New-Item -path $env:windirSystem32driversetc -name hosts -type "file"
 Write-Host "Created new hosts file"
 }
 
 # Remove any lines containing our puppetservername
 $tempfile = $env:temp + "" + (get-date -uformat %s)
 New-Item $tempfile -type file -Force | Out-Null
 Get-Content $HostsFile | Where-Object {$_ -notmatch "$puppetServerName"} | Set-Content $tempfile
 Move-Item -Path $tempfile -Destination $HostsFile -Force
 
 # Insert name, address of puppetserver separated by a tab 
 [email protected]($puppetServerAddress,$puppetServerName)
 $myString=[string]::join("`t", (0,1 | % {$fields[$_]}))
 $found = Get-Content $hostsFile | Where-Object { $_.Contains("$myString") }
 if ([string]::IsNullOrEmpty($found)) {
 [string]::join("`t", (0,1 | % {$fields[$_]})) | Out-File -encoding ASCII -append $hostsFile
 }
 
 # Create access rule
 $userName = "Users"
 $rule = New-Object System.Security.AccessControl.FileSystemAccessRule("$userName", 'Read', 'Allow')
 
 # Apply access rule
 $acl = Get-ACL $hostsFile
 $acl.SetAccessRule($rule)
 Set-Acl -path $hostsFile -AclObject $acl
 
 }

Voit lukea lisää Powershellin Set-Acl-cmdletistä täältä

Edellisessä artikkelissa rakennettiin Packerilla ja Boxcutter-templateilla Windows box Vagrant-käyttöön. Tässä artikkelissa näytetään, miten Vagrantilla rakennetaan varsinaisia Windows-virtuaalikoneita.

Vagrantia ohjataan Vagrantfile-tiedostolla, joka usein sijaitsee projektin (esim. Puppet-moduuli) päähakemistossa. Jopa hyvin yksinkertainen Vagrantfile riittää Windows-virtuaalikoneen pystyttämiseen:

# -*- mode: ruby -*-
 # vi: set ft=ruby :
 
 Vagrant.configure("2") do |config|
 config.vm.define "win2012r2" do |box|
 box.vm.box = "mwrock/Windows2012R2"
 box.vm.box_version = "0.6.1"
 box.vm.hostname = "windows2012r2a"
 box.vm.network "private_network", ip: "192.168.31.101"
 box.vm.provider "virtualbox" do |vb|
 # Poistetaan Virtualboxin konsolinäkymä käytöstä
 vb.gui = false
 vb.memory = 2048
 end
 end
 end

Yllä käytetään erästä julkista Windows 2012r2 boxia. Aivan yhtä hyvin voitaisiin käyttää aiemmassa artikkelissa Packerilla luotua boxia tähän tapaan:

box.vm.box = "/home/samuli/opt/boxcutter-windows/box/virtualbox/eval-win2012r2-standard-nocm-1.0.4.box"

Kun Vagrantfile on luotu, rakennetaan virtuaalikone:

$ vagrant up
 Bringing machine 'win2012r2' up with 'virtualbox' provider...
 ==> win2012r2: Importing base box 'mwrock/Windows2012R2'...
 ==> win2012r2: Matching MAC address for NAT networking...
 ==> win2012r2: Checking if box 'mwrock/Windows2012R2' is up to date...
 ==> win2012r2: Setting the name of the VM: vagrant-win2012r2_win2012r2_1516105136632_99055
 ==> win2012r2: Clearing any previously set forwarded ports...
 ==> win2012r2: Clearing any previously set network interfaces...
 ==> win2012r2: Preparing network interfaces based on configuration...
 win2012r2: Adapter 1: nat
 win2012r2: Adapter 2: hostonly
 ==> win2012r2: Forwarding ports...
 win2012r2: 3389 (guest) => 3389 (host) (adapter 1)
 win2012r2: 5985 (guest) => 55985 (host) (adapter 1)
 win2012r2: 5986 (guest) => 55986 (host) (adapter 1)
 win2012r2: 22 (guest) => 2222 (host) (adapter 1)
 ==> win2012r2: Running 'pre-boot' VM customizations...
 ==> win2012r2: Booting VM...
 ==> win2012r2: Waiting for machine to boot. This may take a few minutes...
 win2012r2: WinRM address: 127.0.0.1:55985
 win2012r2: WinRM username: vagrant
 win2012r2: WinRM execution_time_limit: PT2H
 win2012r2: WinRM transport: negotiate
 ==> win2012r2: Machine booted and ready!
 Sorry, don't know how to check guest version of Virtualbox Guest Additions on this platform. Stopping installation.
 ==> win2012r2: Checking for guest additions in VM...
 ==> win2012r2: Setting hostname...
 ==> win2012r2: Configuring and enabling network interfaces...
 ==> win2012r2: Mounting shared folders...
 win2012r2: /vagrant => /home/samuli/opt/vagrant-win2012r2

Virtuaalikone on nyt käytettävissä:

$ vagrant status
 Current machine states:
 
 win2012r2 running (virtualbox)
 
 The VM is running. To stop this VM, you can run `vagrant halt` to
 shut it down forcefully, or you can run `vagrant suspend` to simply
 suspend the virtual machine. In either case, to restart it again,
 simply run `vagrant up`.

Teoriassa koneeseen pitäisi pystyä nyt yhdistämään "vagrant rdp"-komennolla. Näin ei kuitenkaan ole, kuten on helppo todeta:

$ vagrant rdp
 ==> win2012r2: Detecting RDP info...
 win2012r2: Address: 127.0.0.1:3389
 win2012r2: Username: vagrant
 ==> win2012r2: Vagrant will now launch your RDP client with the connection parameters
 ==> win2012r2: above. If the connection fails, verify that the information above is
 ==> win2012r2: correct. Additionally, make sure the RDP server is configured and
 ==> win2012r2: running in the guest machine (it is disabled by default on Windows).
 ==> win2012r2: Also, verify that the firewall is open to allow RDP connections.

Vagrant jumittaa tässä pisteessä ilman mitään ilmiselvää syytä ja tilanteen saa purettua vain CTRL-C -komennolla.

Ongelman aiheuttaa se, että "vagrant rdp" ei osaa hyväksyä virtuaalikoneen RDP-palvelimen julkista avainta, joten ongelman voi kiertää yhdistämällä virtuaalikoneeseen ensin käsin. Olettaen, että käytetään Linuxia, kannattaa asentaa Vagrant-käyttöön xfreerdp. Sen asentaminen lähdekoodista on melko suoraviivaista, mutta se löytyy monien Linux-jakelujen pakettivarastoista suoraankin.

Yhdistäminen Vagrant-virtuaalikoneeseen onnistuu helposti, koska oletuksena Windows-virtuaalikoneen portti 3389 välitetään isäntäkoneen porttiin 3389:

$ xfreerdp /u:vagrant /p:vagrant /v:127.0.0.1
 [14:45:39:912] [7041:7042] [INFO][com.freerdp.client.common.cmdline] - loading channelEx cliprdr
 [14:45:39:933] [7041:7042] [ERROR][com.freerdp.crypto] - @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 [14:45:39:933] [7041:7042] [ERROR][com.freerdp.crypto] - @ WARNING: CERTIFICATE NAME MISMATCH! @
 [14:45:39:933] [7041:7042] [ERROR][com.freerdp.crypto] - @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 [14:45:39:933] [7041:7042] [ERROR][com.freerdp.crypto] - The hostname used for this connection (127.0.0.1:3389) 
 [14:45:39:933] [7041:7042] [ERROR][com.freerdp.crypto] - does not match the name given in the certificate:
 [14:45:39:933] [7041:7042] [ERROR][com.freerdp.crypto] - Common Name (CN):
 [14:45:39:933] [7041:7042] [ERROR][com.freerdp.crypto] - windows2012r2a
 [14:45:39:933] [7041:7042] [ERROR][com.freerdp.crypto] - A valid certificate for the wrong name should NOT be trusted!
 Certificate details:
 Subject: CN = windows2012r2a
 Issuer: CN = windows2012r2a
 Thumbprint: 6e:b7:b8:e2:b3:ab:3d:13:eb:9b:aa:66:8f:4f:7c:70:
 32:a9:49:33
 The above X.509 certificate could not be verified, possibly because you do not have the CA certificate in your certificate store, or the certificate has expired. Please look at the OpenSSL documentation on how to add a private CA to the store.

Xfreerdp:n varoituksista ei tässä yhteydessä kannata välittää, vaan vastata "Y(es)":

Do you trust the above certificate? (Y/T/N) Y

Tämän jälkeen "vagrant rdp" toimii niinkuin kuuluukin, eli avaa suoraan RDP-ikkunan ajettaessa "vagrant rdp".

Kun virtuaalikonetta ei enää tarvita, voidaan se sammuttaa:

$ vagrant halt
 ==> win2012r2: Attempting graceful shutdown of VM...

Jos kone halutaan tuhota kokonaan, käytetään "vagrant destroy"-komentoa:

$ vagrant destroy
 win2012r2: Are you sure you want to destroy the 'win2012r2' VM? [y/N] y
 ==> win2012r2: Destroying VM and associated drives...

Kone voidaan tuhoamisen jälkeen uudelleenrakentaa puhtaalta pöydältä ajamalla "vagrant up"-komento.

Vagrantin shell-provisioner tukee suoraan Powershell-skriptejä. Toisin sanoen Windows-virtuaalikoneen asetuksia voi muokata Powershellillä ilman, että tarvitsee rakentaa uusi virtuaalikonekuva. Tyypillinen esimerkki on Windows liittäminen konfiguraationhallintajärjestelmään kuten Puppetiin.

Vagrantin dokumentaatiossa mainitaan, että Powershell-skriptille voi välittää parametreja powershell_args -valinnalla joko merkkijonona (string) tai listana (array). Esimerkkejä etenkin Powershell-provisioinnista on kuitenkin heikosti, mistä syystä tämäkin blogipostaus on kirjoitettu. Otetaan esimerkkinä skripti bootstrap_windows.ps1, joka liittää Windows-virtuaalikoneen olemassa olevaan Puppetserveriin. Sitä käytetään käsin Powershellistä seuraavasti:

> .bootstrap_windows.ps1 -certName win2012r2.local
 -ServerName puppet.local
 -puppetServerAddress 192.168.137.10

Rivinvaihdot on lisätty selvyyden vuoksi.

Jos bootstrap_windows.ps1 skripti halutaan ajaa suoraan Vagrantissa, tehdään se seuraavasti:

# -*- mode: ruby -*-
 # vi: set ft=ruby :
 
 Vagrant.configure("2") do |config|
 
 config.vm.define "win2012r2" do |box|
 box.vm.box = "mwrock/Windows2012R2"
 box.vm.box_version = "0.6.1"
 box.vm.hostname = "windows2012r2a"
 box.vm.network "private_network", ip: "192.168.31.101"
 box.vm.provider "virtualbox" do |vb|
 vb.gui = false
 vb.memory = 2048
 end
 box.vm.provision "shell" do |s|
 s.path = "bootstrap_windows.ps1"
 s.args = ["-certName", "win2012r2.local",
 "-ServerName", "puppet.local",
 "-puppetServerAddress", "192.168.31.1"]
 end
 end
 end

Huomaa, miten kukin parametri ja parametrin arvo on lisätty listaan erillisenä merkkijonona; syystä tai toisesta esimerkiksi "-certName win2012r2.local" ei toimi.

Alla tukku hyödyllisiä komentoja Samban debuggaukseen. Oletus on, että Samba AD DC ja Domain Member-palvelinten konfiguraatiot ovat pääosin kunnossa. Tähän pisteeseen päästään helpohkosti Puppet-Finland -projektin samba4-moduulilla. Täysin hands off -asennus on varsin haastava, joten debuggaustyökaluille tulee väistämättä tarvetta.

Tarkistetaan, onko member-nimisellä koneella jo machine account Samban LDAP:ssa, eli onko se jo liitetty domainiin:

$ net ads dn 'CN=member,CN=Computers,DC=smb,DC=domain,dc=com' cn -U administrator%password
 Got 1 replies
 
 cn: member

Tässä eräs toinen tapa selvittää, onko member-kone liitetty domainiin. Tähän vaaditaan Debianissa ldb-tools -paketin asentaminen ja komento on ajettava DC-koneella:

 ldbsearch -H /var/lib/samba/private/sam.ldb.d/DC=SMB,DC=DOMAIN,DC=COM.ldb 'servicePrincipalName=HOST/Member'

Member-koneen liittäminen (Samba) Active Directory Domain Controlleriin:

$ net ads join -U administrator%password
 Using short domain name -- SMB
 Joined 'MEMBER' to dns domain 'smb.domain.com'

Member-koneen poistaminen domainista:

$ net ads leave -U administrator%password
 Deleted account for 'MEMBER' in realm 'SMB.DOMAIN.COM

Levyjaon (testshare) toimivuuden varmistaminen:

$ smbclient //member.smb.domain.com/testshare -UAdministrator%password -c 'ls'
 
 Domain=[SMB] OS=[Windows 6.1] Server=[Samba 4.2.14-Debian]
 . D 0 Tue Dec 20 18:40:13 2016
 .. D 0 Wed Dec 21 10:44:14 2016
 
 9717280 blocks of size 1024. 8038660 blocks available

Debian 8:ssa samba-ad-dc -palvelun käynnistys ei aina näyttäisi käynnistävän Samban Kerberos-palvelua, joka kuuntelee TCP-portissa 88. Ilman Kerberosta AD DC ei tietenkään toimi, joten sen toimivuuden voi tarkistaa esim. seuraavasti:

$ netstat -plnt|grep :88
 tcp 0 0 0.0.0.0:88 0.0.0.0:* LISTEN 668/samba
 tcp6 0 0 :::88 :::* LISTEN 668/samba

Tätä lähestymistapaa käytetään myös samba4-puppet-moduulin samba-ad-dc.monit.erb -tiedostossa.

Toinen, vielä varmempi tapa varmistua Kerberoksen toiminnasta on pyytää siltä tiketti:

$ kinit administrator
 Password for [email protected]:
 Warning: Your password will expire in 41 days on Tue 31 Jan 2017 05:31:40 PM EET

Jos Kerberos ei ole käynnissä, on syytä käynnistää koko samba-ad-dc -palvelu uudelleen:

$ systemctl restart samba-ad-dc

Member-koneilla, joille halutaan kirjautua AD-käyttäjinä, tarvitaan winbind-palvelu, joka on integroitava Linuxin PAM-järjestelmään (pluggable authentication modules). Winbindin toiminnan voi varmistaa getent -komennolla:

$ getent passwd|grep krbtgt
 krbtgt:*:10502:10513:krbtgt:/home/SMB/krbtgt:/bin/bash

Jos winbind ei toimi oikein, yllä oleva komento ei tulosta mitään.

Yleensä halutaan myös sallia sshd:n autentikoida käyttäjät Kerberoksella. Tähän riittää pieni lisäys /etc/ssh/sshd_config -tiedostoon:

KerberosAuthentication yes

AD-käyttäjien oikeudet voi selvittää seuraavasti:

$ net rpc rights list accounts -U administrator%password -I dc1.smb.domain.com
 BUILTINPrint Operators
 SeLoadDriverPrivilege
 SeShutdownPrivilege
 SeInteractiveLogonRight
 
 BUILTINAccount Operators
 SeInteractiveLogonRight
 
 --- snip ---
 
 BUILTINPre-Windows 2000 Compatible Access 
 SeRemoteInteractiveLogonRight 
 SeChangeNotifyPrivilege

Oikeuksia voidaan lisätä seuraavasti:

$ net rpc rights grant 'SMBDomain Admins' SeDiskOperatorPrivilege -U administrator%password -I dc1.smb.domain.com

Ei pidä myöskään unohtaa systemctl-komentoja kuten

$ systemctl status samba-ad-dc
 $ journalctl -n 0 -f --unit=samba-ad-dc
 $ journalctl -n 50 /usr/sbin/winbind

Lopuksi vielä tukku hyödyllisiä linkkejä debuggauksen avuksi:

Windowsin järjestelmätiedostoja ei useinkaan pysty muuttamaan käsin - tai Puppetilla - ilman niiden suojaustason alentamista. Ongelma on siinä, että järjestelmätiedostojen omistaja on usein (pseudo)käyttäjä "TrustedInstaller", eikä edes administrator-tason käyttäjillä ole niihin kirjoitusoikeutta. Onneksi rajoitukset voi kiertää melko suoraviivaisesti käyttämällä takeown.exe -komentoa sekä puppetlabs/acl -moduulia. Alla on muokattu erästä Group Policyn XML-tiedostoa, jonka merkistökoodaus oli siinä määrin poikkeuksellinen, että sen lukeminen Rubyn reXML -kirjastolla ei onnistunut:

include ::acl
 
 # Vaihda tiedoston omistaja
 exec { 'takeown-Search.admx':
 command => 'C:WindowsSystem32takeown.exe /f C:WindowsPolicyDefinitionsSearch.admx',
 }
 
 # Määritä uudet oikeudet
 acl { 'Search.admx':
 target => 'C:/Windows/PolicyDefinitions/Search.admx',
 permissions => [
 { identity => 'Järjestelmänvalvojat', rights => ['full'] },
 { identity => 'SYSTEM', rights => ['full'] }
 ],
 require => Exec['takeown-Search.admx'],
 }
 
 # Korvaa tiedosto
 file { 'C:/Windows/PolicyDefinitions/Search.admx':
 source => 'puppet:///modules/winpolicydefinitions/Search.admx',
 require => Acl['Search.admx'], 
 }

Tästä prosessista kannattaisi muokata oma määritelty resurssinsa, tai jopa peräti oma tyyppinsä, mikäli sille löytyisi runsaasti käyttöä. Takeown-komentoon kannattaisi lisätä myös "unless"-parametri, jotta sitä ei ajeta turhaan joka kerta. Jos Execissä olisi "provider => 'powershell'", niin tarkistuksen voisi tehdä muutamin eri tavoin.

Monia Windowsien asetuksia on perinteisesti muokattu ryhmäkäytänteillä ("Group Policy"). Vaikka ryhmäkäytänteiden teho onkin melko rajallinen, pystyy niillä tekemään yhtä ja toista. Microsoft on kuitenkin Powershell DSC:n kuitenkin siirtymässä tilan hallintaan perustuviin modernimpiin ratkaisuja, joten Group Policyt jäänevät lähivuosina historiaan.

Tästä huolimatta ryhmäkäytänteitä hyödynnetään yhä erityisesti Active Directory -toimialueiden ("domain") kanssa silloin, kun halutaan standardisoida työasemien asetuksia. Myös Samba 4 tukee ryhmäkäytänteiden jakelua työasemille. Ryhmäkäytänteet eivät kuitenkaan vaadi Active Directoryn tai Samba 4:n käyttöä, sillä käytänteitä voidaan määrittää paitsi verkkoalueelle, myös paikallisesti ("Local Group Policy"). Käytänteet voidaan lisäksi jakaa käyttäjäkohtaisiin ("User policy") ja tietokonekohtaisiin ("Machine policy").

Windows 7:ssa paikalliset ryhmäkäytänteet säilötään kahdessa tiedostossa:

  1. C:WindowsSystem32GroupPolicyUserRegistry.pol ("User Policy")
  2. C:WindowsSystem32GroupPolicyMachineRegistry.pol ("Machine Policy")

Nämä tiedostot ovat - yllättävää kyllä - yksinkertaisia yhden rivin tekstitiedostoja. Alla esimerkki UserRegistry.pol -tiedostosta, joka jaettu selvyyden vuoksi usealle riville:

PReg
 
 [SoftwareMicrosoftWindowsCurrentVersionPoliciesActiveDesktop;NoChangingWallPaper;;;]
 
 [SoftwareMicrosoftWindowsCurrentVersionPoliciesSystem;Wallpaper;;F;c:background.jpg]
 
 [SoftwareMicrosoftWindowsCurrentVersionPoliciesSystem;WallpaperStyle;;;4]
 
 [SoftwarePoliciesMicrosoftWindowsControl PanelDesktop;ScreenSaveActive;;;1]

Kukin käytänne määrittää jonkin rekisteriavaimen sisällön, joten periaatteessa lienee mahdollista muokata rekisteriavaimien arvoja myös suoraan esim. puppetlabs/registry-moduulilla. Registry.pol -tiedoston hakemiston nimi (Machine tai User) määrää sen, sijoitetaanko rekisteriavain HKEY_LOCAL_MACHINE vai HKEY_CURRENT_USER -haaraan.

Registry.pol -tiedoston syntaksi on hyvin määritelty, joten sen muokkaaminen käsin tai Puppetilla on helpohkoa. Jokainen käytänne on eroteltu hakasulkein ja sillä on 1-5 parametria:

[key;value;type;size;data]

Kuten yltä näkyy, usein riittää, että key, value ja data on määritelty. Päällä/pois -tyyppisissä käytänteissä vaikuttaa riittävän se, että key ja value on määritetty.

Paikallisia ryhmäkäytänteitä muokataan normaalisti gpedit.msc -ohjelmalla (ohjeita), jolla voidaan varmistua siitä, että Registry.pol -tiedoston sisältö ja syntaksi on kunnossa. Tiedoston sisältö muuttuu sitä mukaa, kun gpedit.msc:llä lisätään, muutetaan tai poistetaan käytänteitä. Mikäli muutoksia tehdään muulla kuin gpedit.msc:llä, pitää ne ottaa käyttöön gpupdate.exe -ohjelmalla:

> gpupdate.exe /force

Valmiin Registry.pol -tiedoston jakelu onnistuu yksinkertaisimmillaan File-resurssilla:

file { 'local-group-policy':
 ensure => 'present',
 name => 'C:WindowsSystem32GroupPolicyUserRegistry.pol',
 source => 'puppet:///modules/windesktop/Registry.pol',
 }

Tässä lähestymistavassa policy-tiedostojen ylläpito muuttuu helposti työlääksi, sillä pienikin muutos vaatii täysin uuden tiedoston luomisen. Jos käytänteet ovat identtisiä tai lähes identtisiä joka koneella, ei tästä ole juuri haittaa.

Skaalautuvampi lähestymistapa olisi muokata Registry.pol-tiedoston yksittäisiä käytänteitä. Käytänteiden määrittämiseen on olemassa oma Puppet-moduulikin, cannonps/local_group_policy, josta PuppetLabs paikutti aikoinaan kovastikin henkseleitä. Moduulin sisältämässä providerissa on kuitenkin lukuisia ongelmia:

Aloitin jo moduulin korjaamisen, mutta onneksi tajusin jättää homman (melko) ajoissa kesken huomattuani miten yksinkertainen Registry.pol -tiedoston syntaksi on.

Toistaiseksi päätin jaella staattisen Registry.pol -tiedoston käsin tarvittaville koneille. Myöhemmin tarkoituksena on kirjoittaa huomattavasti local_group_policy -moduulia yksinkertaisempi provider, joka muokkaa Registry.pol -tiedoston sisältöä suoraan.

menucross-circle