diff --git a/lib/facter/fw_builder_is_docker.rb b/lib/facter/fw_builder_is_docker.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6388b74e49a41b2117f45a65f52a6bd9316270d5
--- /dev/null
+++ b/lib/facter/fw_builder_is_docker.rb
@@ -0,0 +1,9 @@
+Facter.add(:fw_builder_is_docker) do
+  setcode do
+    if Facter::Util::Resolution.which('docker')
+      true
+    else
+      false
+    end
+  end
+end
diff --git a/manifests/chains.pp b/manifests/chains.pp
new file mode 100644
index 0000000000000000000000000000000000000000..ff81dcdc7a1f32236687ccf901c1c5692b8fbe48
--- /dev/null
+++ b/manifests/chains.pp
@@ -0,0 +1,88 @@
+# == Class: fw_builder::chains
+#
+# Pre IPtables allows several icmp type, loopback connection
+# either on IPv6 and IPv4
+#
+# This class opens the firewall to Geant specific servers
+#
+# === Parameters
+#
+# === Requires
+#
+# === Examples
+#
+class fw_builder::chains (
+  $ipv4_enable = $fw_builder::params::ipv4_enable,
+  $ipv6_enable = $fw_builder::params::ipv6_enable
+) {
+
+  assert_private()
+
+  $fw_builder::ip_proto_array.each | String $provider | {
+    $trusted_net = $provider ? {
+      'iptables' => 'trusted_networks_v4',
+      'ip6tables' => 'trusted_networks_v6',
+    }
+    $icmp_proto = $provider ? {
+      'iptables' => 'icmp',
+      'ip6tables' => 'ipv6-icmp',
+    }
+    firewall { "001 accept all inbound to localhost for ${provider}":
+      chain    => 'INPUT',
+      proto    => all,
+      iniface  => 'lo',
+      action   => accept,
+      provider => $provider;
+    }
+    firewall {
+      default:
+        chain    => 'INPUT',
+        action   => accept,
+        provider => 'iptables';
+      "010 accept all icmp for ${provider}":
+        proto    => $icmp_proto;
+      "003 accept inbound related established rules for ${provider}":
+        proto => all,
+        state => ['RELATED', 'ESTABLISHED'];
+    }
+
+    firewall {
+      default:
+        chain    => 'INPUT',
+        jump     => 'INPUT_public',
+        state    => ['NEW'],
+        provider => $provider;
+      "090 UDP INPUT_public for all public services for ${provider}":
+        proto    => 'udp';
+      "090 TCP INPUT_public for all public services for ${provider}":
+        proto    => 'tcp';
+    }
+    firewall { "095 INPUT_trust this is for all ip ranges (mostly internal) for ${provider}":
+      chain    => 'INPUT',
+      proto    => all,
+      state    => ['NEW'],
+      jump     => 'INPUT_trust',
+      ipset    => "${trusted_net} src",
+      provider => $provider;
+    }
+
+  }
+
+  if ($ipv4_enable) {
+    ['udp', 'tcp', 'trust', 'public'].each | $chain | {
+      firewallchain { "INPUT_${chain}:filter:IPv4":
+        ensure  => present;
+      }
+    }
+  }
+
+  if ($ipv6_enable) {
+    ['udp', 'tcp', 'trust', 'public'].each | $chain | {
+      firewallchain { "INPUT_${chain}:filter:IPv6":
+        ensure  => present,
+      }
+    }
+  }
+
+}
+# vim:ts=2:sw=2
diff --git a/manifests/docker.pp b/manifests/docker.pp
new file mode 100644
index 0000000000000000000000000000000000000000..2a13aca0e92d621068f360b048167f1b65324ac9
--- /dev/null
+++ b/manifests/docker.pp
@@ -0,0 +1,63 @@
+# == Class: fw_builder::docker
+#
+# Pre IPtables allows several icmp type, loopback connection
+# either on IPv6 and IPv4
+#
+# This class opens the firewall to Geant specific servers
+#
+# === Parameters
+#
+# === Requires
+#
+# === Examples
+#
+# === ToDo
+#
+# ADD SUPPORT FOR IPv6
+#
+class fw_builder::docker {
+
+  assert_private()
+
+
+  firewallchain { ['INPUT:filter:IPv4', 'OUTPUT:filter:IPv4']:
+    purge  => true,
+    ignore => ['docker', 'br-', 'cali-', 'KUBE'],
+  }
+
+  firewallchain { 'FORWARD:filter:IPv4':
+    purge  => true,
+    ignore => ['docker', 'br-', 'cali-', 'KUBE'],
+  }
+
+  firewallchain { ['DOCKER:nat:IPv4', 'DOCKER:filter:IPv4']:
+    purge  => false,
+  }
+
+  firewallchain { 'POSTROUTING:nat:IPv4':
+    purge  => false,
+  }
+
+  firewallchain { [
+    'INPUT:nat:IPv4', 'PREROUTING:nat:IPv4',
+    'OUTPUT:nat:IPv4', 'PREROUTING:mangle:IPv4',
+    'POSTROUTING:mangle:IPv4', 'INPUT:mangle:IPv4',
+    'FORWARD:mangle:IPv4', 'OUTPUT:mangle:IPv4',
+    'OUTPUT:raw:IPv4', 'PREROUTING:raw:IPv4'
+    ]:
+    purge  => true,
+    ignore => ['DOCKER', 'cali-', 'KUBE'],
+  }
+
+  # this is is for kube / cali
+  firewallchain { [
+    'cali-PREROUTING:mangle:IPv4', 'cali-failsafe-in:mangle:IPv4',
+    'cali-from-host-endpoint:mangle:IPv4', 'cali-failsafe-in:raw:IPv4',
+    'cali-failsafe-out:raw:IPv4', 'cali-from-host-endpoint:raw:IPv4',
+    'cali-to-host-endpoint:raw:IPv4', 'KUBE-SERVICES:filter:IPv4'
+    ]:
+    purge  => false,
+  }
+
+}
+# vim:ts=2:sw=2
diff --git a/manifests/init.pp b/manifests/init.pp
index dad27e829e53f357322e69b9b619afaa253c3896..47077b4cc08bb803393470dae390d40ac69f9091 100644
--- a/manifests/init.pp
+++ b/manifests/init.pp
@@ -1,10 +1,105 @@
 # == Class: fw_builder
 #
+# == Parameters
+#
+# [*trusted_networks*] Fw_builder::Iplist
+# Array of ipv4/ipv6 CIDR/Address
+#
+# [*purge_rules*] Boolean
+# Purge rules not defined via Puppet
+#
+# [*manage_docker*] Boolean
+# If purge rules is set to true, avoid purging rules set by Docker
+#
+# [*ipv4_enable*] Boolean
+# enable iptables provider
+#
+# [*ipv6_enable*] Boolean
+# enable ip6tables provider
+#
+# [*logging*] Boolean
+# enable logging
+#
+# [*log_rotation_days*] Integer
+# define log retention in days
+#
+# [*ipset_package_ensure*] String
+# ipset version
+#
+# [*limit*] Variant[Undef, String]
+# define limit for RST and Dropped connection on post.pp
+#
 # == Authors:
 #
 #   Pete Pedersen<pete.pedersen@geant.org>
 #   Massimiliano Adamo<massimiliano.adamo@geant.org>
 #
-class fw_builder {
-  # resources
+class fw_builder (
+  Fw_builder::Iplist $trusted_networks,
+  Boolean $manage_docker     = $fw_builder::params::manage_docker,
+  Boolean $ipv4_enable       = $fw_builder::params::ipv4_enable,
+  Boolean $ipv6_enable       = $fw_builder::params::ipv6_enable,
+  Boolean $logging           = $fw_builder::params::logging,
+  Boolean $purge_rules       = $fw_builder::params::purge_rules,
+  Integer $log_rotation_days = $fw_builder::params::log_rotation_days,
+  Optional[String] $limit    = $fw_builder::params::limit,
+  $ipset_package_ensure      = $fw_builder::params::ipset_package_ensure
+) {
+
+  if ! ($purge_rules) and ($manage_docker) {
+    fail('cannot set purge_rules to false and manage_docker to true')
+  } elsif ! ($ipv4_enable) and ! ($ipv6_enable) {
+    fail('you cannot disable ipv4 and ipv6 at the same time')
+  }
+
+  if ($ipv4_enable) and ($ipv6_enable) {
+    $ip_proto_array = ['ip6tables', 'iptables']
+  } elsif ($ipv4_enable) and ! ($ipv6_enable) {
+    $ip_proto_array = ['iptables']
+  } elsif ! ($ipv4_enable) and ($ipv6_enable) {
+    $ip_proto_array = ['iptables']
+  }
+
+  anchor { 'fw_builder::begin': }
+  -> class { 'firewall':; }
+  -> class { 'fw_builder::ipset':; }
+  -> class { 'fw_builder::chains':; }
+  -> class { 'fw_builder::post':; }
+  -> anchor { 'fw_builder::end': }
+
+  include fw_builder::logrotate
+
+  if ($purge_rules) {
+    if ($facts['fw_builder_is_docker']) and ($manage_docker) {
+      echo { 'Docker detected':
+        message => 'not purging iptables rules set by docker';
+      }
+      resources { 'firewallchain':
+        purge => false;
+      }
+      class { 'fw_builder::docker':
+        before  => Class['fw_builder::post'],
+        require => Class['fw_builder::ipset'];
+      }
+    } else {
+      if ($ipv4_enable) {
+        firewallchain { 'FORWARD:filter:IPv4':
+          ensure => present,
+          policy => drop,
+          purge  => true;
+        }
+      }
+      if ($ipv6_enable) {
+        firewallchain { 'FORWARD:filter:IPv6':
+          ensure => present,
+          policy => drop,
+          purge  => true;
+        }
+      }
+      resources { 'firewall':
+        purge => true;
+      }
+    }
+  }
+
 }
diff --git a/manifests/ipset.pp b/manifests/ipset.pp
new file mode 100644
index 0000000000000000000000000000000000000000..491313eed3183a7e43c79c45ba538f0be280917f
--- /dev/null
+++ b/manifests/ipset.pp
@@ -0,0 +1,49 @@
+# Class: fw_builder::ipset
+#
+#
+class fw_builder::ipset (
+  $ipv4_enable = $fw_builder::params::ipv4_enable,
+  $ipv6_enable = $fw_builder::params::ipv6_enable
+) {
+
+  assert_private()
+
+  $trusted_net = $fw_builder::trusted_networks
+
+  $firewall_service = $facts['os']['family'] ? {
+    'Debian' => 'netfilter-persistent.service',
+    default => undef
+  }
+
+  $packages = "${facts['os']['family']}_${facts['os']['release']['major']}" ? {
+    'RedHat_6' => ['ipset'],
+    default => undef
+  }
+
+  class { 'ipset':
+    packages         => $packages,
+    package_ensure   => $fw_builder::ipset_package_ensure,
+    firewall_service => $firewall_service
+  }
+
+  if ($ipv4_enable) {
+    $trusted_networks_v4 = $trusted_net.filter |$ip_range| { $ip_range =~ Stdlib::IP::Address::V4 }
+    ipset::set { 'trusted_networks_v4':
+      ensure => 'present',
+      type   => 'hash:net',
+      set    => $trusted_networks_v4;
+    }
+  }
+
+  if ($ipv6_enable) {
+    $trusted_networks_v6 = $trusted_net.filter |$ip_range| { $ip_range =~ Stdlib::IP::Address::V6 }
+    ipset::set { 'trusted_networks_v6':
+      ensure  => 'present',
+      type    => 'hash:net',
+      set     => $trusted_networks_v6,
+      options => {'family' => 'inet6'}
+    }
+  }
+
+}
+# vim:ts=2:sw=2
diff --git a/manifests/logrotate.pp b/manifests/logrotate.pp
new file mode 100644
index 0000000000000000000000000000000000000000..db29cdd8f7d90c6b2d7d12b0c31b8a930485e09a
--- /dev/null
+++ b/manifests/logrotate.pp
@@ -0,0 +1,29 @@
+# == Class: fw_builder
+#
+# == Authors:
+#
+#   Pete Pedersen<pete.pedersen@geant.org>
+#   Massimiliano Adamo<massimiliano.adamo@geant.org>
+#
+class fw_builder::logrotate (
+  $logging           = $fw_builder::params::logging,
+  $log_rotation_days = $fw_builder::params::log_rotation_days
+) {
+
+  assert_private()
+
+  file { ['/var/log/iptables.log', '/var/log/ip6tables.log']: ensure => file; }
+
+  if ($fw_builder::logging) {
+    logrotate::rule { 'iptables':
+      rotate       => $log_rotation_days,
+      dateext      => true,
+      copytruncate => true,
+      missingok    => true,
+      compress     => true,
+      ifempty      => false,
+      path         => '/var/log/ip*tables.log';
+    }
+  }
+
+}
diff --git a/manifests/params.pp b/manifests/params.pp
new file mode 100644
index 0000000000000000000000000000000000000000..623a667f5f427e639c2fce3feeb452629e74bd86
--- /dev/null
+++ b/manifests/params.pp
@@ -0,0 +1,34 @@
+# == Class: fw_builder
+#
+# == Authors:
+#
+#   Pete Pedersen<pete.pedersen@geant.org>
+#   Massimiliano Adamo<massimiliano.adamo@geant.org>
+#
+class fw_builder::params {
+
+  # whether to purge rule not defined in puppet
+  $purge_rules = true
+
+  # avoid that docker rules are being overwritten if purge is set to true
+  $manage_docker = false
+
+  # enable iptables provider
+  $ipv4_enable = true
+
+  # enable ip6tables provider
+  $ipv6_enable = true
+
+  # enable logging
+  $logging = true
+
+  # define log retention daysn
+  $log_rotation_days = 7
+
+  # ipset package version
+  $ipset_package_ensure = 'present'
+
+  # whether to limit RST and dropped connections on post.pp
+  $limit = '1000/sec'
+
+}
diff --git a/manifests/post.pp b/manifests/post.pp
new file mode 100644
index 0000000000000000000000000000000000000000..529af4b19f586950382a1ba12021c490a54b091e
--- /dev/null
+++ b/manifests/post.pp
@@ -0,0 +1,43 @@
+# == Class: fw_builder::post
+#
+class fw_builder::post (
+  $logging = $fw_builder::params::logging
+) {
+
+  assert_private()
+
+  if ($logging) {
+    $fw_builder::ip_proto_array.each | String $provider | {
+      firewall {
+        default:
+          chain     => 'INPUT',
+          provider  => $provider,
+          jump      => 'LOG',
+          limit     => $fw_builder::limit,
+          log_level => '4';
+        "889 log RST dropped inbound chain for provider ${provider}":
+          log_prefix => "[${provider.upcase()} RST RST] dropped";
+        "900 log dropped inbound chain for provider ${provider}":
+          proto      => all,
+          log_prefix => "[${provider.upcase()} INPUT] dropped ",
+      }
+    }
+  }
+
+  $fw_builder::ip_proto_array.each | String $provider | {
+    firewall {
+      default:
+        chain    => 'INPUT',
+        provider => $provider;
+      "910 deny all other inbound requests for provider ${provider}":
+        before => undef,
+        proto  => all,
+        action => 'drop';
+      "890 drop RST RST connections for provider ${provider}":
+        tcp_flags => 'RST RST',
+        action    => 'drop';
+    }
+  }
+
+}
+# vim:ts=2:sw=2