commit 6be2adf7e1b3776436c99b8c18cc81bd21665750
Author: Luis Fernández Álvarez <luis.fernandez.alvarez@cern.ch>
Date:   Mon Mar 8 13:48:27 2021 +0100

    Add Docker-CE default rules

diff --git a/manifests/rules/docker_ce.pp b/manifests/rules/docker_ce.pp
new file mode 100644
index 0000000..9276dd3
--- /dev/null
+++ b/manifests/rules/docker_ce.pp
@@ -0,0 +1,111 @@
+# @summary Default firewall configuration for Docker-CE
+#
+# The configuration distributed in this class represents the default firewall
+# configuration done by docker-ce when the iptables integration is enabled.
+#
+# This class is needed as the default docker-ce rules added to ip-filter conflict
+# with the inet-filter forward rules set by default in this module.
+#
+# When using this class 'docker::iptables: false' should be set.
+#
+# @param docker_interface
+#   Interface name used by docker. It defaults to docker0.
+# @param docker_prefix
+#   The address space used by docker. It defaults to 172.17.0.0/16.
+#
+class nftables::rules::docker_ce (
+  String[1]                     $docker_interface = 'docker0',
+  Stdlib::IP::Address::V4::CIDR $docker_prefix    = '172.17.0.0/16',
+) {
+  #
+  # inet-filter
+  #
+
+  nftables::chain {
+    'DOCKER': ;
+    'DOCKER_ISOLATION_STAGE_1': ;
+    'DOCKER_ISOLATION_STAGE_2': ;
+    'DOCKER_USER': ;
+  }
+
+  nftables::rule {
+    'DOCKER_ISOLATION_STAGE_1-iifname':
+      order   => '01',
+      content => "iifname \"${docker_interface}\" oifname != \"${docker_interface}\" counter jump DOCKER_ISOLATION_STAGE_2";
+    'DOCKER_ISOLATION_STAGE_1-counter':
+      order   => '02',
+      content => 'counter return';
+    'DOCKER_ISOLATION_STAGE_2-drop':
+      order   => '01',
+      content => "oifname \"${docker_interface}\" counter drop";
+    'DOCKER_ISOLATION_STAGE_2-counter':
+      order   => '02',
+      content => 'counter return';
+    'DOCKER_USER-counter':
+      order   => '01',
+      content => 'counter return',
+  }
+
+  nftables::rule {
+    'default_fwd-jump_docker_user':
+      order   => '40',
+      content => 'counter jump DOCKER_USER';
+    'default_fwd-jump_docker_isolation_stage_1':
+      order   => '41',
+      content => 'counter jump DOCKER_ISOLATION_STAGE_1';
+    'default_fwd-out_docker_accept':
+      order   => '42',
+      content => "oifname \"${docker_interface}\" ct state established,related counter accept";
+    'default_fwd-jump_docker':
+      order   => '43',
+      content => "oifname \"${docker_interface}\" counter jump DOCKER";
+    'default_fwd-idocker_onot_accept':
+      order   => '44',
+      content => "iifname \"${docker_interface}\" oifname != \"${docker_interface}\" counter accept";
+    'default_fwd-idocker_odocker_accept':
+      order   => '45',
+      content => "iifname \"${docker_interface}\" oifname \"${docker_interface}\" counter accept";
+  }
+
+  #
+  # ip-nat
+  #
+
+  nftables::chain {
+    'DOCKER-nat':
+      table => 'ip-nat',
+      chain => 'DOCKER';
+    'OUTPUT-nat':
+      table => 'ip-nat',
+      chain => 'OUTPUT';
+    'INPUT-nat':
+      table => 'ip-nat',
+      chain => 'INPUT';
+  }
+
+  nftables::rule {
+    'POSTROUTING-docker':
+      table   => 'ip-nat',
+      content => "oifname != \"${docker_interface}\" ip saddr ${docker_prefix} counter masquerade";
+    'PREROUTING-docker':
+      table   => 'ip-nat',
+      content => 'fib daddr type local counter jump DOCKER';
+    'OUTPUT-jump_docker@ip-nat':
+      rule_name => 'OUTPUT-jump_docker',
+      table     => 'ip-nat',
+      content   => 'ip daddr != 127.0.0.0/8 fib daddr type local counter jump DOCKER';
+    'DOCKER-counter':
+      table   => 'ip-nat',
+      content => "iifname \"${docker_interface}\" counter return";
+    'INPUT-type@ip-nat':
+      rulename => 'INPUT-type',
+      table    => 'ip-nat',
+      order    => '01',
+      content  => 'type nat hook input priority 100';
+    'INPUT-policy@ip-nat':
+      rulename => 'INPUT-policy',
+      table    => 'ip-nat',
+      order    => '02',
+      content  => 'policy accept';
+  }
+}
diff --git a/spec/acceptance/all_rules_spec.rb b/spec/acceptance/all_rules_spec.rb
index b9f263f..504732e 100644
--- a/spec/acceptance/all_rules_spec.rb
+++ b/spec/acceptance/all_rules_spec.rb
@@ -38,6 +38,7 @@ describe 'nftables class' do
       include nftables::rules::ceph
       include nftables::rules::samba
       include nftables::rules::activemq
+      include nftables::rules::docker_ce
       include nftables::rules::out::postgres
       include nftables::rules::out::icmp
       include nftables::rules::out::dns
diff --git a/spec/classes/rules/docker_ce_spec.rb b/spec/classes/rules/docker_ce_spec.rb
new file mode 100644
index 0000000..20bcbeb
--- /dev/null
+++ b/spec/classes/rules/docker_ce_spec.rb
@@ -0,0 +1,62 @@
+require 'spec_helper'
+
+describe 'nftables::rules::docker_ce' do
+  let(:pre_condition) { 'include nftables' }
+
+  on_supported_os.each do |os, os_facts|
+    context "on #{os}" do
+      let(:facts) { os_facts }
+
+      context 'default options' do
+        it { is_expected.to compile }
+        it { is_expected.to contain_nftables__chain('DOCKER') }
+        it { is_expected.to contain_nftables__chain('DOCKER_ISOLATION_STAGE_1') }
+        it { is_expected.to contain_nftables__chain('DOCKER_ISOLATION_STAGE_2') }
+        it { is_expected.to contain_nftables__chain('DOCKER_USER') }
+        it {
+          is_expected.to contain_nftables__chain('DOCKER-nat').with(
+            chain: 'DOCKER',
+            table: 'ip-nat',
+          )
+        }
+        it {
+          is_expected.to contain_nftables__chain('OUTPUT-nat').with(
+            chain: 'OUTPUT',
+            table: 'ip-nat',
+          )
+        }
+        it {
+          is_expected.to contain_nftables__chain('INPUT-nat').with(
+            chain: 'INPUT',
+            table: 'ip-nat',
+          )
+        }
+        it { is_expected.to contain_nftables__rule('DOCKER_ISOLATION_STAGE_2-drop').with_content('oifname "docker0" counter drop') }
+        it {
+          is_expected.to contain_nftables__rule('POSTROUTING-docker').with(
+            content: 'oifname != "docker0" ip saddr 172.17.0.0/16 counter masquerade',
+            table: 'ip-nat',
+          )
+        }
+      end
+
+      context 'with custom interface and subnet' do
+        let(:params) do
+          {
+            docker_interface: 'ifdo0',
+            docker_prefix: '192.168.4.0/24',
+          }
+        end
+
+        it { is_expected.to compile }
+        it { is_expected.to contain_nftables__rule('DOCKER_ISOLATION_STAGE_2-drop').with_content('oifname "ifdo0" counter drop') }
+        it {
+          is_expected.to contain_nftables__rule('POSTROUTING-docker').with(
+            content: 'oifname != "ifdo0" ip saddr 192.168.4.0/24 counter masquerade',
+            table: 'ip-nat',
+          )
+        }
+      end
+    end
+  end
+end
\ No newline at end of file
