Files
algo/roles/common/templates/rules.v4.j2
T
984831bcab fix: add explicit bool filters for Ansible 12 jinja2_native compatibility (#14963)
* fix: add explicit bool filters for Ansible 12 jinja2_native compatibility

Ansible 12 enables jinja2_native by default, which means string values
like "true"/"false" are no longer automatically coerced to booleans in
when: conditions and Jinja2 if statements. Add | bool filters to all
boolean variable references in tasks, templates, and handlers.

Also reformats long single-line Jinja2 conditionals into multi-line for
readability, fixes GCE default() calls for native mode, adds help
command to the algo script, and updates test fixtures to register the
bool filter.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* ci: add j2lint for Jinja2 template linting

Add j2lint (aristanetworks/j2lint) to catch syntax errors, spacing
issues, and operator formatting in Jinja2 templates. Integrated into
pre-commit hooks, lint.yml CI, and smart-tests.yml.

Rules S3/S5/S6/S7/V1 are ignored — they enforce conventions
incompatible with Ansible's config-file-embedded templates.

Also fixes int+1 → int + 1 operator spacing in server.conf.j2.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: resolve all ansible-lint warnings and enforce zero-tolerance policy

Fix 18 jinja[spacing] errors across 12 files by moving Jinja2 block
delimiters to prevent YAML >- folding from introducing trailing spaces.

Fix 27 key-order[task] warnings across 17 files by reordering task keys
to canonical order (name → when → tags → environment → become → block).

Promote key-order[task] and yaml[line-length] from warn_list to hard
errors by removing warn_list entirely from .ansible-lint.

Add zero-tolerance warning policy to CLAUDE.md explaining why warnings
are unacceptable in a security tool and documenting resolution order.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 11:21:56 -05:00

120 lines
5.0 KiB
Django/Jinja

{% set subnets = ([strongswan_network] if ipsec_enabled | bool else []) + ([wireguard_network_ipv4] if wireguard_enabled | bool else []) %}
{% set ports = (['500', '4500'] if ipsec_enabled | bool else []) + ([wireguard_port] if wireguard_enabled | bool else []) + ([wireguard_port_actual] if wireguard_enabled | bool and wireguard_port | int == wireguard_port_avoid | int else []) %}
#### The mangle table
# This table allows us to modify packet headers
# Packets enter this table first
#
*mangle
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
{% if reduce_mtu | int > 0 and ipsec_enabled | bool %}
-A FORWARD -s {{ strongswan_network }} -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss {{ 1360 - reduce_mtu | int }}
{% endif %}
COMMIT
#### The nat table
# This table enables Network Address Translation
# (This is technically a type of packet mangling)
#
*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
{% if wireguard_enabled | bool and wireguard_port | int == wireguard_port_avoid | int %}
# Handle the special case of allowing access to WireGuard over an already used
# port like 53
-A PREROUTING -s {{ subnets | join(',') }} -p udp --dport {{ wireguard_port_avoid }} -j RETURN
-A PREROUTING --in-interface {{ ansible_default_ipv4['interface'] }} -p udp --dport {{ wireguard_port_avoid }} -j REDIRECT --to-port {{ wireguard_port_actual }}
{% endif %}
# Allow traffic from the VPN network to the outside world, and replies
{% if ipsec_enabled | bool %}
# For IPsec traffic - NAT the decrypted packets from the VPN subnet
-A POSTROUTING -s {{ strongswan_network }} -o {{ ansible_default_ipv4['interface'] }} {{ '-j SNAT --to ' + snat_aipv4 if snat_aipv4 | bool else '-j MASQUERADE' }}
{% endif %}
{% if wireguard_enabled | bool %}
# For WireGuard traffic - NAT packets from the VPN subnet
-A POSTROUTING -s {{ wireguard_network_ipv4 }} -o {{ ansible_default_ipv4['interface'] }} {{ '-j SNAT --to ' + snat_aipv4 if snat_aipv4 | bool else '-j MASQUERADE' }}
{% endif %}
COMMIT
#### The filter table
# The default ipfilter table
#
*filter
# By default, drop packets that are destined for this server
:INPUT DROP [0:0]
# By default, drop packets that request to be forwarded by this server
:FORWARD DROP [0:0]
# By default, accept any packets originating from this server
:OUTPUT ACCEPT [0:0]
# Accept packets destined for localhost
-A INPUT -i lo -j ACCEPT
# Accept any packet from an open TCP connection
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
# Accept packets using the encapsulation protocol
-A INPUT -p esp -j ACCEPT
-A INPUT -p ah -j ACCEPT
# rate limit ICMP traffic per source
-A INPUT -p icmp --icmp-type echo-request -m hashlimit --hashlimit-upto 5/s --hashlimit-mode srcip --hashlimit-srcmask 32 --hashlimit-name icmp-echo-drop -j ACCEPT
# Accept IPSEC/WireGuard traffic to ports {{ subnets | join(',') }}
-A INPUT -p udp -m multiport --dports {{ ports | join(',') }} -j ACCEPT
# Allow new traffic to port {{ ansible_ssh_port }} (SSH)
-A INPUT -p tcp --dport {{ ansible_ssh_port }} -m conntrack --ctstate NEW -j ACCEPT
{% if ipsec_enabled | bool %}
# Allow any traffic from the IPsec VPN
-A INPUT -p ipencap -m policy --dir in --pol ipsec --proto esp -j ACCEPT
{% endif %}
# TODO:
# The IP of the resolver should be bound to a DUMMY interface.
# DUMMY interfaces are the proper way to install IPs without assigning them any
# particular virtual (tun,tap,...) or physical (ethernet) interface.
# Accept DNS traffic to the local DNS resolver from VPN clients only
-A INPUT -s {{ subnets | join(',') }} -d {{ local_service_ip }} -p udp --dport 53 -j ACCEPT
# Drop traffic between VPN clients
-A FORWARD -s {{ subnets | join(',') }} -d {{ subnets | join(',') }} -j {{ "DROP" if BetweenClients_DROP else "ACCEPT" }}
# Drop traffic to VPN clients from SSH tunnels
-A OUTPUT -d {{ subnets | join(',') }} -m owner --gid-owner 15000 -j {{ "DROP" if BetweenClients_DROP else "ACCEPT" }}
# Drop traffic to the link-local network
-A FORWARD -s {{ subnets | join(',') }} -d 169.254.0.0/16 -j DROP
# Drop traffic to the link-local network from SSH tunnels
-A OUTPUT -d 169.254.0.0/16 -m owner --gid-owner 15000 -j DROP
# Forward any packet that's part of an established connection
-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
# Drop SMB/CIFS traffic that requests to be forwarded
-A FORWARD -p tcp --dport 445 -j {{ "DROP" if block_smb else "ACCEPT" }}
# Drop NETBIOS traffic that requests to be forwarded
-A FORWARD -p udp -m multiport --ports 137,138 -j {{ "DROP" if block_netbios else "ACCEPT" }}
-A FORWARD -p tcp -m multiport --ports 137,139 -j {{ "DROP" if block_netbios else "ACCEPT" }}
{% if ipsec_enabled | bool %}
# Forward any IPSEC traffic from the VPN network
-A FORWARD -m conntrack --ctstate NEW -s {{ strongswan_network }} -m policy --pol ipsec --dir in -j ACCEPT
{% endif %}
{% if wireguard_enabled | bool %}
# Forward any traffic from the WireGuard VPN network
-A FORWARD -m conntrack --ctstate NEW -s {{ wireguard_network_ipv4 }} -j ACCEPT
{% endif %}
COMMIT