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! :)
我终于设法解决了这个问题,但感觉我的代码块太长了,替换太多了。我已经尝试了更短的方法但无济于事,所以如果有人可以建议使用更短的代码,我们将不胜感激。
简而言之,我最终不得不
通过以下方式将 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'"
…
如果在 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 哈希创建数组。
我正在尝试将 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! :)
我终于设法解决了这个问题,但感觉我的代码块太长了,替换太多了。我已经尝试了更短的方法但无济于事,所以如果有人可以建议使用更短的代码,我们将不胜感激。
简而言之,我最终不得不
通过以下方式将 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'"
…
如果在 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 哈希创建数组。