Add service ports, ssh port, SNAT rule in nftables

ref: INF-138

Change-Id: I94a80467b30416a288b4a2ac6325427123df4d7d
diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml
index 000dc84..f862af0 100644
--- a/molecule/default/converge.yml
+++ b/molecule/default/converge.yml
@@ -6,7 +6,32 @@
 
 - name: Converge
   hosts: all
+  become: true
+  pre_tasks:
+    - name: Create an additional Docker network
+      docker_network:
+        name: limited_network
+        driver_options:
+          com.docker.network.bridge.name: docker1
+        ipam_options:
+          subnet: '172.27.0.0/16'
+          gateway: 172.27.0.1
   tasks:
     - name: "Include netprep"
       include_role:
         name: "netprep"
+  vars:
+    netprep_router: true
+    netprep_netplan:
+      ethernets:
+        eth0:
+          dhcp4: true
+    netprep_nftables:
+      internal_if: docker0
+      external_if: docker1
+      services:
+        - name: nginx8080
+          port: 8080
+          protocol: tcp
+      allow_subnets:
+        - 172.17.0.0/16
diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml
index 2bf9948..52d6c8f 100644
--- a/molecule/default/molecule.yml
+++ b/molecule/default/molecule.yml
@@ -7,19 +7,15 @@
 dependency:
   name: galaxy
 driver:
-  name: docker
+  name: vagrant
 platforms:
-  - name: "ubuntu-16.04-priv"
-    image: "quay.io/paulfantom/molecule-systemd:ubuntu-16.04"
-    privileged: true
-    volumes:
-      - "/sys/fs/cgroup:/sys/fs/cgroup:ro"
-  - name: "ubuntu-18.04-priv"
-    image: "quay.io/paulfantom/molecule-systemd:ubuntu-18.04"
-    privileged: true
-    volumes:
-      - "/sys/fs/cgroup:/sys/fs/cgroup:ro"
+  - name: instance
+    box: generic/ubuntu1804
+    memory: 512
+    cpus: 1
 provisioner:
   name: ansible
+  playbooks:
+    prepare: prepare.yml
 verifier:
   name: ansible
diff --git a/molecule/default/prepare.yml b/molecule/default/prepare.yml
new file mode 100644
index 0000000..51a37b2
--- /dev/null
+++ b/molecule/default/prepare.yml
@@ -0,0 +1,29 @@
+---
+# netprep molecule/default/prepare.yml
+#
+# SPDX-FileCopyrightText: © 2020 Open Networking Foundation <support@opennetworking.org>
+# SPDX-License-Identifier: Apache-2.0
+- name: Prepare
+  hosts: all
+  become: true
+  vars:
+    acme_username: "www-data"
+    vhosts:
+      - name: "port8080.example.com"
+        insecure_port: 8080
+      - name: "port8081.example.com"
+        insecure_port: 8081
+  pre_tasks:
+    - name: Install testing related packages
+      apt:
+        name:
+          - netplan.io
+          - udev
+          - python3-pip
+        update_cache: true
+    - name: Install Docker SDK for Python
+      pip:
+        name: docker
+  roles:
+    - docker
+    - nginx
diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml
index a96350c..1c1a647 100644
--- a/molecule/default/verify.yml
+++ b/molecule/default/verify.yml
@@ -6,7 +6,52 @@
 
 - name: Verify
   hosts: all
+  become: true
+  vars:
+    nginx_static_dir: "/srv/sites"
   tasks:
-  - name: example assertion
-    assert:
-      that: true
+    - name: Create a test file to be served for port 8080, 8081 nginx server
+      lineinfile:
+        path: "{{ nginx_static_dir }}/{{ item }}.example.com/index.html"
+        line: "This file is served from {{ item }}.example.com"
+        mode: 0644
+        create: true
+      with_items:
+        - "port8080"
+        - "port8081"
+    - name: Create Docker container script
+      file:
+        dest: /tmp/docker_script.sh
+        state: touch
+    - name: Write content into Docker container script
+      lineinfile:
+        dest: /tmp/docker_script.sh
+        line: "{{ item }}"
+      with_items:
+        - "curl 172.17.0.1:8080 --connect-timeout 1 || exit 1"
+        - "curl 172.17.0.1:8081 --connect-timeout 1 || exit 1"
+        - "curl 172.27.0.1:8080 --connect-timeout 1 || exit 1"
+        - "curl 172.27.0.1:8081 --connect-timeout 1 && exit 1"
+        - "sleep 3600"
+    - name: Start a testing container
+      docker_container:
+        name: curl
+        image: curlimages/curl
+        state: started
+        entrypoint: "sh script.sh"
+        networks:
+          - name: bridge
+          - name: limited_network
+        volumes:
+          - /tmp/docker_script.sh:/script.sh
+    - name: Sleep for 5 seconds for curl execution
+      wait_for:
+        timeout: 5
+    - name: Get container's information
+      docker_container_info:
+        name: curl
+      register: result
+    - name: Check container is live (it'll be live if test pass)
+      docker_container_info:
+        name: curl
+      failed_when: result.container["State"]["Running"] != true
diff --git a/templates/nftables.conf.j2 b/templates/nftables.conf.j2
index 95c1439..e710436 100644
--- a/templates/nftables.conf.j2
+++ b/templates/nftables.conf.j2
@@ -9,13 +9,37 @@
 # Primary rules
 table inet filter {
   chain input {
-    type filter hook input priority 0;
+    type filter hook input priority 0; policy drop;
+
+    # The basic rules to accept ICMP and established connection
+    iif "lo" accept
+    ip protocol icmp accept
+    ct state established,related accept
+    ct state invalid drop
+
+    {% if "services" in netprep_nftables %}
+    ## The service present on this server
+    {% for item in netprep_nftables["services"] %}
+    # For service {{ item["name"] }}
+    iif "{{ netprep_nftables["external_if"] }}" {{ item["protocol"] }} dport {{ item["port"]}} accept
+    {% endfor %}
+    {% endif %}
+
+    # Allow SSH on all interfaces
+    tcp dport ssh accept
+
+    {% if "allow_subnets" in netprep_nftables %}
+    # The ingress traffic restriction of internal networks
+      {% for item in netprep_nftables["allow_subnets"] %}
+    iif "{{ netprep_nftables["internal_if"] }}" ip saddr {{ item }} accept
+      {% endfor %}
+    {% endif %}
   }
   chain forward {
-    type filter hook forward priority 0;
+    type filter hook forward priority 0; policy accept;
   }
   chain output {
-    type filter hook output priority 0;
+    type filter hook output priority 0; policy accept;
   }
 }
 
@@ -27,9 +51,14 @@
 
   chain postrouting {
     type nat hook postrouting priority 100;
-    oifname "{{ netprep_nat_if }}" masquerade;
-{% if netprep_nftables_nat_postrouting %}
-{{ netprep_nftables_nat_postrouting | indent(width=4) }}
-{% endif %}
+    oifname "{{ netprep_nftables["internal_if"] }}" masquerade;
+    {% if "ue_routing" in netprep_nftables %}
+    {% for src_subnet in netprep_nftables["ue_routing"]["src_subnets"] %}
+      {% for ue_subnet in netprep_nftables["ue_routing"]["ue_subnets"] %}
+    ip saddr {{ src_subnet }} ip daddr {{ ue_subnet }} counter snat to {{ netprep_nftables["ue_routing"]["snat_addr"] }};
+      {% endfor %}
+    {% endfor %}
+
+    {% endif %}
   }
 }