Puppet - 从散列标题构建数组以检查 exec 中的内容

Puppet - build array from hash titles to check contents in exec

我正在尝试将 thoward-windows_firewall 模块应用到 Windows 10,但遇到了一个障碍,即大多数内置规则都可以用模块的清除功能清除,但其他一些(例如小娜)不能。这个问题在早期的 Windows 版本中没有发生。解决方法似乎是 运行 一个带有 'netsh advfirewall reset' 的执行程序清除它们并阻止它们重新出现。

但是,如果存在我在 Hiera 中指定的防火墙规则以外的防火墙规则,我只想应用 'netsh advfirewall reset' exec。

我的方法是在 hiera 中构建一个仅包含标题的数组(或列表),然后在 PowerShell 'only if' 或 'unless'.

中迭代它们

目前的代码(不起作用)是:

Hiera 片段:

harden::firewall:
   'Remote Desktop - User Mode (UDP-In)':
      description:      'Inbound rule for the Remote Desktop service to allow RDP traffic. [UDP 3389]'
      application_name: 'C:\Windows\system32\svchost.exe'
      service_name:     'termservice'
      protocol:         17
      local_ports:      '3389'
      remote_ports:     '*'
      local_addresses:  '%{facts.networking.ip}'
      remote_addresses: '*'
      direction:        1
      interface_types:  'All'
      enabled:          true
      grouping:         '@FirewallAPI.dll,-28752'
      profiles:         3
      action:           1

   'File and Printer Sharing (Echo Request - ICMPv4-In) 1':
      description:          'Echo Request messages are sent as ping requests to other nodes.'
      protocol:             1
      local_addresses:      '%{facts.networking.ip}'
      remote_addresses:     'LocalSubnet'
      icmp_types_and_codes: '8:*'
      direction:            1
      interface_types:      'All'
      enabled:              true
      grouping:             '@FirewallAPI.dll,-28502'
      profiles:             6
      action:               1

清单(摘录):

class harden (
Hash     $firewall_rule_names = lookup('harden::firewall'),
){

# reset firewall rules
  exec { 'reset_firewall':
    command  => 'netsh advfirewall reset',
    onlyif   => 'if (Get-NetFirewallRule | where {$_.DisplayName -notmatch $firewall_rule_names}) { exit 0 } else { exit 1 }',
    provider => powershell,
  }

  Class { 'windows_firewall':
    profile_state => 'on',
    in_policy     => 'BlockInbound',
    out_policy    => 'BlockOutbound',
    rule_key      => 'harden::firewall',
    purge_rules   => true,
  }

我知道我需要在某处查看 .each,并整理 powershell 'only if' 以便它只查看散列中的标题(可能 re-written 到只是散列标题的数组)和 运行 如果主机上有不在 Hiera 中的规则,则执行程序,但我有点迷路了。

真诚感谢任何帮助。

我发现 Only IF 语句有问题。 $_DisplayName 应该是 $_.DisplayName ,您需要使用点运算符来挑选对象的属性,并且 \ 也不是必需的。

您写道:

My approach is to build an array (or list) of only the titles in hiera and then iterate over them in a PowerShell 'only if' or 'unless'.

显然,您尝试在 class 参数 $firewall_rule_names 中构建该数组,声明如下:

Hash     $firewall_rule_names = lookup('harden::firewall'),

然后您尝试在 Exec:

onlyif 参数中使用该列表
    onlyif   => 'if (Get-NetFirewallRule | where {$_.DisplayName -notmatch $firewall_rule_names}) { exit 0 } else { exit 1 }',

这有很多问题。

首先,如果要将puppet变量插值成字符串,那么该字符串需要用双引号引起来(");用单引号引用 (') 抑制插值(并且还将 $ 视为两个文字字符,而不是转义序列)。

Second,以及您似乎不知所措的地方,例如如何提取 $firewall_rule_names 散列的键并适当地格式化它们。我不确定这里 Powershell 到底需要什么,但是一些用来获取它的最佳工具是 puppetlabs/stdlib 模块或 Puppet 本身提供的 keys()join() 函数,如果您使用的是 5.5 或更高版本。例如,如果您只需要一个以逗号分隔的名称列表,那么可以这样做:

$really_the_rule_names = join(keys($firewall_rule_names), ', ')

不过,我怀疑您可能需要引用密钥。您可以通过巧妙地使用指定给 join 的分隔符来获得大部分结果,但您可能还想考虑在将结果连接到字符串之前使用内置 regsubst() 函数处理键数组.

@John-Bollinger - Puppet 和 PowerShell = PuppetHell! :)

我终于设法解决了这个问题,但感觉我的代码块太长了,替换太多了。我已经尝试了更短的方法但无济于事,所以如果有人可以建议使用更短的代码,我们将不胜感激。

简而言之,我最终不得不

  1. 通过以下方式将 hiera 散列键(标题)转换为适合 Powershell 比较的数组语法:

    一个。添加单引号和逗号作为分隔符

    b。在数组的开头和结尾添加单引号和双引号

    c。从数组中的任何地方删除括号,因为 PowerShell 将它吐在它们上面

    $firewall_hiera = regsubst(regsubst(regsubst(join(keys($firewall_rules), "', '"), '^', '"\''), '$', '\'"'), '[\(\)]', '', 'G')
    

产生

    "'Core Networking - DNS UDP-Out', 'Core Networking - Dynamic Host Configuration Protocol DHCP-Out', 'File and Printer Sharing Echo Request - ICMPv4-Out', 'Internet Browsing HTTP-Out', 'Internet Browsing HTTPS-Out'"

  1. 如果在 Puppet hiera 中未定义,请使用 Powershell exec 清除防火墙:

    一个。使用 exec 命令清除主机防火墙规则:

    command   => 'netsh advfirewall firewall delete rule name=all; reg delete "HKLM\SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\FirewallRules" /f',
    

    b。使用非常长的 unless 语句确保幂等性:

    unless => "if (@(Compare-Object((Get-NetFirewallRule | foreach {\"'\"+$_.DisplayName+\"'\"}) -join ', ' -replace '[()]') $firewall_hiera).length -eq 0) {exit 0} else {exit 1}",
    

用上面创建的 $firewall_hiera

为下面的 compare-object 生成
    'Core Networking - DNS UDP-Out', 'Core Networking - Dynamic Host Configuration Protocol DHCP-Out', 'File and Printer Sharing Echo Request - ICMPv4-Out', 'Internet Browsing HTTP-Out', 'Internet Browsing HTTPS-Out'

然后使用迭代相同源层级的 thoward-windows_firewall 模块重新创建所需的规则(如果发生清除)。这个模块比 cr4ppy puppetlabs-windows_firewall 模块好很多,但是在用户登录后无法处理 Windows 10 可怕的防火墙添加剂。

有趣的是,只有人偶创建的数组需要外部双引号。由于 puppetlabs-powershell 模块没有将 .ps1 回显到磁盘,我不得不手动将它们回显以了解实际创建的内容并在 Powershell ISE(较旧的Josh Cooper powershell 模块确实创建了临时 .ps1's,虽然不太安全但很方便)

我能够在数组中放置一些 regsubst 或替换字符,但 ^ 和 $ 在数组中的表现不佳。

所有这一切都是为了解决 Windows 10 只有在用户登录后才不断创建额外的毫无意义的防火墙规则。这会间歇地持续大约 6 次人偶运行,最后停止。例如,Server 2012 R2 从来没有遇到过这个问题。

删除以下注册表项(使用 Puppetlabs 注册表模块确保 => 不存在)提供了一些额外的静音功能,但它本身并不是目的:

    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\RestrictedServices\AppIso\FirewallRules

再次感谢任何有助于缩短上述代码的帮助,特别是关于 regsubst 和 -replace 命令的帮助。请记住,生成的数组需要使用 Powershell 的 'compare-object' 功能或类似功能进行比较。

感谢@John-Bollinger 让我开始使用键和连接函数从 hiera 哈希创建数组。