使用 hiera 访问另一个节点的事实

使用 hiera 访问另一个节点的事实

我们正在尝试为 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和事实,并使用从主机上的资源加载它们。sharedpuppet-stdlibfile

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”,然后使用“导出的资源”。

您可以在这里找到有关此主题的一些文档,包括一些示例:

相关内容