From d091e46dc061d81c3a9e2f561efa15a4ee94a187 Mon Sep 17 00:00:00 2001 From: Emilien Macchi Date: Mon, 8 Jun 2015 17:45:58 -0400 Subject: [PATCH] Implement Advanced Firewalling support * Provide a Define function which will allow to manage IPtables rules. * Manage rules in 'pre' and 'post' Puppet stages, it allows to create rules before and after regular Puppet stages (ie: to make sure no rule exists *before* and everything is blocked *after* regular Puppet stages) Change-Id: I84fc79096f6fc3db76a61d012d8cb62dd12bdd89 --- .fixtures.yml | 6 ++ manifests/firewall/post.pp | 51 +++++++++++++ manifests/firewall/pre.pp | 57 +++++++++++++++ manifests/firewall/rule.pp | 80 +++++++++++++++++++++ manifests/init.pp | 70 +++++++++++++++++- spec/classes/tripleo_init_spec.rb | 114 ++++++++++++++++++++++++++++++ 6 files changed, 377 insertions(+), 1 deletion(-) create mode 100644 .fixtures.yml create mode 100644 manifests/firewall/post.pp create mode 100644 manifests/firewall/pre.pp create mode 100644 manifests/firewall/rule.pp create mode 100644 spec/classes/tripleo_init_spec.rb diff --git a/.fixtures.yml b/.fixtures.yml new file mode 100644 index 000000000..e3ab8f9cd --- /dev/null +++ b/.fixtures.yml @@ -0,0 +1,6 @@ +fixtures: + repositories: + 'firewall': 'git://github.com/puppetlabs/puppetlabs-firewall.git' + 'stdlib': 'git://github.com/puppetlabs/puppetlabs-stdlib.git' + symlinks: + "tripleo": "#{source_dir}" diff --git a/manifests/firewall/post.pp b/manifests/firewall/post.pp new file mode 100644 index 000000000..b76db7593 --- /dev/null +++ b/manifests/firewall/post.pp @@ -0,0 +1,51 @@ +# +# Copyright (C) 2015 eNovance SAS +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# == Class: tripleo::firewall::post +# +# Firewall rules during 'post' Puppet stage +# +# === Parameters: +# +# [*debug*] +# (optional) Set log output to debug output +# Defaults to false +# +# [*firewall_settings*] +# (optional) Allow to add custom parameters to firewall rules +# Should be an hash. +# Default to {} +# +class tripleo::firewall::post( + $debug = false, + $firewall_settings = {}, +){ + + if $debug { + warning('debug is enabled, the traffic is not blocked.') + } else { + firewall { '998 log all': + proto => 'all', + jump => 'LOG', + } + tripleo::firewall::rule{ '999 drop all': + proto => 'all', + action => 'drop', + extras => $firewall_settings, + } + notice('At this stage, all network traffic is blocked.') + } + +} diff --git a/manifests/firewall/pre.pp b/manifests/firewall/pre.pp new file mode 100644 index 000000000..2d7203a66 --- /dev/null +++ b/manifests/firewall/pre.pp @@ -0,0 +1,57 @@ +# +# Copyright (C) 2015 eNovance SAS +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# == Class: tripleo::firewall::pre +# +# Firewall rules during 'pre' Puppet stage +# +# === Parameters: +# +# [*firewall_settings*] +# (optional) Allow to add custom parameters to firewall rules +# Should be an hash. +# Default to {} +# +class tripleo::firewall::pre( + $firewall_settings = {}, +){ + + # ensure the correct packages are installed + include ::firewall + + # defaults 'pre' rules + tripleo::firewall::rule{ '000 accept related established rules': + proto => 'all', + state => ['RELATED', 'ESTABLISHED'], + extras => $firewall_settings, + } + + tripleo::firewall::rule{ '001 accept all icmp': + proto => 'icmp', + extras => $firewall_settings, + } + + tripleo::firewall::rule{ '002 accept all to lo interface': + proto => 'all', + iniface => 'lo', + extras => $firewall_settings, + } + + tripleo::firewall::rule{ '003 accept ssh': + port => '22', + extras => $firewall_settings, + } + +} diff --git a/manifests/firewall/rule.pp b/manifests/firewall/rule.pp new file mode 100644 index 000000000..02afbc2d9 --- /dev/null +++ b/manifests/firewall/rule.pp @@ -0,0 +1,80 @@ +# +# Copyright (C) 2015 eNovance SAS +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# == Define: tripleo::firewall::rule +# +# Define used to manage IPtables rules. +# +# === Parameters: +# +# [*port*] +# (optional) The port associated to the rule. +# Defaults to undef +# +# [*proto*] +# (optional) The protocol associated to the rule. +# Defaults to 'tcp' +# +# [*action*] +# (optional) The action policy associated to the rule. +# Defaults to 'accept' +# +# [*state*] +# (optional) Array of states associated to the rule.. +# Defaults to ['NEW'] +# +# [*source*] +# (optional) The source IP address associated to the rule. +# Defaults to '0.0.0.0/0' +# +# [*iniface*] +# (optional) The network interface associated to the rule. +# Defaults to undef +# +# [*chain*] +# (optional) The chain associated to the rule. +# Defaults to 'INPUT' +# +# [*extras*] +# (optional) Hash of any puppetlabs-firewall supported parameters. +# Defaults to {} +# +define tripleo::firewall::rule ( + $port = undef, + $proto = 'tcp', + $action = 'accept', + $state = ['NEW'], + $source = '0.0.0.0/0', + $iniface = undef, + $chain = 'INPUT', + $extras = {}, +) { + + $basic = { + 'port' => $port, + 'proto' => $proto, + 'action' => $action, + 'state' => $state, + 'source' => $source, + 'iniface' => $iniface, + 'chain' => $chain, + } + + $rule = merge($basic, $extras) + validate_hash($rule) + + create_resources('firewall', { "${title}" => $rule }) + +} diff --git a/manifests/init.pp b/manifests/init.pp index 9f6d77523..cdaf95afb 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -17,7 +17,75 @@ # # Installs the system requirements # +# === Parameters: +# +# [*manage_firewall*] +# (optional) Completely enable or disable firewall settings +# (false means disabled, and true means enabled) +# Defaults to false +# +# [*firewall_rules*] +# (optional) Allow to add custom firewall rules +# Should be an hash. +# Default to {} +# +# [*purge_firewall_rules*] +# (optional) Boolean, purge all firewall resources +# Defaults to false +# +# [*firewall_pre_extras*] +# (optional) Allow to add custom parameters to firewall rules (pre stage) +# Should be an hash. +# Default to {} +# +# [*firewall_post_extras*] +# (optional) Allow to add custom parameters to firewall rules (post stage) +# Should be an hash. +# Default to {} +# +class tripleo( + $manage_firewall = false, + $firewall_rules = {}, + $purge_firewall_rules = false, + $firewall_pre_extras = {}, + $firewall_post_extras = {}, +) { -class tripleo{ + include ::stdlib + + if $manage_firewall { + + # Only purges IPv4 rules + if $purge_firewall_rules { + resources { 'firewall': + purge => true + } + } + + # anyone can add your own rules + # example with Hiera: + # + # tripleo::firewall::rules: + # '300 allow custom application 1': + # port: 999 + # proto: udp + # action: accept + # '301 allow custom application 2': + # port: 8081 + # proto: tcp + # action: accept + # + create_resources('tripleo::firewall::rule', $firewall_rules) + + ensure_resource('class', 'tripleo::firewall::pre', { + 'firewall_settings' => $firewall_pre_extras, + 'stage' => 'setup', + }) + + ensure_resource('class', 'tripleo::firewall::post', { + 'stage' => 'runtime', + 'firewall_settings' => $firewall_post_extras, + }) + } } diff --git a/spec/classes/tripleo_init_spec.rb b/spec/classes/tripleo_init_spec.rb new file mode 100644 index 000000000..9f018575f --- /dev/null +++ b/spec/classes/tripleo_init_spec.rb @@ -0,0 +1,114 @@ +# +# Copyright (C) 2015 eNovance SAS +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Unit tests for tripleo +# + +require 'spec_helper' + +describe 'tripleo' do + + let :params do + { } + end + + shared_examples_for 'tripleo node' do + + context 'with firewall enabled' do + before :each do + params.merge!( + :manage_firewall => true, + ) + end + + it 'configure basic pre firewall rules' do + is_expected.to contain_firewall('000 accept related established rules').with( + :proto => 'all', + :state => ['RELATED', 'ESTABLISHED'], + :action => 'accept', + ) + is_expected.to contain_firewall('001 accept all icmp').with( + :proto => 'icmp', + :action => 'accept', + :state => ['NEW'], + ) + is_expected.to contain_firewall('002 accept all to lo interface').with( + :proto => 'all', + :iniface => 'lo', + :action => 'accept', + :state => ['NEW'], + ) + is_expected.to contain_firewall('003 accept ssh').with( + :port => '22', + :proto => 'tcp', + :action => 'accept', + :state => ['NEW'], + ) + end + + it 'configure basic post firewall rules' do + is_expected.to contain_firewall('999 drop all').with( + :proto => 'all', + :action => 'drop', + :source => '0.0.0.0/0', + ) + end + end + + context 'with custom firewall rules' do + before :each do + params.merge!( + :manage_firewall => true, + :firewall_rules => { + '300 add custom application 1' => {'port' => '999', 'proto' => 'udp', 'action' => 'accept'}, + '301 add custom application 2' => {'port' => '8081', 'proto' => 'tcp', 'action' => 'accept'} + } + ) + end + it 'configure custom firewall rules' do + is_expected.to contain_firewall('300 add custom application 1').with( + :port => '999', + :proto => 'udp', + :action => 'accept', + :state => ['NEW'], + ) + is_expected.to contain_firewall('301 add custom application 2').with( + :port => '8081', + :proto => 'tcp', + :action => 'accept', + :state => ['NEW'], + ) + end + end + + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_configures 'tripleo node' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'tripleo node' + end + +end