### Recommended Setup
At the moment you need to provide some setup outside of what we provide in the
-module to support proper ordering, purging and firewall peristence.
+module to support proper ordering and purging.
-So It is recommended that you provide the following in top scope somewhere
-(such as your site.pp):
+Persistence of rules between reboots is handled automatically for the
+supported distributions listed below. Although there are known issues with
+ip6tables on older Debian/Ubuntu and ebtables.
- # Always persist firewall rules
- exec { 'persist-firewall':
- command => $operatingsystem ? {
- 'debian' => '/sbin/iptables-save > /etc/iptables/rules.v4',
- /(RedHat|CentOS)/ => '/sbin/iptables-save > /etc/sysconfig/iptables',
- },
- refreshonly => true,
- }
+It is recommended that you provide the following in top scope somewhere
+(such as your site.pp):
- # These defaults ensure that the persistence command is executed after
- # every change to the firewall, and that pre & post classes are run in the
- # right order to avoid potentially locking you out of your box during the
- # first puppet run.
- Firewall {
- notify => Exec['persist-firewall'],
- before => Class['my_fw::post'],
- require => Class['my_fw::pre'],
- }
- Firewallchain {
- notify => Exec['persist-firewall'],
- }
-
# Purge unmanaged firewall resources
#
# This will clear any existing rules, and make sure that only rules
resources { "firewall":
purge => true
}
+
+ # These defaults ensure that the pre & post classes are run in the right
+ # order to avoid potentially locking you out of your box during the
+ # first puppet run.
+ Firewall {
+ before => Class['my_fw::post'],
+ require => Class['my_fw::pre'],
+ }
You also need to declare the 'my_fw::pre' & 'my_fw::post' classes so that
dependencies are satisfied. This can be achieved using an External Node
--- /dev/null
+Facter.add(:iptables_persistent_version) do
+ confine :operatingsystem => %w{Debian Ubuntu}
+ setcode do
+ cmd = "dpkg-query -Wf '${Version}' iptables-persistent"
+ version = Facter::Util::Resolution.exec(cmd)
+
+ if version.nil? or !version.match(/\d+\.\d+/)
+ nil
+ else
+ version
+ end
+ end
+end
ip6tables_save(*args)
end
+ @protocol = "IPv6"
+
@resource_map = {
:burst => "--limit-burst",
:destination => "-d",
mark_flag = '--set-xmark'
end
+ @protocol = "IPv4"
+
@resource_map = {
:burst => "--limit-burst",
:destination => "-d",
notice("Properties changed - updating rule")
update
end
+ persist_iptables(self.class.instance_variable_get(:@protocol))
@property_hash.clear
end
Puppet::Type.type(:firewallchain).provide :iptables_chain do
+ include Puppet::Util::Firewall
+
@doc = "Iptables chain provider"
has_feature :iptables_chain
def flush
debug("[flush]")
+ persist_iptables(@resource[:name].match(Nameformat)[3])
# Clear the property hash so we re-initialize with updated values
@property_hash.clear
end
+# This is a workaround for bug: #4248 whereby ruby files outside of the normal
+# provider/type path do not load until pluginsync has occured on the puppetmaster
+#
+# In this case I'm trying the relative path first, then falling back to normal
+# mechanisms. This should be fixed in future versions of puppet but it looks
+# like we'll need to maintain this for some time perhaps.
+$LOAD_PATH.unshift(File.join(File.dirname(__FILE__),"..",".."))
+require 'puppet/util/firewall'
+
Puppet::Type.newtype(:firewallchain) do
+ include Puppet::Util::Firewall
@doc = <<-EOS
This type provides the capability to manage rule chains for firewalls.
end
return nil
end
+
+ def persist_iptables(proto)
+ debug("[persist_iptables]")
+
+ # Basic normalisation for older Facter
+ os_key = Facter.value(:osfamily)
+ os_key ||= case Facter.value(:operatingsystem)
+ when 'RedHat', 'CentOS', 'Fedora'
+ 'RedHat'
+ when 'Debian', 'Ubuntu'
+ 'Ubuntu'
+ else
+ Facter.value(:operatingsystem)
+ end
+
+ # Older iptables-persistent doesn't provide save action.
+ if os_key == 'Debian'
+ persist_ver = Facter.value(:iptables_persistent_version)
+ if (persist_ver and Puppet::Util::Package.versioncmp(persist_ver, '0.5.0') < 0)
+ os_key = 'Debian_manual'
+ end
+ end
+
+ cmd = case os_key.to_sym
+ when :RedHat
+ case proto.to_sym
+ when :IPv4
+ %w{/sbin/service iptables save}
+ when :IPv6
+ %w{/sbin/service ip6tables save}
+ end
+ when :Debian
+ case proto.to_sym
+ when :IPv4, :IPv6
+ %w{/usr/sbin/service iptables-persistent save}
+ end
+ when :Debian_manual
+ case proto.to_sym
+ when :IPv4
+ ["/bin/sh", "-c", "/sbin/iptables-save > /etc/iptables/rules"]
+ end
+ end
+
+ # Catch unsupported OSs from the case statement above.
+ if cmd.nil?
+ debug('firewall: Rule persistence is not supported for this type/OS')
+ return
+ end
+
+ begin
+ execute(cmd)
+ rescue Puppet::ExecutionFailure => detail
+ warning("Unable to persist firewall rules: #{detail}")
+ end
+ end
end
# Class: firewall
#
# Manages the installation of packages for operating systems that are
-# currently supported by the firewall type.
+# currently supported by the firewall type.
#
class firewall {
case $::kernel {
describe 'firewall::linux::debian' do
it { should contain_package('iptables-persistent').with(
- :ensure => 'present',
+ :ensure => 'present'
)}
it { should contain_service('iptables-persistent').with(
:ensure => nil,
:enable => 'true',
- :require => 'Package[iptables-persistent]',
+ :require => 'Package[iptables-persistent]'
)}
end
describe 'firewall::linux::redhat' do
it { should contain_service('iptables').with(
:ensure => 'running',
- :enable => 'true',
+ :enable => 'true'
)}
end
--- /dev/null
+require 'spec_helper'
+
+describe "Facter::Util::Fact iptables_persistent_version" do
+ before { Facter.clear }
+ let(:dpkg_cmd) { "dpkg-query -Wf '${Version}' iptables-persistent" }
+
+ {
+ "Debian" => "0.0.20090701",
+ "Ubuntu" => "0.5.3ubuntu2",
+ }.each do |os, ver|
+ describe "#{os} package installed" do
+ before {
+ Facter.fact(:operatingsystem).stubs(:value).returns(os)
+ Facter::Util::Resolution.stubs(:exec).with(dpkg_cmd).returns(ver)
+ }
+ it { Facter.fact(:iptables_persistent_version).value.should == ver }
+ end
+ end
+
+ describe 'Ubuntu package not installed' do
+ before {
+ Facter.fact(:operatingsystem).stubs(:value).returns("Ubuntu")
+ Facter::Util::Resolution.stubs(:exec).with(dpkg_cmd).returns(nil)
+ }
+ it { Facter.fact(:iptables_persistent_version).value.should be_nil }
+ end
+
+ describe 'CentOS not supported' do
+ before { Facter.fact(:operatingsystem).stubs(:value).returns("CentOS") }
+ it { Facter.fact(:iptables_persistent_version).value.should be_nil }
+ end
+end