แนวคิดของการจัดการiptables
กฎของเรากับ Puppet ได้ถูกนำขึ้นมา ฉันเห็นว่าaugeas
มีiptables
เลนส์ แต่กำลังทดลองอยู่
ไม่มีใครมีข้อเสนอแนะใด ๆ เกี่ยวกับวิธีการจัดการนี้ โดยหลักการแล้วฉันต้องการสร้างเครือข่ายตามคลาสของเซิร์ฟเวอร์
แนวคิดของการจัดการiptables
กฎของเรากับ Puppet ได้ถูกนำขึ้นมา ฉันเห็นว่าaugeas
มีiptables
เลนส์ แต่กำลังทดลองอยู่
ไม่มีใครมีข้อเสนอแนะใด ๆ เกี่ยวกับวิธีการจัดการนี้ โดยหลักการแล้วฉันต้องการสร้างเครือข่ายตามคลาสของเซิร์ฟเวอร์
คำตอบ:
นี่คือสิ่งที่ฉันทำกับ Red Hat Enterprise (RHEL)
RHEL มีiptables
บริการที่โหลดกฎจาก/etc/sysconfig/iptables
และฉันกำลังทำงานกับการแก้ไขไฟล์นั้นและเริ่มบริการ iptables ใหม่ หลายคนชอบที่จะส่งแฟรกเมนต์ไปยังไดเร็กทอรี iptables.d และสร้าง iptables (ผ่าน make หรืออะไรทำนองนั้น) ruleset จากนั้น ฉันมีสิ่งต่าง ๆ สำหรับการสร้างชุดกฎเริ่มต้นใหม่ แต่ก็ไม่เคยทำอะไรเลย หากความต้องการของคุณง่ายคุณก็สามารถคัดลอกไฟล์ iptables ไปยังระบบ
แม้จะดูเหมือนว่าสิ่งนี้น่าเกลียด แต่ก็มีการทดสอบอย่างละเอียดเกี่ยวกับ RHEL4, RHEL5 และ RHEL6
ฉันทำสิ่งนี้ก่อนที่การสนับสนุนของ augeas จะเป็นหุ่นเชิด ถ้าฉันเขียนมันอีกครั้งวันนี้ฉันจะดูเลนส์ augeas iptables ก่อนหันไปexec { "perl ...": }
ใช้
# 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'",
}
}
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 => "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" }
}
Puppet Labs มีตัวอย่างใน wiki ของพวกเขานั่นคือModule Iptables Patterns
กล่าวโดยย่อ: คุณสร้างแฟรกเมนต์สำหรับแต่ละเซอร์วิสจากนั้นติดตั้งโดยการเรียกใช้ ipt_fragment ที่กำหนดประเภท:
ipt_fragment {"filter-ftp": sure => present}
เมื่อติดตั้งแฟรกเมนต์ (อยู่ใน /etc/iptables.d/) มันจะทริกเกอร์การทำงานของสคริปต์ที่เชื่อมต่อแฟรกเมนต์ทั้งหมดและรีสตาร์ท iptables
คำถามคือคุณตั้งใจจะทำอะไร
การวาง iptables บน Puppet นั้นง่าย: วางสคริปต์ไว้บนเซิร์ฟเวอร์ puppet และให้บริการกับทุกที่ที่คุณต้องการ หากต้องการการปรับแต่งบางอย่างให้ทำเป็นเทมเพลต
ตอนนี้บางทีคุณอาจต้องการบางสิ่งเช่น "ถ้าโฮสต์ X มี WebServer ดังนั้นพอร์ต 80 และ 443 จะต้องเปิดอยู่" ในกรณีนั้นสิ่งที่ฉันแนะนำให้คุณทำคือการเขียนสคริปต์จากหลาย ๆ ส่วนของไฟล์โดยใช้โมดูลทั่วไปconcatenated_file
หรือconcatfilepart
(ฉันชอบอันหลังซึ่งเปิดใช้งานการสั่งซื้อ แต่มันไม่พร้อมใช้งานสำหรับส้อมทั้งหมด - ฉันขอให้คุณ ของ camptocamp ซึ่งมี)
ส่วนของไฟล์เหล่านี้สามารถเขียนได้อย่างง่ายดายโดยใช้แม่แบบ เคล็ดลับคือการที่คุณส่งออกconcatfilepart
บนApache
ชั้น (อาจจะโทรกำหนดที่เตรียมconcatfilepart
ตามพารามิเตอร์เช่นที่อยู่ IP และพอร์ต) และในiptables
ระดับที่คุณจะตระหนักถึงทั้งหมดที่ส่งออกconcatfilepart
ที่มีแท็กiptables
หรือสิ่งที่ต้องการ
ถ้าคุณทำอย่างนั้นฉันชอบที่จะเห็นโมดูลที่บน GitHub ฉันไม่เคยเขียนโมดูล iptables :-)