diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ac40c83 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,20 @@ +FROM ubuntu:16.04 +MAINTAINER Mischa ter Smitten + +# python +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y python-minimal python-dev curl && \ + apt-get clean +RUN curl -sL https://bootstrap.pypa.io/get-pip.py | python - +RUN rm -rf $HOME/.cache + +# ansible +RUN DEBIAN_FRONTEND=noninteractive apt-get install -y gcc libffi-dev libssl-dev net-tools iproute2 ethtool && \ + apt-get clean +RUN pip install ansible==2.6.2 +RUN rm -rf $HOME/.cache + +# provision +COPY . /etc/ansible/roles/ansible-role +WORKDIR /etc/ansible/roles/ansible-role +RUN ansible-playbook -i tests/inventory tests/test.yml --connection=local diff --git a/Vagrantfile b/Vagrantfile index 653c851..3517233 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -53,6 +53,13 @@ boxes = [ :cpu => "50", :ram => "256" }, + { + :name => "debian-10", + :box => "bento/debian-10", + :ip => '10.0.0.18', + :cpu => "50", + :ram => "256" + }, ] Vagrant.configure("2") do |config| diff --git a/defaults/main.yml b/defaults/main.yml index 37730c6..e9d0ccd 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -23,3 +23,15 @@ ufw_etc_default_ipt_modules: - nf_conntrack_ftp - nf_nat_ftp - nf_conntrack_netbios_ns + +ufw_etc_ufw_after_manage: false +ufw_etc_ufw_after6_rules: [] +ufw_etc_ufw_after_rules: [] + +ufw_etc_ufw_before_manage: false +ufw_etc_ufw_before6_rules: [] +ufw_etc_ufw_before_rules: [] + +ufw_etc_ufw_user_manage: false +ufw_etc_ufw_user6_rules: [] +ufw_etc_ufw_user_rules: [] diff --git a/meta/main.yml b/meta/main.yml index 9fd3f0a..ff60999 100644 --- a/meta/main.yml +++ b/meta/main.yml @@ -19,6 +19,7 @@ galaxy_info: - wheezy - jessie - stretch + - buster galaxy_tags: - system - networking diff --git a/tasks/configure.yml b/tasks/configure.yml index aa39ca8..e3d604c 100644 --- a/tasks/configure.yml +++ b/tasks/configure.yml @@ -2,7 +2,7 @@ --- - name: configure | create (local facts) directory file: - path: /etc/ansible/facts.d/ + path: "{{ ufw_etc_ansible_facts_file | dirname }}/" state: directory owner: root group: root @@ -18,22 +18,26 @@ group: root mode: 0644 with_items: - - src: etc/default/ufw.j2 - dest: /etc/default/ufw - - src: etc/ansible/facts.d/ufw.fact.j2 - dest: /etc/ansible/facts.d/ufw.fact - register: configuration + - src: "{{ ufw_etc_default_file.lstrip('/') }}.j2" + dest: "{{ ufw_etc_default_file }}" + - src: "{{ ufw_etc_ansible_facts_file.lstrip('/') }}.j2" + dest: "{{ ufw_etc_ansible_facts_file }}" + register: _configuration tags: - ufw-configure-facts - name: configure | reset ufw: state: reset - when: configuration is changed + when: > + _configuration is changed +# or _after_rules is changed +# or _before_rules is changed +# or _user_rules is changed tags: - ufw-configure-reset -- name: configure | default (incoming) policy +- name: configure | default policy | incoming ufw: policy: "{{ ufw_default_incoming_policy }}" direction: incoming @@ -42,7 +46,7 @@ - ufw-configure-default-policy - ufw-configure-default-policy-incoming -- name: configure | default (outgoing) policy +- name: configure | default policy | outgoing ufw: policy: "{{ ufw_default_outgoing_policy }}" direction: outgoing @@ -75,3 +79,60 @@ notify: reload ufw tags: - ufw-configure-logging + +- name: configure | rules | update after file(s) + template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + owner: root + group: root + mode: 0640 + with_items: + - src: "{{ ufw_etc_ufw_after6_rules_file.lstrip('/') }}.j2" + dest: "{{ ufw_etc_ufw_after6_rules_file }}" + - src: "{{ ufw_etc_ufw_after_rules_file.lstrip('/') }}.j2" + dest: "{{ ufw_etc_ufw_after_rules_file }}" + when: ufw_etc_ufw_after_manage | bool + register: _after_rules + notify: reload ufw + tags: + - ufw-configure-rules + - ufw-configure-rules-after + +- name: configure | rules | update before file(s) + template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + owner: root + group: root + mode: 0640 + with_items: + - src: "{{ ufw_etc_ufw_before6_rules_file.lstrip('/') }}.j2" + dest: "{{ ufw_etc_ufw_before6_rules_file }}" + - src: "{{ ufw_etc_ufw_before_rules_file.lstrip('/') }}.j2" + dest: "{{ ufw_etc_ufw_before_rules_file }}" + when: ufw_etc_ufw_before_manage | bool + register: _before_rules + notify: reload ufw + tags: + - ufw-configure-rules + - ufw-configure-rules-before + +- name: configure | rules | update user file(s) + template: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + owner: root + group: root + mode: 0640 + with_items: + - src: "{{ ufw_etc_ufw_user6_rules_file.lstrip('/') }}.j2" + dest: "{{ ufw_etc_ufw_user6_rules_file }}" + - src: "{{ ufw_etc_ufw_user_rules_file.lstrip('/') }}.j2" + dest: "{{ ufw_etc_ufw_user_rules_file }}" + when: ufw_etc_ufw_user_manage | bool + register: _user_rules + notify: reload ufw + tags: + - ufw-configure-rules + - ufw-configure-rules-user diff --git a/templates/etc/ufw/after.rules.j2 b/templates/etc/ufw/after.rules.j2 new file mode 100644 index 0000000..f7804a7 --- /dev/null +++ b/templates/etc/ufw/after.rules.j2 @@ -0,0 +1,5 @@ +# {{ ansible_managed }} + +{% for line in ufw_etc_ufw_after_rules | default([]) %} +{{ line }} +{% endfor %} diff --git a/templates/etc/ufw/after6.rules.j2 b/templates/etc/ufw/after6.rules.j2 new file mode 100644 index 0000000..ecc426e --- /dev/null +++ b/templates/etc/ufw/after6.rules.j2 @@ -0,0 +1,5 @@ +# {{ ansible_managed }} + +{% for line in ufw_etc_ufw_after6_rules | default([]) %} +{{ line }} +{% endfor %} diff --git a/templates/etc/ufw/before.rules.j2 b/templates/etc/ufw/before.rules.j2 new file mode 100644 index 0000000..b9761d8 --- /dev/null +++ b/templates/etc/ufw/before.rules.j2 @@ -0,0 +1,5 @@ +# {{ ansible_managed }} + +{% for line in ufw_etc_ufw_before_rules | default([]) %} +{{ line }} +{% endfor %} diff --git a/templates/etc/ufw/before6.rules.j2 b/templates/etc/ufw/before6.rules.j2 new file mode 100644 index 0000000..ee42f15 --- /dev/null +++ b/templates/etc/ufw/before6.rules.j2 @@ -0,0 +1,5 @@ +# {{ ansible_managed }} + +{% for line in ufw_etc_ufw_before6_rules | default([]) %} +{{ line }} +{% endfor %} diff --git a/templates/etc/ufw/user.rules.j2 b/templates/etc/ufw/user.rules.j2 new file mode 100644 index 0000000..478c6bf --- /dev/null +++ b/templates/etc/ufw/user.rules.j2 @@ -0,0 +1,5 @@ +# {{ ansible_managed }} + +{% for line in ufw_etc_ufw_user_rules | default([]) %} +{{ line }} +{% endfor %} diff --git a/templates/etc/ufw/user6.rules.j2 b/templates/etc/ufw/user6.rules.j2 new file mode 100644 index 0000000..eb86df6 --- /dev/null +++ b/templates/etc/ufw/user6.rules.j2 @@ -0,0 +1,5 @@ +# {{ ansible_managed }} + +{% for line in ufw_etc_ufw_user6_rules | default([]) %} +{{ line }} +{% endfor %} diff --git a/tests/vagrant.yml b/tests/vagrant.yml index aa0b5e2..63fa724 100644 --- a/tests/vagrant.yml +++ b/tests/vagrant.yml @@ -5,3 +5,224 @@ become: true roles: - ../../ + vars: + ufw_etc_ufw_before_manage: true + ufw_etc_ufw_before6_rules: + - | + # + # rules.before + # + # Rules that should be run before the ufw command line added rules. Custom + # rules should be added to one of these chains: + # ufw6-before-input + # ufw6-before-output + # ufw6-before-forward + # + + # Don't delete these required lines, otherwise there will be errors + *filter + :ufw6-before-input - [0:0] + :ufw6-before-output - [0:0] + :ufw6-before-forward - [0:0] + # End required lines + + + # allow all on loopback + -A ufw6-before-input -i lo -j ACCEPT + -A ufw6-before-output -o lo -j ACCEPT + + # drop packets with RH0 headers + -A ufw6-before-input -m rt --rt-type 0 -j DROP + -A ufw6-before-forward -m rt --rt-type 0 -j DROP + -A ufw6-before-output -m rt --rt-type 0 -j DROP + + # quickly process packets for which we already have a connection + -A ufw6-before-input -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT + -A ufw6-before-output -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT + -A ufw6-before-forward -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT + + # drop INVALID packets (logs these in loglevel medium and higher) + -A ufw6-before-input -m conntrack --ctstate INVALID -j ufw6-logging-deny + -A ufw6-before-input -m conntrack --ctstate INVALID -j DROP + + # ok icmp codes for INPUT (rfc4890, 4.4.1 and 4.4.2) + -A ufw6-before-input -p icmpv6 --icmpv6-type destination-unreachable -j ACCEPT + -A ufw6-before-input -p icmpv6 --icmpv6-type packet-too-big -j ACCEPT + # codes 0 and 1 + -A ufw6-before-input -p icmpv6 --icmpv6-type time-exceeded -j ACCEPT + # codes 0-2 + -A ufw6-before-input -p icmpv6 --icmpv6-type parameter-problem -j ACCEPT + -A ufw6-before-input -p icmpv6 --icmpv6-type echo-request -j ACCEPT + -A ufw6-before-input -p icmpv6 --icmpv6-type echo-reply -j ACCEPT + -A ufw6-before-input -p icmpv6 --icmpv6-type router-solicitation -m hl --hl-eq 255 -j ACCEPT + -A ufw6-before-input -p icmpv6 --icmpv6-type router-advertisement -m hl --hl-eq 255 -j ACCEPT + -A ufw6-before-input -p icmpv6 --icmpv6-type neighbor-solicitation -m hl --hl-eq 255 -j ACCEPT + -A ufw6-before-input -p icmpv6 --icmpv6-type neighbor-advertisement -m hl --hl-eq 255 -j ACCEPT + # IND solicitation + -A ufw6-before-input -p icmpv6 --icmpv6-type 141 -m hl --hl-eq 255 -j ACCEPT + # IND advertisement + -A ufw6-before-input -p icmpv6 --icmpv6-type 142 -m hl --hl-eq 255 -j ACCEPT + # MLD query + -A ufw6-before-input -p icmpv6 --icmpv6-type 130 -s fe80::/10 -j ACCEPT + # MLD report + -A ufw6-before-input -p icmpv6 --icmpv6-type 131 -s fe80::/10 -j ACCEPT + # MLD done + -A ufw6-before-input -p icmpv6 --icmpv6-type 132 -s fe80::/10 -j ACCEPT + # MLD report v2 + -A ufw6-before-input -p icmpv6 --icmpv6-type 143 -s fe80::/10 -j ACCEPT + # SEND certificate path solicitation + -A ufw6-before-input -p icmpv6 --icmpv6-type 148 -m hl --hl-eq 255 -j ACCEPT + # SEND certificate path advertisement + -A ufw6-before-input -p icmpv6 --icmpv6-type 149 -m hl --hl-eq 255 -j ACCEPT + # MR advertisement + -A ufw6-before-input -p icmpv6 --icmpv6-type 151 -s fe80::/10 -m hl --hl-eq 1 -j ACCEPT + # MR solicitation + -A ufw6-before-input -p icmpv6 --icmpv6-type 152 -s fe80::/10 -m hl --hl-eq 1 -j ACCEPT + # MR termination + -A ufw6-before-input -p icmpv6 --icmpv6-type 153 -s fe80::/10 -m hl --hl-eq 1 -j ACCEPT + + # ok icmp codes for OUTPUT (rfc4890, 4.4.1 and 4.4.2) + -A ufw6-before-output -p icmpv6 --icmpv6-type destination-unreachable -j ACCEPT + -A ufw6-before-output -p icmpv6 --icmpv6-type packet-too-big -j ACCEPT + # codes 0 and 1 + -A ufw6-before-output -p icmpv6 --icmpv6-type time-exceeded -j ACCEPT + # codes 0-2 + -A ufw6-before-output -p icmpv6 --icmpv6-type parameter-problem -j ACCEPT + -A ufw6-before-input -p icmpv6 --icmpv6-type echo-request -j ACCEPT + -A ufw6-before-input -p icmpv6 --icmpv6-type echo-reply -j ACCEPT + -A ufw6-before-output -p icmpv6 --icmpv6-type router-solicitation -m hl --hl-eq 255 -j ACCEPT + -A ufw6-before-output -p icmpv6 --icmpv6-type neighbor-advertisement -m hl --hl-eq 255 -j ACCEPT + -A ufw6-before-output -p icmpv6 --icmpv6-type neighbor-solicitation -m hl --hl-eq 255 -j ACCEPT + -A ufw6-before-output -p icmpv6 --icmpv6-type router-advertisement -m hl --hl-eq 255 -j ACCEPT + # IND solicitation + -A ufw6-before-output -p icmpv6 --icmpv6-type 141 -m hl --hl-eq 255 -j ACCEPT + # IND advertisement + -A ufw6-before-output -p icmpv6 --icmpv6-type 142 -m hl --hl-eq 255 -j ACCEPT + # MLD query + -A ufw6-before-output -p icmpv6 --icmpv6-type 130 -s fe80::/10 -j ACCEPT + # MLD report + -A ufw6-before-output -p icmpv6 --icmpv6-type 131 -s fe80::/10 -j ACCEPT + # MLD done + -A ufw6-before-output -p icmpv6 --icmpv6-type 132 -s fe80::/10 -j ACCEPT + # MLD report v2 + -A ufw6-before-output -p icmpv6 --icmpv6-type 143 -s fe80::/10 -j ACCEPT + # SEND certificate path solicitation + -A ufw6-before-output -p icmpv6 --icmpv6-type 148 -m hl --hl-eq 255 -j ACCEPT + # SEND certificate path advertisement + -A ufw6-before-output -p icmpv6 --icmpv6-type 149 -m hl --hl-eq 255 -j ACCEPT + # MR advertisement + -A ufw6-before-output -p icmpv6 --icmpv6-type 151 -s fe80::/10 -m hl --hl-eq 1 -j ACCEPT + # MR solicitation + -A ufw6-before-output -p icmpv6 --icmpv6-type 152 -s fe80::/10 -m hl --hl-eq 1 -j ACCEPT + # MR termination + -A ufw6-before-output -p icmpv6 --icmpv6-type 153 -s fe80::/10 -m hl --hl-eq 1 -j ACCEPT + + # ok icmp codes for FORWARD (rfc4890, 4.3.1) + -A ufw6-before-forward -p icmpv6 --icmpv6-type destination-unreachable -j ACCEPT + -A ufw6-before-forward -p icmpv6 --icmpv6-type packet-too-big -j ACCEPT + # codes 0 and 1 + -A ufw6-before-forward -p icmpv6 --icmpv6-type time-exceeded -j ACCEPT + # codes 0-2 + -A ufw6-before-forward -p icmpv6 --icmpv6-type parameter-problem -j ACCEPT + -A ufw6-before-forward -p icmpv6 --icmpv6-type echo-request -j ACCEPT + -A ufw6-before-forward -p icmpv6 --icmpv6-type echo-reply -j ACCEPT + # ok icmp codes for FORWARD (rfc4890, 4.3.2) + # Home Agent Address Discovery Reques + -A ufw6-before-input -p icmpv6 --icmpv6-type 144 -j ACCEPT + # Home Agent Address Discovery Reply + -A ufw6-before-input -p icmpv6 --icmpv6-type 145 -j ACCEPT + # Mobile Prefix Solicitation + -A ufw6-before-input -p icmpv6 --icmpv6-type 146 -j ACCEPT + # Mobile Prefix Advertisement + -A ufw6-before-input -p icmpv6 --icmpv6-type 147 -j ACCEPT + + # allow dhcp client to work + -A ufw6-before-input -p udp -s fe80::/10 --sport 547 -d fe80::/10 --dport 546 -j ACCEPT + + # allow MULTICAST mDNS for service discovery + -A ufw6-before-input -p udp -d ff02::fb --dport 5353 -j ACCEPT + + # allow MULTICAST UPnP for service discovery + -A ufw6-before-input -p udp -d ff02::f --dport 1900 -j ACCEPT + + # don't delete the 'COMMIT' line or these rules won't be processed + COMMIT + ufw_etc_ufw_before_rules: + - | + # + # rules.before + # + # Rules that should be run before the ufw command line added rules. Custom + # rules should be added to one of these chains: + # ufw-before-input + # ufw-before-output + # ufw-before-forward + # + + # Don't delete these required lines, otherwise there will be errors + *filter + :ufw-before-input - [0:0] + :ufw-before-output - [0:0] + :ufw-before-forward - [0:0] + :ufw-not-local - [0:0] + # End required lines + + + # allow all on loopback + -A ufw-before-input -i lo -j ACCEPT + -A ufw-before-output -o lo -j ACCEPT + + # quickly process packets for which we already have a connection + -A ufw-before-input -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT + -A ufw-before-output -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT + -A ufw-before-forward -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT + + # drop INVALID packets (logs these in loglevel medium and higher) + -A ufw-before-input -m conntrack --ctstate INVALID -j ufw-logging-deny + -A ufw-before-input -m conntrack --ctstate INVALID -j DROP + + # ok icmp codes for INPUT + -A ufw-before-input -p icmp --icmp-type destination-unreachable -j DROP + -A ufw-before-input -p icmp --icmp-type source-quench -j DROP + -A ufw-before-input -p icmp --icmp-type time-exceeded -j DROP + -A ufw-before-input -p icmp --icmp-type parameter-problem -j DROP + -A ufw-before-input -p icmp --icmp-type echo-request -j DROP + + # ok icmp code for FORWARD + -A ufw-before-forward -p icmp --icmp-type destination-unreachable -j ACCEPT + -A ufw-before-forward -p icmp --icmp-type source-quench -j ACCEPT + -A ufw-before-forward -p icmp --icmp-type time-exceeded -j ACCEPT + -A ufw-before-forward -p icmp --icmp-type parameter-problem -j ACCEPT + -A ufw-before-forward -p icmp --icmp-type echo-request -j ACCEPT + + # allow dhcp client to work + -A ufw-before-input -p udp --sport 67 --dport 68 -j ACCEPT + + # + # ufw-not-local + # + -A ufw-before-input -j ufw-not-local + + # if LOCAL, RETURN + -A ufw-not-local -m addrtype --dst-type LOCAL -j RETURN + + # if MULTICAST, RETURN + -A ufw-not-local -m addrtype --dst-type MULTICAST -j RETURN + + # if BROADCAST, RETURN + -A ufw-not-local -m addrtype --dst-type BROADCAST -j RETURN + + # all other non-local packets are dropped + -A ufw-not-local -m limit --limit 3/min --limit-burst 10 -j ufw-logging-deny + -A ufw-not-local -j DROP + + # allow MULTICAST mDNS for service discovery (be sure the MULTICAST line above + # is uncommented) + -A ufw-before-input -p udp -d 224.0.0.251 --dport 5353 -j ACCEPT + + # allow MULTICAST UPnP for service discovery (be sure the MULTICAST line above + # is uncommented) + -A ufw-before-input -p udp -d 239.255.255.250 --dport 1900 -j ACCEPT + + # don't delete the 'COMMIT' line or these rules won't be processed + COMMIT diff --git a/vars/main.yml b/vars/main.yml index 63ef6a6..ed03946 100644 --- a/vars/main.yml +++ b/vars/main.yml @@ -7,4 +7,21 @@ ufw_facts: default_incoming_policy: "{{ ufw_default_incoming_policy }}" default_outgoing_policy: "{{ ufw_default_outgoing_policy }}" logging: "{{ ufw_logging }}" - rules: "{{ ufw_rules }}" +# after6_rules: "{{ ufw_etc_ufw_after6_rules }}" +# after_rules: "{{ ufw_etc_ufw_after6_rules }}" +# before6_rules: "{{ ufw_etc_ufw_before6_rules }}" +# before_rules: "{{ ufw_etc_ufw_before_rules }}" +# user6_rules: "{{ ufw_etc_ufw_user6_rules }}" +# user_rules: "{{ ufw_etc_ufw_user_rules }}" + +ufw_etc_default_file: /etc/default/ufw +ufw_etc_ansible_facts_file: /etc/ansible/facts.d/ufw.fact + +ufw_etc_ufw_after6_rules_file: /etc/ufw/after6.rules +ufw_etc_ufw_after_rules_file: /etc/ufw/after.rules + +ufw_etc_ufw_before6_rules_file: /etc/ufw/before6.rules +ufw_etc_ufw_before_rules_file: /etc/ufw/before.rules + +ufw_etc_ufw_user6_rules_file: /etc/ufw/user6.rules +ufw_etc_ufw_user_rules_file: /etc/ufw/user.rules