From 2bd43f64951ebdc818ca18015b34f6682b635e6f Mon Sep 17 00:00:00 2001 From: Alexander Kratzsch Date: Sun, 25 Nov 2018 16:47:40 +0100 Subject: [PATCH] First version of IPtables module --- modules/iptables/manifests/init.pp | 12 ++ modules/iptables/manifests/ng.pp | 167 ++++++++++++++++++ .../iptables/manifests/ng/advanced_rule.pp | 54 ++++++ modules/iptables/manifests/ng/header.pp | 100 +++++++++++ modules/iptables/manifests/ng/rule.pp | 116 ++++++++++++ modules/iptables/manifests/ng/trailer.pp | 22 +++ 6 files changed, 471 insertions(+) create mode 100644 modules/iptables/manifests/ng.pp create mode 100644 modules/iptables/manifests/ng/advanced_rule.pp create mode 100644 modules/iptables/manifests/ng/header.pp create mode 100644 modules/iptables/manifests/ng/rule.pp create mode 100644 modules/iptables/manifests/ng/trailer.pp diff --git a/modules/iptables/manifests/init.pp b/modules/iptables/manifests/init.pp index 995545d2..103f0d4c 100644 --- a/modules/iptables/manifests/init.pp +++ b/modules/iptables/manifests/init.pp @@ -73,4 +73,16 @@ provider => 'ip6tables'; } } + + # Testing new iptables module + class { 'iptables::ng': + chains => { + 'INPUT' => 'DROP', + 'FORWARD' => upcase($forward_policy), + 'OUTPUT' => 'ACCEPT', + }, + rules => $rules, + log_fallthrough => str2bool($log_fallthrough), + } + } diff --git a/modules/iptables/manifests/ng.pp b/modules/iptables/manifests/ng.pp new file mode 100644 index 00000000..29f8b351 --- /dev/null +++ b/modules/iptables/manifests/ng.pp @@ -0,0 +1,167 @@ +# Copyright 2018 dhtech +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file +# +# == Class: iptables +# +# Firewall hooks for the firewall lib. +# +# === Parameters +# +# [*rules*] +# The host specific rules for this machine as calculated from ipplan. +# +# [*log_fallthrough*] +# Log the packets that will be policy dropped in the INPUT chain. +# +# [*chains*] +# A hash containing chains with their default policy. Defaults to +# ``` +# { +# 'INPUT' => 'DROP', +# 'FORWARD' => 'DROP', +# 'OUTPUT' => 'ACCEPT', +# } +# ``` +# [*ipv4file*] +# The file to store the IPv4 rules in. Defaults to +# `/etc/iptables/rules.v4.puppet` +# +# [*ipv6file*] +# The file to store the IPv6 rules in. Defaults to +# `/etc/iptables/rules.v6.puppet` + +class iptables::ng ( + + Hash $rules, + Boolean $log_fallthrough, + Hash[String, Enum['ACCEPT', 'DROP', 'REJECT'], 1] $chains = { + 'INPUT' => 'DROP', + 'FORWARD' => 'DROP', + 'OUTPUT' => 'ACCEPT', + }, + String $ipv4file = '/etc/iptables/rules.v4.puppet', + String $ipv6file = '/etc/iptables/rules.v6.puppet', + +) { + + $chains_header = $chains.map |$chain,$policy| { sprintf(':%s %s [0:0]', $chain, $policy) } + + $enforce_command = '/usr/local/sbin/enforce-iptables' + file { 'enforce-command': + path => $enforce_command, + source => 'puppet:///scripts/iptables/enforce-iptables.sh', + owner => 'root', + group => 'root', + mode => '0750', + } + + + # Header and trailer rules + class { 'iptables::ng::header': } + class { 'iptables::ng::trailer': + log_input => $log_fallthrough, + } + + + # IPv4 + concat { $ipv4file: + ensure => present, + backup => true, + warn => '# This file is managed by Puppet. Do not edit.', + order => 'numeric', + validate_cmd => '/usr/sbin/iptables-restore -t < %', + ensure_newline => true, + notify => Exec['enforce-puppet-iptables'], + } + + concat::fragment { '00-ipv4-header': + target => $ipv4file, + order => 0, + content => ([ + '*filter' + ] + $chains_header).join("\n"), + } + + concat::fragment { '99-ipv4-trailer': + target => $ipv4file, + order => 9999, + content => [ + 'COMMIT' + ].join("\n"), + } + + exec { 'enforce-puppet-iptables': + command => "/usr/bin/echo ${enforce_command} ipv4 '${ipv4file}'", + refreshonly => true, + require => File['enforce-command'], + } + + each($rules['v4']) |$rule| { + $name = $rule['name'] + $proto = $rule['proto'] + + iptables::ng::rule { "v4 ${name} ${proto}": + type => 'ipv4', + chain => 'INPUT', + action => 'ACCEPT', + order => 500, + source => $rule['src'], + proto => $rule['proto'], + dport => $rule['dports'], + sport => $rule['sports'], + } + } + + + # IPv6 + concat { $ipv6file: + ensure => present, + backup => true, + warn => '# This file is managed by Puppet. Do not edit.', + order => numeric, + validate_cmd => '/usr/sbin/ip6tables-restore -t < %', + ensure_newline => true, + notify => Exec['enforce-puppet-ip6tables'], + } + + concat::fragment { '00-ipv6-header': + target => $ipv6file, + order => 0, + content => ([ + '*filter' + ] + $chains_header).join("\n"), + } + + concat::fragment { '99-ipv6-trailer': + target => $ipv6file, + order => 9999, + content => [ + 'COMMIT', + ].join("\n"), + } + + exec { 'enforce-puppet-ip6tables': + command => "/usr/bin/echo ${enforce_command} ipv6 '${ipv6file}'", + refreshonly => true, + require => File['enforce-command'], + } + + each($rules['v6']) |$rule| { + $name = $rule['name'] + $proto = $rule['proto'] + + iptables::ng::rule { "v6 ${name} ${proto}": + type => 'ipv6', + chain => 'INPUT', + action => 'ACCEPT', + order => 500, + source => $rule['src'], + proto => $rule['proto'], + dport => $rule['dports'], + sport => $rule['sports'], + } + } + +} diff --git a/modules/iptables/manifests/ng/advanced_rule.pp b/modules/iptables/manifests/ng/advanced_rule.pp new file mode 100644 index 00000000..790151ab --- /dev/null +++ b/modules/iptables/manifests/ng/advanced_rule.pp @@ -0,0 +1,54 @@ +# Copyright 2018 dhtech +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file +# +# == Class: iptables::ng::rule +# +# Firewall rules for the firewall lib. +# +# === Parameters +# +# [*type*] +# Version of the IP protocol for this rule. Must be `4` or `6`. +# +# [*rule*] +# The rule that should be used. In a format that can be understood +# by `iptables-restore` it will have `-A ${chain} ` prepended +# +# [*order*] +# Allows you to change the order in which the rules are placed. Header rules +# should have `order < 200`, trailer rules `order >= 800`. Defaults to `500` + +define iptables::ng::advanced_rule ( + + Enum['ipv4', 'ipv6', 'both'] $type, + String $rule, + Integer $order = 500, + +) { + + include iptables::ng + + + if $type in ['ipv4', 'both'] { + + concat::fragment { "v4 ${name}": + target => $::iptables::ng::ipv4file, + order => $order, + content => $rule, + } + + } + + if $type in ['ipv6', 'both'] { + + concat::fragment { "v6 ${name}": + target => $::iptables::ng::ipv6file, + order => $order, + content => $rule, + } + + } + +} diff --git a/modules/iptables/manifests/ng/header.pp b/modules/iptables/manifests/ng/header.pp new file mode 100644 index 00000000..f82f753f --- /dev/null +++ b/modules/iptables/manifests/ng/header.pp @@ -0,0 +1,100 @@ +# Copyright 2018 dhtech +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file +# +# Initial iptables rules that always applies + +class iptables::ng::header { + + iptables::ng::advanced_rule { 'accept related established rules': + type => 'both', + order => 1, + rule => [ + '-A INPUT -m state --state RELATED,ESTABLISHED', + '-m comment --comment "accept related established rules"', + '-j ACCEPT', + ].join(' '), + } + + iptables::ng::advanced_rule { 'accept all to lo interface': + type => 'both', + order => 10, + rule => [ + '-A INPUT -i lo', + '-m comment --comment "accept all to lo interface"', + '-j ACCEPT', + ].join(' '), + } + + + # IPv4 ICMP + iptables::ng::advanced_rule { 'v4 accept icmp, heavy rate limited': + type => 'ipv4', + order => 20, + rule => [ + '-A INPUT -p icmp', + '-m limit --limit 5/sec --limit-burst 20', + '-m comment --comment "accept icmp, heavy rate limited"', + '-j ACCEPT', + ].join(' '), + } + + iptables::ng::advanced_rule { 'v4 reject with icmp udp echo, heavy rate limited': + type => 'ipv4', + order => 21, + rule => [ + '-A INPUT -p udp', + '-m multiport --dports 33434:33523', + '-m limit --limit 5/sec --limit-burst 20', + '-m comment --comment "reject with icmp udp echo, heavy rate limited"', + '-j REJECT --reject-with icmp-port-unreachable', + ].join(' '), + } + + iptables::ng::advanced_rule { 'v4 drop remaining icmp': + type => 'ipv4', + order => 29, + rule => [ + '-A INPUT -p icmp', + '-m comment --comment "drop remaining icmp"', + '-j DROP', + ].join(' '), + } + + + # IPv6 ICMP + iptables::ng::advanced_rule { 'v6 accept icmp, heavy rate limited': + type => 'ipv6', + order => 20, + rule => [ + '-A INPUT -p ipv6-icmp', + '-m limit --limit 5/sec --limit-burst 20', + '-m comment --comment "accept icmp, heavy rate limited"', + '-j ACCEPT', + ].join(' '), + } + + iptables::ng::advanced_rule { 'v6 reject with icmp udp echo, heavy rate limited': + type => 'ipv6', + order => 21, + rule => [ + '-A INPUT -p udp', + '-m multiport --dports 33434:33523', + '-m limit --limit 5/sec --limit-burst 20', + '-m comment --comment "reject with icmp udp echo, heavy rate limited"', + '-j REJECT --reject-with icmp6-port-unreachable', + ].join(' '), + } + + iptables::ng::advanced_rule { 'v6 drop remaining icmp': + type => 'ipv6', + order => 29, + rule => [ + '-A INPUT -p ipv6-icmp', + '-m comment --comment "drop remaining icmp"', + '-j DROP', + ].join(' '), + } + +} diff --git a/modules/iptables/manifests/ng/rule.pp b/modules/iptables/manifests/ng/rule.pp new file mode 100644 index 00000000..87044c1f --- /dev/null +++ b/modules/iptables/manifests/ng/rule.pp @@ -0,0 +1,116 @@ +# Copyright 2018 dhtech +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file +# +# == Class: iptables::ng::rule +# +# Firewall rules for the firewall lib. +# +# === Parameters +# +# [*type*] +# Version of the IP protocol for this rule. Must be one of `ipv4`, +# `ipv6` or `both` +# +# [*chain*] +# The chaing to place the rule in, defaults to `INPUT` +# +# [*action*] +# What to do with traffic matching the rule. Used as `-j` parameter +# for iptables, defaults to `ACCEPT` +# +# [*source*] +# Source of the traffic, used as `-s` parameter for iptables +# +# [*proto*] +# Protocol of the traffic, used as `-p` parameter for iptables +# +# [*dport*] +# Destination port of the traffic, used as `--dports` parameter +# +# [*sport*] +# Source port of the traffic, used as `--sports` parameter +# +# [*order*] +# Allows you to change the order in which the rules are placed. Defaults +# to `500` + +define iptables::ng::rule ( + + Enum['ipv4', 'ipv6', 'both'] $type, + String $chain = 'INPUT', + Enum['ACCEPT', 'REJECT', ''] $action = 'ACCEPT', + Variant[String, Undef] $source = undef, + Variant[String, Undef] $proto = undef, + Variant[String, Integer, Tuple, Undef] $dport = undef, + Variant[String, Integer, Tuple, Undef] $sport = undef, + Integer $order = 500, + +) { + + include iptables::ng + + + if $source { + $source_line = "-s ${source}" + } + + if $proto { + $proto_line = "-p ${proto}" + } + + if $dport or $sport { + $multiport_line = '-m multiport' + } + + $dport_line = $dport ? { + String => "--dports ${dport}", + Integer => "--dports ${dport}", + Array => "--dports ${dport.join(',')}", + Tuple => "--dports ${dport.join(',')}", + default => undef, + } + + $sport_line = $sport ? { + String => "--sports ${sport}", + Integer => "--sports ${sport}", + Array => "--sports ${sport.join(',')}", + Tuple => "--sports ${sport.join(',')}", + default => undef, + } + + $rule = [ + "-A ${chain}", + $source_line, + $proto_line, + $multiport_line, + $dport_line, + $sport_line, + '-m comment', + "--comment \"${name}\"", + "-j ${action}", + ].filter |$e| { $e =~ NotUndef }.join(' ') + + + if $type in ['ipv4', 'both'] { + + concat::fragment { $name: + target => $::iptables::ng::ipv4file, + order => $order, + content => $rule, + } + + } + + if $type in ['ipv6', 'both'] { + + concat::fragment { $name: + target => $::iptables::ng::ipv6file, + order => $order, + content => $rule, + } + + } + +} diff --git a/modules/iptables/manifests/ng/trailer.pp b/modules/iptables/manifests/ng/trailer.pp new file mode 100644 index 00000000..6e347611 --- /dev/null +++ b/modules/iptables/manifests/ng/trailer.pp @@ -0,0 +1,22 @@ +# Copyright 2018 dhtech +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file +# +class iptables::ng::trailer ( + + Boolean $log_input + +) { + + if $log_input== true { + + iptables::ng::advanced_rule { 'log all': + type => 'both', + order => 999, + rule => '-A INPUT -j LOG', + } + + } + +}