我们要做的是为 iptables 生成防火墙规则(puppetlabs/firewall)。我们的节点在概念上是这样分组的:
-- site1
---- shared1
------ specific1
------ specific2
---- shared2
------ specific3
------ specific4
Run Code Online (Sandbox Code Playgroud)
节点“specific4”将始终需要访问“shared2”上的端口 8080 和“site1”上的端口 10000。“specific1”同样需要访问“shared1”上的8080。每个节点的规则总是相同的,但它们将取决于它们属于哪个组。
我正在努力寻找一种方法来在 hiera 中不重复地表示这一点。是否可以从完全独立的节点获取事实?
我想我希望能够做这样的事情(简化):
--
hosts:
host specific4:
rules:
rule:
port: 8080
ip: get_ip(get_my_shared())
Run Code Online (Sandbox Code Playgroud)
但显然,您不能从yaml文件中调用函数。最好的方法是使用自定义事实吗?我还没有真正使用过 hiera - 所以我不确定最佳实践和什么不是。任何朝着正确方向的温和推动将不胜感激。
编辑:
这是我采用的解决方案,但如果我可以使用导出的资源,我可以消除对 puppetdb-query 的依赖。
# helper for creating rules from an array
define firewall_rules($port, $service_type) {
$source = $name
firewall { "$port $service_type $source":
proto => 'tcp',
dport => $port,
state => 'NEW',
source => "$source",
action => 'accept'
}
}
class profile::specific inherits profile {
$site = hiera('site')
$shared = hiera('shared')
$query = "site=\"$site\" and shared=\"$shared\""
$shared_hosts = query_nodes($query)
$specific_port = hiera('specific_ports', '8080')
firewall_rules { $shared_hosts:
port => $specific_port,
service_type => 'SPECIFIC'
}
}
Run Code Online (Sandbox Code Playgroud)
然后我根据 hiera 数据导出事实site和shared事实,并使用puppet-stdlib从file主机上的资源加载它们。
class profile::facts {
$site = hiera('site', 'none')
$shared = hiera('shared', 'none')
$specific = hiera('specific', 'none')
$role = hiera('role', 'none')
$grouping = "site=$site\nshared=$shared\nspecific=$specific\nrole=$role"
notify { "facts being set: $grouping ": }
file { ['/etc/facter/', '/etc/facter/facts.d/']:
ensure => directory,
owner => 'root',
group => 'root'
}->
file { '/etc/facter/facts.d/grouping.txt':
ensure => file,
owner => 'root',
group => 'root',
mode => '0775',
content => $grouping
}
}
Run Code Online (Sandbox Code Playgroud)
正如我所说,这可行,但如果可能,我更愿意使用导出的资源。我遇到的问题是,进行导出的资源也不能导出自己的 IP/主机进行收集。也许我错过了一些东西,但我认为这是不可能的,因为导出是在解析资源时发生的,而不是在实现包含该资源的节点时发生。
因此,您希望某些主机从另一个主机的事实中获取信息,但是事实来自哪个主机会因特定主机的配置而异。那是对的吗?
如果是这样,我还建议使用导出的资源并使用标签来指定要使用的特定资源。这样做的原因是主机基本上有两种方法可以获取另一主机的事实。两者都需要启用 storeconfigs。一种是让 puppet master 对你的 storeconfigs 后端进行显式查找;我不知道有任何模块可以封装它,因此您可能必须自己编写。另一种是源主机导出包含其事实的资源;这更容易,我将在下面描述。
如果您制作自己的资源类型来包装防火墙规则,这会更容易。这可以防止与碰巧导出防火墙规则的任何其他类发生任何冲突。
define site_firewall ($ipaddr) {
firewall { '500 allow site access':
chain => 'OUTPUT',
destination => $ipaddr,
proto => 'tcp',
port => 10000,
}
}
Run Code Online (Sandbox Code Playgroud)
接下来,您的每个站点都应该导出自己的定义site_firewall:
@@site_firewall { $hostname:
ipaddr => $ipaddress,
}
Run Code Online (Sandbox Code Playgroud)
在 hiera 中,您可以在层次结构中的某个位置定义每个主机所属的站点:
sitename: site1
Run Code Online (Sandbox Code Playgroud)
然后在您的宿主类中,实例化适当的site_firewall定义:
Site_firewall <<| name == hiera('sitename', 'default') |>>
Run Code Online (Sandbox Code Playgroud)
类似的设置适用于共享主机。
如果您需要站点和共享主机上的防火墙规则,您应该使用标签而不是名称,因为给定主机将有多个防火墙规则。在特定主机上:
@@firewall { "500 allow site traffic from ${hostname}":
tag => hiera('sitename', 'default-site'),
source => $ipaddress,
proto => 'tcp',
port => 10000,
}
@@firewall { "500 allow shared traffic from ${hostname}":
tag => hiera('sharedname', 'default-shared'),
source => $ipaddress,
proto => 'tcp',
port => 8080,
}
Run Code Online (Sandbox Code Playgroud)
在站点主机上,您只需要收集这些主机的防火墙规则:
Firewall <<| tag == $hostname |>>
Run Code Online (Sandbox Code Playgroud)
编辑:啊哈。我想我已经找到了您在导出资源时遇到的问题。至少这是一个问题,我会在这里记录下来以备不时之需。
如果您有一个带有默认参数的资源并且您在没有明确设置这些参数的情况下导出该资源,则参数默认值由实现该资源的主机提供,而不是由主机提供。
换句话说,如果你有这个资源类型定义:
define foo ($bar = $fqdn) {
notice($bar)
}
Run Code Online (Sandbox Code Playgroud)
然后从主机 baz.example.com 导出它:
@@foo { 'title': }
Run Code Online (Sandbox Code Playgroud)
你在主机 quux.example.com 上意识到它:
Foo <<| |>>
Run Code Online (Sandbox Code Playgroud)
那么 的值$bar将是“quux.example.com”。
如果,相反,您从 baz.example.com 导出它,如下所示:
@@foo { 'title': bar => $fqdn }
Run Code Online (Sandbox Code Playgroud)
那么 的值$bar确实是“baz.example.com”。