我们正在尝试为 iptables 生成防火墙规则 (puppetlabs/firewall)。我们的节点在概念上分组如下:
-- site1
---- shared1
------ specific1
------ specific2
---- shared2
------ specific3
------ specific4
节点“specific4”将始终需要访问“shared2”上的端口 8080 和“site1”上的端口 10000。“specific1”同样需要访问“shared1”上的 8080。每个节点的规则始终相同,但它们将依赖于它们属于哪个组。
我正在努力寻找一种不重复地在 hiera 中表示这一点的方法。是否有可能从完全独立的节点获取事实?
我想我希望能够做这样的事情(简化):
--
hosts:
host specific4:
rules:
rule:
port: 8080
ip: get_ip(get_my_shared())
但显然,您不能从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'
}
}
然后,我根据 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
}
}
正如我所说,这可行,但如果可能的话,我更愿意使用导出的资源。我遇到的问题是,执行导出的资源无法导出自己的 IP/主机以供收集。也许我错过了什么,但我认为这是不可能的,因为导出发生在解析资源时,而不是在实现包含该资源的节点时。
答案1
因此,您希望某些主机从另一台主机的事实中获取信息,但事实来自哪个主机将取决于特定主机的配置。这样对吗?
如果是这样,我还建议使用导出的资源并使用标签来指定要使用的特定资源。这样做的原因是主机基本上有两种方式来获取另一台主机的事实。两者都需要启用 storeconfigs。一种是让 puppet master 对你的 storeconfigs 后端进行显式查找;我不知道有任何模块可以封装这个,所以你可能必须自己编写一个。另一种是让源主机导出包含其事实的资源;这比较简单,我将在下面描述。
如果您创建自己的资源类型来包装防火墙规则,这将更容易。这可以防止与任何其他恰好导出防火墙规则的类发生冲突。
define site_firewall ($ipaddr) {
firewall { '500 allow site access':
chain => 'OUTPUT',
destination => $ipaddr,
proto => 'tcp',
port => 10000,
}
}
接下来,您的每个站点都应导出自己的定义site_firewall
:
@@site_firewall { $hostname:
ipaddr => $ipaddress,
}
在层次结构中,你可以在层次结构的某个位置定义每个主机所属的站点:
sitename: site1
然后在您的主机类中实例化适当的site_firewall
定义:
Site_firewall <<| name == hiera('sitename', 'default') |>>
类似的设置也适用于共享主机。
如果您需要站点和共享主机上的防火墙规则,则应使用标签而不是名称,因为给定主机将有多条防火墙规则。在特定主机上:
@@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,
}
在站点主机上,您只需要收集这些主机的防火墙规则:
Firewall <<| tag == $hostname |>>
编辑:啊哈。我想我已经找到你在导出资源时遇到的问题了。至少这是一个陷阱,我会在这里记录下来以防万一。
如果您拥有具有默认参数的资源,并且您在未明确设置这些参数的情况下导出该资源,则参数默认值由主机提供实现资源,而不是出口资源。
换句话说,如果您有以下资源类型定义:
define foo ($bar = $fqdn) {
notice($bar)
}
并从主机 baz.example.com 导出它:
@@foo { 'title': }
您可以在主机 quux.example.com 上实现这一点:
Foo <<| |>>
那么的值$bar
将是“quux.example.com”。
如果你像这样从 baz.example.com 导出它:
@@foo { 'title': bar => $fqdn }
那么的值$bar
确实是“baz.example.com”。
答案2
嗯,我认为对于您的用例来说,一个好的选择是启用“storeconfigs”,然后使用“导出的资源”。
您可以在这里找到有关此主题的一些文档,包括一些示例: