refactor(security): reworked firewall configuration and added support for DNS, HTTP and ICMP rules; added autoconf for resolv.conf to match FW rules

This commit is contained in:
NaeiKinDus 2024-01-06 00:00:00 +00:00
parent 3a7440f570
commit da45c7c409
Signed by: WoodSmellParticle
GPG key ID: 8E52ADFF7CA8AE56
22 changed files with 169 additions and 48 deletions

View file

@ -1 +1,8 @@
custom_base_user_account: 'vagrant'
custom_security:
firewall:
mangle:
drop_privatenets: false
custom_common:
configure_resolv_conf: true
ip_dualstack: false

View file

@ -14,6 +14,7 @@ common:
install_fonts: false
sysctl: {}
user_account: "{{ custom_base_user_account | default('root') }}"
configure_resolv_conf: false
custom_common: {}
recursive_combine: true

View file

@ -4,6 +4,37 @@
common: "{{ common | combine(custom_common, recursive=recursive_combine) }}"
changed_when: false
- name: '[system] setup DNS server'
block:
- name: disable resolv.conf updates from dhclient
ansible.builtin.copy:
dest: /etc/dhcp/dhclient-enter-hooks.d/nodnsupdate
content: |
#!/bin/sh
make_resolv_conf(){
:
}
owner: root
group: root
mode: '0755'
- name: update resolv.conf
ansible.builtin.template:
src: ../templates/system/resolv.conf.j2
dest: /etc/resolv.conf
mode: '0644'
owner: root
group: root
become: true
when: common.configure_resolv_conf is truthy
- name: '[system] re-allow DHCP client to setup DNS resolvers'
become: true
ansible.builtin.file:
path: /etc/dhcp/dhclient-enter-hooks.d/nodnsupdate
state: absent
failed_when: false
when : common.configure_resolv_conf is falsy
- name: '[apt] verify components of default sources'
become: true
block:

View file

@ -0,0 +1,10 @@
{% if dns[dns.type].dns4 is defined and dns[dns.type].dns4 | length > 0 -%}
{% for server in dns[dns.type].dns4 -%}
nameserver {{ server }}
{% endfor %}
{% endif %}
{% if ip_dualstack | default(false) and dns[dns.type].dns6 is defined and dns[dns.type].dns6 | length > 0 -%}
{% for server in dns[dns.type].dns6 -%}
nameserver {{ server }}
{% endfor %}
{% endif %}

View file

@ -11,23 +11,20 @@ security:
policy:
prerouting: accept
input: accept
postrouting: accept
output: accept
additional_rules: ""
postrouting: accept
mangle:
drop_privatenets: true
policy:
prerouting: accept
postrouting: accept
output: accept
forward: drop
additional_rules: ""
postrouting: accept
filter:
policy:
input: drop
output: drop
forward: drop
additional_rules: ""
custom_security: {}
recursive_combine: true

View file

@ -1,7 +1,7 @@
---
- name: '[firewall] restart service'
become: true
systemd_service:
ansible.builtin.systemd_service:
name: nftables.service
enabled: true
state: restarted

View file

@ -45,7 +45,7 @@
dest: /etc/nftables.conf
mode: '0700'
- name: common firewall rules
- name: base tables definition
ansible.builtin.template:
src: "../templates/system/nftables/{{ item }}.table.j2"
dest: "/etc/nftables.d/{{ item }}.table"
@ -56,3 +56,10 @@
- 01-nat
- 02-mangle
- 03-filter
- name: common firewall rules
ansible.builtin.template:
src: "{{ item }}"
dest: "/etc/nftables.d/{{ (item.split('/') | last)[:-3] }}"
mode: '0600'
loop: "{{ q('fileglob', '../templates/system/nftables.d/*.j2') }}"

View file

@ -4,8 +4,12 @@ flush ruleset
define ansible_controller_ip = {{ supervisor_ip | default('127.0.0.1', true) }}
define ansible_controller_ip6 = {{ supervisor_ip6 | default('fe80::', true) }}
define dns_server = {{ dns_server | default('9.9.9.9', true) }}
define dns_server6 = {{ dns_server | default('2620:fe::fe', true) }}
define dns_servers = {
{{ dns[dns.type].dns4 | default(["9.9.9.9", "149.112.112.112"], true) | join(", ") | wordwrap(40, wrapstring="\n\t") }}
}
define dns_servers6 = {
{{ dns[dns.type].dns6 | default(["2620:fe::fe", "2620:fe::9"], true) | join(", ") | wordwrap(40, wrapstring="\n\t") }}
}
define private_nets = {
10.0.0.0/8, 100.64.0.0/10, 172.16.0.0/12,
192.0.0.0/24, 192.168.0.0/16, 198.18.0.0/15
@ -15,6 +19,7 @@ define reserved_nets = {
192.88.99.0/24, 198.51.100.0/24, 203.0.113.0/24,
224.0.0.0/4, 233.252.0.0/24, 240.0.0.0/4
}
define ssh_localport = {{ ssh_localport | default(22, true) }}
include "/etc/nftables.d/01-nat.table"
include "/etc/nftables.d/02-mangle.table"

View file

@ -0,0 +1,5 @@
table inet filter {
chain output {
meta nfproto { ipv4, ipv6 } tcp dport { http, https } accept
}
}

View file

@ -0,0 +1,14 @@
table inet filter {
chain output {
icmp type {
echo-reply, destination-unreachable, source-quench, redirect, echo-request,
time-exceeded, parameter-problem, timestamp-request, timestamp-reply, info-request,
info-reply, address-mask-request, address-mask-reply, router-advertisement, router-solicitation
} accept
icmpv6 type {
destination-unreachable, packet-too-big, time-exceeded, echo-request, echo-reply, mld-listener-query,
mld-listener-report, mld-listener-reduction, nd-router-solicit, nd-router-advert, nd-neighbor-solicit,
nd-neighbor-advert, parameter-problem, mld2-listener-report
} accept
}
}

View file

@ -0,0 +1,14 @@
table inet filter {
chain input {
icmp type {
echo-reply, destination-unreachable, source-quench, redirect, echo-request,
time-exceeded, parameter-problem, timestamp-request, timestamp-reply, info-request,
info-reply, address-mask-request, address-mask-reply, router-advertisement, router-solicitation
} accept
icmpv6 type {
destination-unreachable, packet-too-big, time-exceeded, echo-request, echo-reply, mld-listener-query,
mld-listener-report, mld-listener-reduction, nd-router-solicit, nd-router-advert, nd-neighbor-solicit,
nd-neighbor-advert, parameter-problem, mld2-listener-report
} accept
}
}

View file

@ -8,11 +8,11 @@ table inet nat {
type nat hook input priority 100; policy {{ firewall.nat.policy.input }};
}
chain postrouting {
type nat hook postrouting priority 100; policy {{ firewall.nat.policy.postrouting }};
}
chain output {
type nat hook output priority -100; policy {{ firewall.nat.policy.output }};
}
chain postrouting {
type nat hook postrouting priority 100; policy {{ firewall.nat.policy.postrouting }};
}
}

View file

@ -2,15 +2,10 @@
table inet mangle {
chain prerouting {
type filter hook prerouting priority -150; policy {{ firewall.mangle.policy.prerouting }};
ip saddr $ansible_controller_ip tcp dport 22 accept
ip6 saddr $ansible_controller_ip6 tcp dport 22 accept
ip daddr $ansible_controller_ip tcp sport 22 accept
ip6 daddr $ansible_controller_ip6 tcp sport 22 accept
ip protocol icmp accept
ip frag-off & 0x1fff != 0 counter drop
ct state invalid counter drop
tcp flags & (fin|syn|rst|ack) != syn ct state new counter drop
tcp flags & (fin|syn|rst|ack) != syn ct state new counter drop
tcp flags & (fin|syn|rst|psh|ack|urg) == 0x0 counter drop
tcp flags & (fin|syn|rst|psh|ack|urg) == fin|syn|rst|psh|ack|urg counter drop
tcp flags & (fin|syn|rst|psh|ack|urg) == 0x0 counter drop
@ -26,6 +21,12 @@ table inet mangle {
tcp flags & (fin|syn|rst|psh|ack|urg) == fin|psh|urg counter drop
tcp flags & (fin|syn|rst|psh|ack|urg) == fin|syn|psh|urg counter drop
tcp flags & (fin|syn|rst|psh|ack|urg) == fin|syn|rst|ack|urg counter drop
ip saddr $ansible_controller_ip tcp dport $ssh_localport accept
ip6 saddr $ansible_controller_ip6 tcp dport $ssh_localport accept
ip daddr $ansible_controller_ip tcp sport $ssh_localport accept
ip6 daddr $ansible_controller_ip6 tcp sport $ssh_localport accept
{% if firewall.mangle.drop_privatenets -%}
ip saddr $private_nets counter drop
{% endif -%}
@ -33,14 +34,6 @@ table inet mangle {
iifname != "lo" ip saddr 127.0.0.0/8 counter drop
}
chain postrouting {
type filter hook postrouting priority -150; policy {{ firewall.mangle.policy.postrouting }};
ip saddr $ansible_controller_ip tcp dport 22 accept
ip6 saddr $ansible_controller_ip6 tcp dport 22 accept
ip daddr $ansible_controller_ip tcp sport 22 accept
ip6 daddr $ansible_controller_ip6 tcp sport 22 accept
}
chain output {
type route hook output priority -150; policy {{ firewall.mangle.policy.output }};
}
@ -48,4 +41,12 @@ table inet mangle {
chain forward {
type filter hook forward priority -150; policy {{ firewall.mangle.policy.forward }};
}
chain postrouting {
type filter hook postrouting priority -150; policy {{ firewall.mangle.policy.postrouting }};
ip saddr $ansible_controller_ip tcp dport $ssh_localport accept
ip6 saddr $ansible_controller_ip6 tcp dport $ssh_localport accept
ip daddr $ansible_controller_ip tcp sport $ssh_localport accept
ip6 daddr $ansible_controller_ip6 tcp sport $ssh_localport accept
}
}

View file

@ -2,22 +2,26 @@
table inet filter {
chain input {
type filter hook input priority 0; policy {{ firewall.filter.policy.input }};
ip saddr $ansible_controller_ip tcp dport 22 accept
ip6 saddr $ansible_controller_ip6 tcp dport 22 accept
ip saddr $ansible_controller_ip tcp dport $ssh_localport accept
ip6 saddr $ansible_controller_ip6 tcp dport $ssh_localport accept
iifname "lo" counter accept
ct state related,established counter accept
tcp dport 22 limit rate 10/hour burst 5 packets counter accept
tcp dport $ssh_localport limit rate 10/hour burst 5 packets counter accept
}
chain output {
type filter hook output priority 0; policy {{ firewall.filter.policy.output }};
ip daddr $ansible_controller_ip tcp sport 22 accept
ip6 daddr $ansible_controller_ip6 tcp sport 22 accept
ip daddr $ansible_controller_ip tcp sport $ssh_localport accept
ip6 daddr $ansible_controller_ip6 tcp sport $ssh_localport accept
oifname "lo" counter accept
ct state related,established counter accept
tcp sport 22 counter accept
tcp sport $ssh_localport counter accept
# Allow DNS queries using UDP, DoT and DoH
ip daddr $dns_servers meta l4proto { tcp, udp } th dport { 53, 443, 953 } accept
ip6 daddr $dns_servers6 meta l4proto { tcp, udp } th dport { 53, 443, 953 } accept
}
chain forward {

View file

@ -1,2 +0,0 @@
custom_base_user_account: '{{ vault_custom_base_user_account }}'
custom_github_token: '{{ vault_custom_github_token }}'

View file

@ -0,0 +1,9 @@
custom_base_user_account: '{{ vault_custom_base_user_account }}'
custom_github_token: '{{ vault_custom_github_token }}'
dns:
type: "dot"
udp: '{{ vault_groups.defaults.udp }}'
dot: '{{ vault_groups.defaults.dot }}'
doh: '{{ vault_groups.defaults.doh }}'
network: "external"
ip_dualstack: true

View file

@ -0,0 +1,15 @@
ansible_become_password: "{{ vault_root_pass }}"
ansible_host: "{{ vault_ansible_host }}"
ansible_user: "{{ vault_ssh_user }}"
custom_security:
firewall:
mangle:
drop_privatenets: false
policy:
forward: accept
dns:
type: "udp"
udp: "{{ vault_groups.network.internal }}"
network: "internal"
ip_dualstack: false

View file

@ -1,3 +1,5 @@
ansible_become_password: "{{ vault_root_pass }}"
ansible_host: "{{ vault_ansible_host }}"
ansible_user: "{{ vault_ssh_user }}"
network: "external"
ip_dualstack: true

View file

@ -32,3 +32,11 @@ custom_security:
drop_privatenets: false
policy:
forward: accept
dns:
type: "udp"
udp:
dns4: "{{ vault_groups.network.internal.dns4 }}"
dns6: "{{ vault_groups.network.internal.dns6 }}"
network: "internal"
ip_dualstack: false

View file

@ -1,3 +0,0 @@
vault_custom_base_user_account: ""
vault_custom_github_token: ""
vault_custom_dockerhub_password: ""

View file

@ -2,15 +2,13 @@
- name: setup external infrastructure
hosts: external
gather_facts: false
vars_files: ../inventory/vault.yml
tasks:
- include_vars: ../inventory/vault.yml
- name: include common role
ansible.builtin.include_role:
name: nullified.infrastructure.common
- name: include security role
ansible.builtin.include_role:
name: nullified.infrastructure.security
- name: include common role
ansible.builtin.include_role:
name: nullified.infrastructure.common
- name: setup servers
hosts: external:&server

View file

@ -2,15 +2,13 @@
- name: setup internal infrastructure
hosts: internal
gather_facts: false
vars_files: ../inventory/vault.yml
tasks:
- include_vars: ../inventory/vault.yml
- name: include common role
ansible.builtin.include_role:
name: nullified.infrastructure.common
- name: include security role
ansible.builtin.include_role:
name: nullified.infrastructure.security
- name: include common role
ansible.builtin.include_role:
name: nullified.infrastructure.common
- name: setup servers
hosts: internal:&server