Implement Advanced Firewalling support
authorEmilien Macchi <emilien@redhat.com>
Mon, 8 Jun 2015 21:45:58 +0000 (17:45 -0400)
committerEmilien Macchi <emilien@redhat.com>
Fri, 12 Jun 2015 18:28:27 +0000 (14:28 -0400)
* 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 [new file with mode: 0644]
manifests/firewall/post.pp [new file with mode: 0644]
manifests/firewall/pre.pp [new file with mode: 0644]
manifests/firewall/rule.pp [new file with mode: 0644]
manifests/init.pp
spec/classes/tripleo_init_spec.rb [new file with mode: 0644]

diff --git a/.fixtures.yml b/.fixtures.yml
new file mode 100644 (file)
index 0000000..e3ab8f9
--- /dev/null
@@ -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 (file)
index 0000000..b76db75
--- /dev/null
@@ -0,0 +1,51 @@
+#
+# Copyright (C) 2015 eNovance SAS <licensing@enovance.com>
+#
+# 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 (file)
index 0000000..2d7203a
--- /dev/null
@@ -0,0 +1,57 @@
+#
+# Copyright (C) 2015 eNovance SAS <licensing@enovance.com>
+#
+# 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 (file)
index 0000000..02afbc2
--- /dev/null
@@ -0,0 +1,80 @@
+#
+# Copyright (C) 2015 eNovance SAS <licensing@enovance.com>
+#
+# 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 })
+
+}
index 9f6d775..cdaf95a 100644 (file)
 #
 # 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 = {},
+) {
+
+  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',
+    })
 
-class tripleo{
+    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 (file)
index 0000000..9f01857
--- /dev/null
@@ -0,0 +1,114 @@
+#
+# Copyright (C) 2015 eNovance SAS <licensing@enovance.com>
+#
+# 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