]> gitweb.fluxo.info Git - puppet-ferm.git/commitdiff
implement ipset support
authorTim Meusel <tim@bastelfreak.de>
Mon, 30 Sep 2019 12:51:12 +0000 (14:51 +0200)
committerTim Meusel <tim@bastelfreak.de>
Tue, 1 Oct 2019 14:27:42 +0000 (16:27 +0200)
README.md
REFERENCE.md
manifests/chain.pp
manifests/ipset.pp [new file with mode: 0644]
spec/defines/ipset_spec.rb [new file with mode: 0644]
templates/ferm-chain-ipset.epp [new file with mode: 0644]

index 93edb62111d454cbe3eaf8038b599220b9a2da5a..01217bd49756477e7ad1e24ea8d7e21f5503607c 100644 (file)
--- a/README.md
+++ b/README.md
@@ -64,7 +64,8 @@ You can collect them like this:
 Ferm::Rule <<| tag == 'allow_kafka_server2server' |>>
 ```
 
-You can also define rules in Hiera. Make sure to use `alias()` as interpolation function, because `hiera()` will always return a string.
+You can also define rules in Hiera. Make sure to use `alias()` as interpolation
+function, because `hiera()` will always return a string.
 
 ```yaml
 ---
@@ -94,6 +95,20 @@ defined hashes and hand them over to the class. The main class will create
 rules for all of them. It also collects all exported resources that are tagged
 with the FQDN of a box.
 
+It's also possible to match against [ipsets](http://ipset.netfilter.org/). This
+allows to easily match against a huge amount of IP addresses or network ranges.
+You can use this as follows:
+
+```puppet
+ferm::ipset { 'INPUT':
+  sets => {
+   'office'   => 'ACCPET',
+   'internet' => 'DROP',
+  }
+}
+```
+
+please see the [references](#reference) section for more examples.
 
 ## Examples
 
@@ -131,7 +146,6 @@ The second rule will disable connection tracking for all other traffic coming in
 
 This will prevent your conntrack table from overflowing, tracking only the relevant connections and allowing you to use a stateful ruleset.
 
-
 ## Reference
 
 All parameters are documented within the classes. We generate markdown
index 019c5a4b4f5ef481a731ae81ff956bc2981ec5f5..7e7d518beb05d8840ded88d3d01d91983b162a63 100644 (file)
@@ -18,6 +18,7 @@ _Private Classes_
 **Defined types**
 
 * [`ferm::chain`](#fermchain): This defined resource manages ferm/iptables chains
+* [`ferm::ipset`](#fermipset): a defined resource that can match for ipsets at the top of a chain. This is a per-chain resource. You cannot mix IPv4 and IPv6 sets.
 * [`ferm::rule`](#fermrule): This defined resource manages a single rule in a specific chain
 
 **Data types**
@@ -273,6 +274,81 @@ Default value: $ferm::ip_versions
 
 Default value: $ferm::ip_versions
 
+### ferm::ipset
+
+a defined resource that can match for ipsets at the top of a chain. This is a per-chain resource. You cannot mix IPv4 and IPv6 sets.
+
+* **See also**
+http://ferm.foo-projects.org/download/2.1/ferm.html#set
+
+#### Examples
+
+##### 
+
+```puppet
+ferm::ipset { 'CONSUL':
+  sets => {
+    'internet' => 'ACCEPT'
+  },
+}
+```
+
+##### create to matches for IPv6, both at the end of the `INPUT` chain. Explicitly mention the `filter` table.
+
+```puppet
+ferm::ipset { 'INPUT':
+  prepend_to_chain => false,
+  table            => 'filter',
+  ip_version       => 'ip6',
+  sets             => {
+    'testset01'      => 'ACCEPT',
+    'anothertestset' => 'DROP'
+  },
+}
+```
+
+#### Parameters
+
+The following parameters are available in the `ferm::ipset` defined type.
+
+##### `chain`
+
+Data type: `String[1]`
+
+name of the chain we want to apply those rules to. The name of the defined resource will be used as default value for this.
+
+Default value: $name
+
+##### `table`
+
+Data type: `Ferm::Tables`
+
+name of the table where we want to apply  this. Defaults to `filter` because that's the most common usecase.
+
+Default value: 'filter'
+
+##### `ip_version`
+
+Data type: `Enum['ip','ip6']`
+
+sadly, ip sets are version specific. You cannot mix IPv4 and IPv6 addresses. Because of this you need to provide the version.
+
+Default value: 'ip'
+
+##### `sets`
+
+Data type: `Hash[String[1], Ferm::Actions]`
+
+A hash with multiple sets. For each hash you can provide an action like `DROP` or `ACCEPT`.
+
+##### `prepend_to_chain`
+
+Data type: `Boolean`
+
+
+
+Default value: `true`
+
 ### ferm::rule
 
 This defined resource manages a single rule in a specific chain
index 10cc9c16d14faf7fdf8e4886327c517941758021..1be7e832ffacbcbfb2ec3c37043ae65bc2a6dc06 100644 (file)
@@ -73,6 +73,10 @@ define ferm::chain (
   }
 
   # make sure the generated snippet is actually included
+  # the ordering here is hacked. We might end up with multiple blocks for the same filter+chain.
+  # This happens if we add ipset matches. We suffix this ordering with `bbb`. This allows us to
+  # insert ipset matches before other rules by adding `-aaa` or
+  # insert them at the end by ordering them with `-ccc`.
   concat::fragment{"${table}-${chain}-config-include":
     target  => $ferm::configfile,
     content => epp(
@@ -83,7 +87,7 @@ define ferm::chain (
         'filename' => $filename,
       }
     ),
-    order   => "${table}-${chain}",
+    order   => "${table}-${chain}-bbb",
     require => Concat[$filename],
   }
 }
diff --git a/manifests/ipset.pp b/manifests/ipset.pp
new file mode 100644 (file)
index 0000000..fab7894
--- /dev/null
@@ -0,0 +1,62 @@
+#
+# @summary a defined resource that can match for ipsets at the top of a chain. This is a per-chain resource. You cannot mix IPv4 and IPv6 sets.
+#
+# @see http://ferm.foo-projects.org/download/2.1/ferm.html#set
+#
+# @example
+#   ferm::ipset { 'CONSUL':
+#     sets => {
+#       'internet' => 'ACCEPT'
+#     },
+#   }
+#
+# @example create to matches for IPv6, both at the end of the `INPUT` chain. Explicitly mention the `filter` table.
+#   ferm::ipset { 'INPUT':
+#     prepend_to_chain => false,
+#     table            => 'filter',
+#     ip_version       => 'ip6',
+#     sets             => {
+#       'testset01'      => 'ACCEPT',
+#       'anothertestset' => 'DROP'
+#     },
+#   }
+#
+# @param chain
+#   name of the chain we want to apply those rules to. The name of the defined resource will be used as default value for this.
+#
+# @param table
+#   name of the table where we want to apply  this. Defaults to `filter` because that's the most common usecase.
+#
+# @param ip_version
+#   sadly, ip sets are version specific. You cannot mix IPv4 and IPv6 addresses. Because of this you need to provide the version.
+#
+# @param sets
+#   A hash with multiple sets. For each hash you can provide an action like `DROP` or `ACCEPT`.
+#
+define ferm::ipset (
+  Hash[String[1], Ferm::Actions] $sets,
+  String[1]                      $chain            = $name,
+  Ferm::Tables                   $table            = 'filter',
+  Enum['ip','ip6']               $ip_version       = 'ip',
+  Boolean                        $prepend_to_chain = true,
+) {
+
+  $suffix = $prepend_to_chain ? {
+    true  => 'aaa',
+    false => 'ccc',
+  }
+
+  # make sure the generated snippet is actually included
+  concat::fragment{"${table}-${chain}-ipset":
+    target  => $ferm::configfile,
+    content => epp(
+      "${module_name}/ferm-chain-ipset.epp", {
+        'ip'    => $ip_version,
+        'table' => $table,
+        'chain' => $chain,
+        'sets'  => $sets,
+      }
+    ),
+    order   => "${table}-${chain}-${suffix}",
+  }
+}
diff --git a/spec/defines/ipset_spec.rb b/spec/defines/ipset_spec.rb
new file mode 100644 (file)
index 0000000..050e5ef
--- /dev/null
@@ -0,0 +1,29 @@
+require 'spec_helper'
+
+describe 'ferm::ipset', type: :define do
+  on_supported_os.each do |os, facts|
+    context "on #{os} " do
+      let :facts do
+        facts
+      end
+      let(:title) { 'INPUT' }
+
+      let :pre_condition do
+        'include ferm'
+      end
+
+      context 'default params creates INPUT2 chain' do
+        let :params do
+          {
+            sets: {
+              office: 'ACCEPT',
+              internet: 'DROP'
+            }
+          }
+        end
+
+        it { is_expected.to compile.with_all_deps }
+      end
+    end
+  end
+end
diff --git a/templates/ferm-chain-ipset.epp b/templates/ferm-chain-ipset.epp
new file mode 100644 (file)
index 0000000..79aeb5c
--- /dev/null
@@ -0,0 +1,13 @@
+<%- | String[1] $ip,
+Ferm::Tables $table,
+String[1] $chain,
+Hash[String[1], Ferm::Actions] $sets,
+| -%>
+
+domain (<%= $ip %>) table <%= $table %> {
+    chain <%= $chain %> {
+      <%- $sets.each |$ipset, $action| { -%>
+      mod set set <%= $ipset %> src <%= $action %>;
+      <%- } -%>
+    }
+}