Ідея управління нашими iptables
правилами з Лялькою висунута. Я бачу, що augeas
у iptables
лінзи є, але зараз вона експериментальна.
Хтось має якісь пропозиції, як впоратися з цим? В ідеалі я хотів би побудувати ланцюги на основі класу сервера.
Ідея управління нашими iptables
правилами з Лялькою висунута. Я бачу, що augeas
у iptables
лінзи є, але зараз вона експериментальна.
Хтось має якісь пропозиції, як впоратися з цим? В ідеалі я хотів би побудувати ланцюги на основі класу сервера.
Відповіді:
Ось що я роблю з Red Hat Enterprise (RHEL).
RHEL має iptables
сервіс, який завантажує правила, /etc/sysconfig/iptables
і я працюю над зміною цього файлу та перезапуском служби iptables. Багатьом людям подобається скидати фрагменти в каталог iptables.d і створювати з цього набір правил iptables (через make або щось подібне). Я включаю речі для відновлення набору правил за замовчуванням, але це зазвичай ніколи нічого не робить. Якщо ваші потреби прості, ви можете просто скопіювати файл 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" }
}
Лялькові лабораторії мають приклад прямо у своїй вікі: Шаблони модулів Iptables
Якщо коротко: ви створюєте фрагменти для кожної служби, а потім встановлюєте їх, викликаючи визначений тип ipt_fragment:
ipt_fragment {"filter-ftp": secure => присутній}
Коли фрагмент встановлений (вони знаходяться в /etc/iptables.d/), він запускає виконання сценарію, який об'єднує всі фрагменти і перезапускає iptables.
Питання в тому, що ви маєте намір здійснити?
Поставити iptables на Ляльковому просто: поставте скрипт на ляльковий сервер і подайте його туди, де вам це потрібно. Якщо воно потребує певного налаштування, зробіть його шаблоном.
Тепер, можливо, ви хочете щось на кшталт "Якщо хост X має WebServer, то порти 80 і 443 до нього повинні бути відкритими". У цьому випадку, я пропоную вам зробити сценарій, щоб скласти скрипт з декількох частин файлів, використовуючи загальний модуль concatenated_file
або concatfilepart
(я віддаю перевагу останній, який дозволяє замовляти, але він доступний не на всіх вилах - я наказую вам Camptocamp's, який має).
Ці частини файлів можна легко записати за допомогою шаблонів. Хитрість полягає в тому, що ви експортуватиconcatfilepart
на Apache
клас (можливо, викликавши визначити , що готує на concatfilepart
основі таких параметрів , як IP - адреса і порт), і на iptables
класі ви б зрозуміли , все експортовані concatfilepart
з тегами iptables
або що - то в цьому роді.
Якщо ви це зробите, я хотів би побачити цей модуль на github. Мені ніколи не доводилося писати модуль iptables. :-)