使用Puppetpipe理iptables

用Puppetpipe理我们的iptables规则的想法已经提出来了。 我看到augeas有一个iptables镜头,但它目前是实验性的。

有没有人有如何处理这个问题的build议? 理想情况下,我想构build基于服务器类的链。

这就是我正在做的与红帽企业(RHEL)。

RHEL有一个从/etc/sysconfig/iptables加载规则的iptables服务,我正在修改该文件并重新启动iptables服务。 许多人喜欢把碎片放到一个iptables.d目录下,并从中build立一个iptables(通过make或类似的东西)规则集。 我包括重build默认规则集的东西,但通常不会做任何事情。 如果您的需求很简单,您可以将iptables文件复制到系统中。

尽pipe看起来有多丑,但在RHEL4,RHEL5和RHEL6上已经完全testing过了。

在傀儡支持之前,我有过这样的事情。 如果我今天再写一遍,我会在使用exec { "perl ...": }之前查看augeas iptables镜头。

一些全局定义用于编辑文件

基于最初从http://reductivelabs.com/trac/puppet/wiki/SimpleTextRecipes的东西

 # Ensure that the line "line" exists in "file": # Usage: # append_if_no_such_line { dummy_modules: # file => "/etc/modules", # line => dummy # } # define append_if_no_such_line($file, $line, $refreshonly = 'false') { exec { "/bin/echo '$line' >> '$file'": unless => "/bin/grep -Fxqe '$line' '$file'", refreshonly => $refreshonly, } } # Ensure that the line "line" exists in "file": # Usage: # prepend_if_no_such_line { dummy_modules: # file => "/etc/modules", # line => dummy # } # define prepend_if_no_such_line($file, $line, $refreshonly = 'false') { $line_no_slashes = slash_escape($line) exec { "/usr/bin/perl -p0i -e 's/^/$line_no_slashes\n/;' '$file'": unless => "/bin/grep -Fxqe '$line' '$file'", refreshonly => $refreshonly, } } define insert_line_after_if_no_such_line($file, $line, $after) { $line_no_slashes = slash_escape($line) $after_no_slashes = slash_escape($after) exec { "/usr/bin/perl -p0i -e 's/^($after_no_slashes)\$/\$1\n$line_no_slashes/m' '$file'": onlyif => "/usr/bin/perl -ne 'BEGIN { \$ret = 0; } \$ret = 1 if /^$line_no_slashes/; END { exit \$ret; }' '$file'", } } define insert_line_before_if_no_such_line($file, $line, $beforeline) { $line_no_slashes = slash_escape($line) $before_no_slashes = slash_escape($beforeline) exec { "/usr/bin/perl -p0i -e 's/^($before_no_slashes)\$/$line_no_slashes\n\$1/m' '$file'": onlyif => "/usr/bin/perl -ne 'BEGIN { \$ret = 0; } \$ret = 1 if /^$line_no_slashes/; END { exit \$ret; }' '$file'", } } 

我的iptables类:

 class iptables { if $lsbmajdistrelease >= '6' { $primarychain = 'INPUT' } else { $primarychain = 'RH-Firewall-1-INPUT' } package { iptables: ensure => installed # "latest" would be too much } service { iptables: enable => true, # default on ensure => running, # start it up if it's stopped hasstatus => true, # since there's no daemon } file { "/etc/sysconfig/iptables": ensure => present; } ## # Build up a config if it's missing components we expect; should # automatically repair a config if it's broken for really simple reasons ## # Very first thing: a comment at the top warning about our evil; add even if # we're not touching anything else... prepend_if_no_such_line { "/etc/sysconfig/iptables comment": file => "/etc/sysconfig/iptables", line => "# This file partially managed by puppet; attempts to edit will result in magic reappearances" } # start # *filter insert_line_after_if_no_such_line { "/etc/sysconfig/iptables *filter": file => "/etc/sysconfig/iptables", line => "\\*filter", after => "#.*", notify => Service[iptables], } # first default chain # :INPUT ACCEPT [0:0] insert_line_after_if_no_such_line { "/etc/sysconfig/iptables:INPUT": file => "/etc/sysconfig/iptables", line => ":INPUT ACCEPT \\[0:0\\]", after => "\\*filter", notify => Service[iptables], } # second default chain # :FORWARD ACCEPT [0:0] insert_line_after_if_no_such_line { "/etc/sysconfig/iptables:FORWARD": file => "/etc/sysconfig/iptables", line => ":FORWARD ACCEPT \\[0:0\\]", after => ":INPUT ACCEPT \\[\\d+:\\d+\\]", notify => Service[iptables], } # third default chain # :OUTPUT ACCEPT [0:0] insert_line_after_if_no_such_line { "/etc/sysconfig/iptables:OUTPUT": file => "/etc/sysconfig/iptables", line => ":OUTPUT ACCEPT \\[0:0\\]", after => ":FORWARD ACCEPT \\[\\d+:\\d+\\]", notify => Service[iptables], } if $lsbmajdistrelease <= 5 { # Finally, the RH special chain # :RH-Firewall-1-INPUT - [0:0] insert_line_after_if_no_such_line { "/etc/sysconfig/iptables:RH-Firewall-1-INPUT": file => "/etc/sysconfig/iptables", line => ":RH-Firewall-1-INPUT - \\[0:0\\]", after => ":OUTPUT ACCEPT \\[\\d+:\\d+\\]", notify => Service[iptables], } # redirect INPUT to RH chain # -A INPUT -j RH-Firewall-1-INPUT insert_line_after_if_no_such_line { "/etc/sysconfig/iptables:INPUT:RH-Firewall-1-INPUT": file => "/etc/sysconfig/iptables", line => "-A INPUT -j RH-Firewall-1-INPUT", after => ":RH-Firewall-1-INPUT - \\[\\d+:\\d+\\]", notify => Service[iptables], } # redirect FORWARD to RH chain # -A FORWARD -j RH-Firewall-1-INPUT insert_line_after_if_no_such_line { "/etc/sysconfig/iptables:FORWARD:RH-Firewall-1-INPUT": file => "/etc/sysconfig/iptables", line => "-A FORWARD -j RH-Firewall-1-INPUT", after => "-A INPUT -j RH-Firewall-1-INPUT", notify => Service[iptables], } } # Let anything on localhost work... # -A $primarychain -i lo -j ACCEPT insert_line_after_if_no_such_line { "/etc/sysconfig/iptables:$primarychain lo": file => "/etc/sysconfig/iptables", line => "-A $primarychain -i lo -j ACCEPT", after => "-A FORWARD -j $primarychain", notify => Service[iptables], } # And let through all the ICMP stuff: # -A $primarychain -p icmp --icmp-type any -j ACCEPT if $lsbmajdistrelease >= '6' { insert_line_after_if_no_such_line { "/etc/sysconfig/iptables:$primarychain icmp": file => "/etc/sysconfig/iptables", line => "-A $primarychain -p icmp -j ACCEPT", after => "-A $primarychain -i lo -j ACCEPT", notify => Service[iptables], } } else { insert_line_after_if_no_such_line { "/etc/sysconfig/iptables:$primarychain icmp": file => "/etc/sysconfig/iptables", line => "-A $primarychain -p icmp --icmp-type any -j ACCEPT", after => "-A $primarychain -i lo -j ACCEPT", notify => Service[iptables], } } # Finally, let anything that's part of an exisiting connection through: # -A $primarychain -m state --state ESTABLISHED,RELATED -j ACCEPT insert_line_after_if_no_such_line { "/etc/sysconfig/iptables:ESTABLISHED": file => "/etc/sysconfig/iptables", line => "-A $primarychain -m state --state ESTABLISHED,RELATED -j ACCEPT", after => "-A $primarychain -p icmp --icmp-type any -j ACCEPT", notify => Service[iptables], } # Very last thing: # COMMIT append_if_no_such_line { "/etc/sysconfig/iptables:COMMIT": file => "/etc/sysconfig/iptables", line => "COMMIT", notify => Service[iptables], } # Next to last thing: reject! # -A $primarychain -j REJECT --reject-with icmp-host-prohibited insert_line_before_if_no_such_line { "/etc/sysconfig/iptables:final reject": file => "/etc/sysconfig/iptables", line => "-A $primarychain -j REJECT --reject-with icmp-host-prohibited", beforeline => "COMMIT", notify => Service[iptables], } } # example: # iptable_rule { "iptable:ssh": # rule => "-m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT" # } # change your mind about a rule, do this: # iptable_rule { "iptable:ssh": # rule => "-m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT", # ensure => "absent", # } define iptable_rule($rule, $ensure = 'present') { if $lsbmajdistrelease >= '6' { $primarychain = 'INPUT' } else { $primarychain = 'RH-Firewall-1-INPUT' } $iptablesline = "-A $primarychain $rule" case $ensure { default: { err ( "unknown ensure value $ensure" ) } present: { insert_line_before_if_no_such_line { "/etc/sysconfig/iptables:add $rule": file => "/etc/sysconfig/iptables", line => $iptablesline, beforeline => "-A $primarychain -j REJECT --reject-with icmp-host-prohibited", notify => Service[iptables], } } absent: { delete_lines { "/etc/sysconfig/iptables:remove $rule": file => "/etc/sysconfig/iptables", pattern => $iptablesline, notify => Service[iptables], } } } } # Example: # iptable_tcp_port { "iptable:ssh": # port => "22", # } # Example: # iptable_tcp_port { "iptable:oracle:130.157.5.0/24": # port => "1521", # source => "130.157.5.0/24", # } # (add ensure => "absent" to remove) define iptable_tcp_port($port, $ensure = 'present', $source = 'ANY') { case $source { "ANY": { iptable_rule { "iptable_tcp_port:$port": rule => "-m state --state NEW -m tcp -p tcp --dport $port -j ACCEPT", ensure => $ensure, } } default: { iptable_rule { "iptable_tcp_port:$port:$source": rule => "-m state --state NEW -m tcp -p tcp --source $source --dport $port -j ACCEPT", ensure => $ensure, } } } } # Example: # iptable_udp_port { "iptable:ntp": # port => "123", # } # (again, ensure => "absent" if needed) define iptable_udp_port($port, $ensure = 'present', $source = 'ANY') { case $source { "ANY": { iptable_rule { "iptable_udp_port:$port": rule => "-p udp -m udp --dport $port -j ACCEPT", ensure => $ensure, } } default: { iptable_rule { "iptable_udp_port:$port": rule => "-p udp -m udp --source $source --dport $port -j ACCEPT", ensure => $ensure, } } } } 

其他类中使用的一些例子:

 class ssh { include iptables iptable_tcp_port { "iptables:ssh": port => "22", ensure => "present" } } class ssh_restricted inherits ssh { Iptable_tcp_port["iptables:ssh"]{ensure => "absent"} iptable_tcp_port { "ssh:RESTRICTED": port => "22", source => "XY0.0/16", ensure => "present"; } } class apache { iptable_tcp_port { "iptables:http": require => Service["httpd"], port => "80"; } } class apache::secure { iptable_tcp_port { "iptables:https": require => Service["httpd"], port => "443"; } } class snmp { iptable_udp_port { "iptables:snmp": port => "161" } } 

Puppet Labs在他们的wiki中有一个例子: Module Iptables Patterns

简而言之:您为每个服务创build片段,然后通过调用ipt_fragment defined-type来安装它们:

  ipt_fragment {“filter-ftp”:ensure => present} 

当一个片段被安装(它们在/etc/iptables.d/中)时,它会触发一个连接所有片段的脚本并重新启动iptables。

问题是,你打算完成什么?

把iptables放在Puppet上很简单:把脚本放在puppet服务器上,并把它提供给你需要的地方。 如果需要一些定制,请将其作为模板。

现在,也许你想要的东西像“如果主机X有WebServer,那么端口80和443必须打开”。 在这种情况下,我build议你要做的是从多个文件部分组成的脚本,使用通用模块的concatenated_fileconcatfilepart (我更喜欢后者,这使得sorting,但它不是在所有的叉 – – 我点你camptocamp的,有它)。

这些文件部分可以很容易地使用模板来编写。 诀窍是你concatfilepartApache类上导出 concatfilepart (可能通过调用一个根据IP地址和端口等参数准备一个concatfilepart的定义),并且在iptables类中你可以实现所有用iptables标记的导出的concatfilepart ,或者类似的东西。

如果你这样做,我很乐意在github上看到这个模块。 我从来没有写一个iptables模块。 🙂