--- install: vm: memory: 128M numcpus: 2 autostart: true disks: primary: /dev/sda scsi: sda: type: image path: "/srv/nvme/{{ inventory_hostname }}/root.img" interfaces: - bridge: br-svc - bridge: br-magenta - bridge: br-mgmt openwrt_arch: x86 openwrt_target: 64 openwrt_profile: generic openwrt_output_image_suffixes: - "{{ openwrt_profile }}-ext4-combined.img.gz" openwrt_packages_remove: - ppp - ppp-mod-pppoe - dnsmasq - firewall - firewall4 - odhcpd - odhcpd-ipv6only openwrt_packages_add: - nftables - kmod-nft-nat - sqm-scripts - rng-tools - htop - ip - less - nano - tcpdump-mini - iperf - iperf3 - mtr - usbutils - openvpn-openssl - kmod-wireguard - wireguard-tools - iptraf-ng - prometheus-node-exporter-lua - prometheus-node-exporter-lua-nat_traffic - prometheus-node-exporter-lua-netstat - prometheus-node-exporter-lua-openwrt openwrt_mixin: /etc/openvpn/ca.crt: content: "{{ openvpn_ca_certificate }}" /etc/openvpn/dhparams: mode: "0600" content: "{{ openvpn_dhparams }}" /etc/openvpn/ta.key: mode: "0600" content: "{{ openvpn_ta_key }}" /etc/openvpn/server.crt: content: | -----BEGIN CERTIFICATE----- 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 8ucdxgsmNPJk/dyj/4vqxQ== -----END CERTIFICATE----- /etc/openvpn/server.key: mode: "0600" content: "{{ vault_openvpn_key }}" /etc/openvpn/ipp.txt: mode: "0444" content: | pan,192.168.8.4 mimas,192.168.8.8 /etc/dropbear/authorized_keys: content: "{{ ssh_keys_root | join('\n') }}\n" /etc/htoprc: file: "{{ global_files_dir }}/common/htoprc" /etc/rc.d/S21nftables: link: "../init.d/nftables" /etc/rc.d/K89nftables: link: "../init.d/nftables" /etc/init.d/nftables: mode: "0755" content: | #!/bin/sh /etc/rc.common START=21 STOP=89 start() { nft -f /etc/nftables.conf } stop() { nft flush ruleset } /etc/nftables.conf: content: | flush ruleset define nic_magenta = eth1 define ip_magenta = {{ network_zones.magenta.prefix | ansible.utils.ipaddr(network_zones.magenta.offsets[inventory_hostname]) | ansible.utils.ipaddr('address') }} define nic_mgmt = eth2 define nic_internal = eth0 define nic_openvpn = extern0 define nic_remote = remote define prefix_mgmt = {{ network_zones.mgmt.prefix }} define prefix_openvpn = 192.168.8.0/24 define prefix_remote = 192.168.51.0/24 define prefix_svc = {{ network_zones.svc.prefix }} define prefixes_internal = { {{ network_zones.svc.prefix }}, {{ network_zones.lan.prefix }} } define prefixes_natonly = { {{ network_zones.c3voc.prefix }} } define ip_prometheus_legacy = {{ network_zones.lan.prefix | ansible.utils.ipaddr(network_zones.lan.offsets['ch-prometheus-legacy']) | ansible.utils.ipaddr('address') }} table inet global { ## INPUT chain input_mgmt { ip saddr $prefix_mgmt accept } chain input_internal { ip saddr != $prefixes_internal drop ip protocol icmp accept ip6 nexthdr ipv6-icmp accept tcp dport { {{ ansible_port }} } accept } chain input_magenta { ip daddr != $ip_magenta drop ip protocol icmp accept ip6 nexthdr ipv6-icmp accept tcp dport { {{ ansible_port }} } accept udp dport { openvpn, 51820 } accept } chain input_openvpn { ip saddr != $prefix_openvpn drop ip protocol icmp accept tcp dport { {{ ansible_port }} } accept } chain input_remote { ip saddr != $prefix_remote drop ip protocol icmp accept tcp dport { {{ ansible_port }} } accept } chain input { type filter hook input priority filter; policy drop; ct state vmap { established: accept, related: accept, invalid: drop } iifname vmap { lo: accept, $nic_mgmt: jump input_mgmt, $nic_internal: jump input_internal, $nic_magenta: jump input_magenta, $nic_openvpn: jump input_openvpn, $nic_remote: jump input_remote } } ## FORWARD chain forward { type filter hook forward priority filter; policy drop; ct state vmap { established: accept, related: accept, invalid: drop } iif $nic_internal ip saddr $prefixes_internal oif $nic_magenta accept iif $nic_internal ip saddr $prefixes_natonly oif $nic_magenta accept iif $nic_internal ip saddr $prefixes_internal oifname $nic_openvpn ip daddr $prefix_openvpn accept iifname $nic_openvpn ip saddr $prefix_openvpn oif $nic_internal ip daddr $prefixes_internal accept iif $nic_internal ip saddr { $prefix_svc, $ip_prometheus_legacy } oifname $nic_remote ip daddr $prefix_remote accept iifname $nic_remote ip saddr $prefix_remote oif $nic_internal ip daddr { $prefix_svc, $ip_prometheus_legacy } accept {% for name, svc in network_services.items() %} iif $nic_magenta oif $nic_internal ip daddr {{ svc.addr }} tcp dport { {{ svc.ports | join(', ') }} } accept comment "Service: {{ name }}" {% endfor %} } chain prerouting { type nat hook prerouting priority dstnat; policy accept; {% for name, svc in network_services.items() %} iif $nic_magenta ip daddr $ip_magenta tcp dport { {{ svc.ports | join(', ') }} } dnat to {{ svc.addr }} comment "Service: {{ name }}" {% endfor %} } chain postrouting { type nat hook postrouting priority srcnat; policy accept; ip saddr $prefixes_internal oif $nic_magenta snat to $ip_magenta ip saddr $prefixes_natonly oif $nic_magenta snat to $ip_magenta } } openwrt_uci: system: - name: system options: hostname: '{{ host_name }}' timezone: 'CET-1CEST,M3.5.0,M10.5.0/3' ttylogin: '0' log_size: '64' urandom_seed: '0' - name: timeserver 'ntp' options: enabled: '1' enable_server: '1' interface: 'mgmt' server: - '0.at.pool.ntp.org' - '1.at.pool.ntp.org' - '2.at.pool.ntp.org' - '3.at.pool.ntp.org' - name: rngd options: enabled: '1' device: '/dev/hwrng' dropbear: - name: dropbear options: PasswordAuth: 'off' RootPasswordAuth: 'off' Port: '{{ ansible_port | default(22) }}' uhttpd: - name: uhttpd main options: enabled: '0' prometheus-node-exporter-lua: - name: prometheus-node-exporter-lua 'main' options: listen_interface: 'mgmt' listen_port: '9100' openvpn: - name: openvpn 'extern' options: enabled: '1' port: '1194' proto: 'udp' dev_type: 'tun' dev: 'extern0' server: '192.168.8.0 255.255.255.0' client_to_client: '1' ifconfig_pool_persist: '/etc/openvpn/ipp.txt' push: - 'route 192.168.28.0 255.255.255.0' - 'route 192.168.32.0 255.255.255.0' tls_auth: '/etc/openvpn/ta.key 0' ca: '/etc/openvpn/ca.crt' cert: '/etc/openvpn/server.crt' key: '/etc/openvpn/server.key' dh: '/etc/openvpn/dhparams' tls_cipher: 'DHE-RSA-AES256-SHA' tls_version_min: '1.1' cipher: 'AES-256-CBC' auth: 'SHA256' comp_lzo: 'yes' keepalive: '10 120' persist_key: '1' persist_tun: '1' user: 'nobody' verb: '3' network: - name: globals 'globals' options: ula_prefix: "fc{{ '%02x:%04x:%04x' | format((255 | random(seed=inventory_hostname + '0')), (65535 | random(seed=inventory_hostname + '1')), (65535 | random(seed=inventory_hostname + '2'))) }}::/48" - name: interface 'loopback' options: device: lo proto: static ipaddr: 127.0.0.1 netmask: 255.0.0.0 - name: interface 'svc' options: device: eth0 proto: static ipaddr: "{{ network_zones.svc.prefix | ansible.utils.ipaddr(network_zones.svc.offsets[inventory_hostname]) | ansible.utils.ipaddr('address') }}" netmask: "{{ network_zones.svc.prefix | ansible.utils.ipaddr('netmask') }}" - name: interface 'magenta' options: device: eth1 proto: static ipaddr: "{{ network_zones.magenta.prefix | ansible.utils.ipaddr(network_zones.magenta.offsets[inventory_hostname]) | ansible.utils.ipaddr('address') }}" netmask: "{{ network_zones.magenta.prefix | ansible.utils.ipaddr('netmask') }}" gateway: "{{ network_zones.magenta.gateway }}" dns: "{{ network_zones.magenta.dns }}" - name: interface 'mgmt' options: device: eth2 proto: static ipaddr: "{{ network_zones.mgmt.prefix | ansible.utils.ipaddr(network_zones.mgmt.offsets[inventory_hostname]) | ansible.utils.ipaddr('address') }}" netmask: "{{ network_zones.mgmt.prefix | ansible.utils.ipaddr('netmask') }}" - name: route 'lan' options: interface: svc target: "{{ network_zones.lan.prefix | ansible.utils.ipaddr('network') }}" netmask: "{{ network_zones.lan.prefix | ansible.utils.ipaddr('netmask') }}" gateway: "{{ network_zones.svc.prefix | ansible.utils.ipaddr(network_zones.svc.offsets['ch-gw-lan']) | ansible.utils.ipaddr('address') }}" - name: route 'c3voc' options: interface: svc target: "{{ network_zones.c3voc.prefix | ansible.utils.ipaddr('network') }}" netmask: "{{ network_zones.c3voc.prefix | ansible.utils.ipaddr('netmask') }}" gateway: "{{ network_zones.svc.prefix | ansible.utils.ipaddr(network_zones.svc.offsets['ch-gw-c3voc']) | ansible.utils.ipaddr('address') }}" - name: interface 'remote' options: proto: wireguard private_key: "{{ vault_wireguard_remote_private_key }}" listen_port: 51820 addresses: - "{{ network_zones.remote.prefix | ansible.utils.ipaddr(network_zones.remote.offsets[inventory_hostname]) }}" nohostroute: 1 - name: wireguard_remote 'pan' options: public_key: "sd/OqiO0hktuJ3FvIBnM8RJpqG0lkN7wWJjdKbU1TSw=" # preshared_key: "" endpoint_host: "{{ hostvars['ch-pan'].network.primary.address | ansible.utils.ipaddr('address') }}" endpoint_port: 51820 allowed_ips: - "{{ network_zones.remote.prefix | ansible.utils.ipaddr(network_zones.remote.offsets['ch-pan']) | ansible.utils.ipaddr('address') }}" persistent_keepalive: 60 - name: wireguard_remote 'mimas' options: public_key: "ZpvJ3Myn/FSJTqsEkNB5AQaVAuTqfFFCAqLomkeZV3g=" # preshared_key: "" endpoint_host: "{{ hostvars['ch-mimas'].external_ip }}" endpoint_port: 51820 allowed_ips: - "{{ network_zones.remote.prefix | ansible.utils.ipaddr(network_zones.remote.offsets['ch-mimas']) | ansible.utils.ipaddr('address') }}" persistent_keepalive: 60 - name: wireguard_remote 'fp4' options: public_key: "m0CoYVrdTQirEnM86ReGJvsabnJKLM6Rph2hnVQllnU=" allowed_ips: - "{{ network_zones.remote.prefix | ansible.utils.ipaddr(network_zones.remote.offsets['ch-equinox-fp4']) | ansible.utils.ipaddr('address') }}" sqm: - name: queue 'magenta' options: enabled: '1' interface: 'eth1' download: '147000' upload: '20000' qdisc: 'cake' script: 'piece_of_cake.qos' qdisc_advanced: '0' ingress_ecn: 'ECN' egress_ecn: 'ECN' qdisc_really_really_advanced: '0' itarget: 'auto' etarget: 'auto' linklayer: 'ethernet' overhead: '18 mpu 64 noatm' prometheus_scrape_endpoint: "{{ network_zones.mgmt.prefix | ansible.utils.ipaddr(network_zones.mgmt.offsets[inventory_hostname]) | ansible.utils.ipaddr('address') }}:9100" prometheus_exporters_default: - openwrt