使用 Puppet 管理 iptables

Bel*_*dez 10 linux configuration iptables puppet

提出了iptables使用 Puppet管理我们的规则的想法。我看到它augeas有一个iptables镜头,但目前处于实验阶段。

有没有人对如何处理这个问题有任何建议?理想情况下,我想根据服务器的类构建链。

小智 6

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

简而言之:您为每个服务创建片段,然后通过调用 ipt_fragment 定义类型来安装它们:

ipt_fragment { "filter-ftp": 确保 => 存在 }

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


fre*_*eit 6

这是我在 Red Hat Enterprise (RHEL) 上所做的事情。

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

尽管这看起来很丑陋,但它已经在 RHEL4、RHEL5 和 RHEL6 上进行了相当彻底的测试。

在augeas支持成为傀儡之前,我已经这样做了。如果我今天再写一遍,我会先看看 augeas iptables 镜头,然后再求助于exec { "perl ...": }.

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

基于最初来自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'",
    }
}
Run Code Online (Sandbox Code Playgroud)

我的 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,
         }
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

在其他类中的一些用法示例:

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 => "X.Y.0.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" }
}
Run Code Online (Sandbox Code Playgroud)