*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
:LOGNDROP - [0:0]

{% if enable_ssh_over_tor %}
# Prod ssh connections happen through an authenticated Tor Onion Service
# The ssh connection is proxied on the server by the tor client to
# the ssh dameon listening on the local loopback.
# Limit the number of new tcp connections allowed by the tor user to the ssh dameon
# listening on the local loopback. Drop new connection attempts after the limit
# by the tor user.
# limit-burst is set to '3' which means the limit of 3/min only starts after the
# first three connection are made. To test will need to try to create 7 connections.
# The 7th (and any additional attempts during that minute) will be dropped.
-A OUTPUT -o lo -p tcp --dport 22 -m owner --uid-owner debian-tor -m state --state NEW -m limit --limit 3/min --limit-burst 3 -j ACCEPT -m comment --comment "Rate limit traffic from tor to the ssh dameon"
-A OUTPUT -o lo -p tcp --dport 22 -m owner --uid-owner debian-tor -m state --state NEW -j LOGNDROP -m comment --comment "Drop all other new connections from tor to the ssh dameon"
-A OUTPUT -o lo -p tcp --dport 22 -m owner --uid-owner debian-tor -m state --state ESTABLISHED,RELATED -j ACCEPT -m comment --comment "Allow the established traffic from tor to the ssh dameon"
{% endif %}

# Load before tor user drop rules
-A OUTPUT -p tcp -m owner --uid-owner debian-tor -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT -m comment --comment "Allow tor outbound"
-A INPUT -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT -m comment --comment "Allow traffic back for tor"

# Drop all other outbound traffic by the tor user.
# Load before generic loopback rules
-A OUTPUT -m owner --uid-owner debian-tor -j LOGNDROP -m comment --comment "Drop all other traffic for tor"

{% if 'securedrop_application_server' in group_names %}
# Only allow inbound rules from loopback with a dport of 80 or 8080 respectively for apache user
# Load before application users drop rules
# Rate limiting does not make sense here because src ip is always loopback address
-A INPUT -i lo -p tcp --dport 80 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT -m comment --comment "Allow tor connection from local loopback to connect to source int"
-A OUTPUT -o lo -p tcp --sport 80 -m owner --uid-owner www-data -m state --state ESTABLISHED,RELATED -j ACCEPT -m comment --comment "Restrict the apache user outbound connections"
-A INPUT -i lo -p tcp --dport 8080 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT -m comment --comment "Allow tor connection from local loopback to connect to journalist int"
-A OUTPUT -o lo -p tcp --sport 8080 -m owner --uid-owner www-data -m state --state ESTABLISHED,RELATED -j ACCEPT -m comment --comment "Restrict the apache user outbound connections"

# For the redis worker allow the application user allow access for locahost to
# localhost traffic. The redis worker user is the application user.
-A OUTPUT -o lo -s 127.0.0.1 -d 127.0.0.1  -p tcp -m owner --uid-owner www-data -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT -m comment --comment "for redis worker all application user local loopback user"
-A INPUT -i lo -s 127.0.0.1 -d 127.0.0.1  -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT -m comment --comment "for redis worker all application user local loopback user"

# Block all other traffic by application users
# Load before generic loopback rules
-A OUTPUT -m owner --uid-owner www-data -j LOGNDROP -m comment --comment "Drop all other traffic by the securedrop user"

{% endif %}

# Block all other outbound access for users in the sdssh group
# Load before generic loopback rules
-A OUTPUT -m owner --gid-owner sdssh -j LOGNDROP -m comment --comment "Drop all other outbound traffic for ssh user"

# DNS rules
{% for address in dns_server -%}
-A OUTPUT -d {{ address }} -p tcp --dport 53 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT -m comment --comment "tcp/udp dns"
-A INPUT -s {{ address }} -p tcp --sport 53 -m state --state ESTABLISHED,RELATED -j ACCEPT -m comment --comment "tcp/udp dns"
-A OUTPUT -d {{ address }} -p udp --dport 53 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT -m comment --comment "tcp/udp dns"
-A INPUT -s {{ address }} -p udp --sport 53 -m state --state ESTABLISHED,RELATED -j ACCEPT -m comment --comment "tcp/udp dns"
{% endfor -%}

# NTP rules
-A OUTPUT -p udp --dport 123 -m owner --uid-owner {{ time_service_user }} -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT -m comment --comment "ntp"
-A INPUT -p udp --sport 123 -m state --state ESTABLISHED,RELATED -j ACCEPT -m comment --comment "ntp"

# apt rules can't be restricted by destination address because iptables will only resolve FQDNs once at startup
-A OUTPUT -p tcp --match multiport --dports 80,8080,443 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT -m comment --comment "apt updates"
-A INPUT -p tcp --match multiport --sports 80,8080,443 -m state --state ESTABLISHED,RELATED -j ACCEPT -m comment --comment "apt updates"

{% if 'securedrop_application_server' in group_names %}
# OSSEC server-agent rules
-A OUTPUT -d {{ monitor_hostname }} -p udp --dport 1514 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT -m comment --comment "OSSEC server agent"
-A INPUT -s {{ monitor_hostname }} -p udp --sport 1514 -m state --state ESTABLISHED,RELATED -j ACCEPT -m comment --comment "OSSEC server agent"

{% elif 'securedrop_monitor_server' in group_names %}
# OSSEC server-agent rules
-A INPUT -s {{ app_hostname }} -p udp --dport 1514 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT -m comment --comment "Allow OSSEC agent to monitor"
-A OUTPUT -d {{ app_hostname }} -p udp --sport 1514 -m state --state ESTABLISHED,RELATED -j ACCEPT -m comment --comment "Allow OSSEC agent to monitor"

# OSSEC smtp out rules
# dns rule for postfix to lookup smtp relay
{% for address in dns_server -%}
-A OUTPUT -d {{ address }} -p tcp --dport 53 -m owner --uid-owner postfix -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT -m comment --comment "postfix dns rule"
-A INPUT -s {{ address }} -p tcp --sport 53 -m state --state ESTABLISHED,RELATED -j ACCEPT -m comment --comment "tcp/udp dns"
-A OUTPUT -d {{ address }} -p udp --dport 53 -m owner --uid-owner postfix -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT -m comment --comment "postfix dns rule"
-A INPUT -s {{ address }} -p udp --sport 53 -m state --state ESTABLISHED,RELATED -j ACCEPT -m comment --comment "tcp/udp dns"
{% endfor -%}

# postfix rule for outbound smtp
-A OUTPUT -p tcp --dport {{ smtp_relay_port }} -m owner --uid-owner postfix -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT -m comment --comment "Allow ossec email alerts out"
-A INPUT -p tcp --sport {{ smtp_relay_port }}  -m state --state ESTABLISHED,RELATED -j ACCEPT -m comment --comment "Allow ossec email alerts out"
{% endif %}


# Permit direct SSH access.
# Allowed for staging and optionally for production (disables ssh over tor)
{% if not enable_ssh_over_tor %}
  {%- for interface in ansible_interfaces -%}
    {%- if 'ipv4' in hostvars[inventory_hostname]['ansible_'+interface] -%}
        {%- set int_details = hostvars[inventory_hostname]['ansible_'+interface].ipv4 -%}
        {%- set net_string = '/'.join([int_details.network,int_details.netmask]) -%}
        {%- if ssh_ip|ipaddr(net_string) -%}
          {%- set ssh_int = interface -%}
-A INPUT -s {{ adjacent_sd_ip }} -p tcp --dport 22 -j DROP -m comment --comment "Block explicitly SSH from the adjacent SD component"
-A INPUT -i {{ ssh_int }} -s {{ ssh_net_in_override|default(admin_net_cidr) }} -p tcp --dport 22 -m state --state NEW -m limit --limit 3/min --limit-burst 3 -j ACCEPT -m comment --comment "Rate limit incoming ssh traffic"
-A INPUT -i {{ ssh_int }} -s {{ ssh_net_in_override|default(admin_net_cidr) }} -p tcp --dport 22 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
-A OUTPUT -o {{ ssh_int }} -p tcp -m owner --uid-owner root --sport 22 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
       {%- endif %}
    {%- endif %}
  {%- endfor %}
{% endif %}

# Allow generic loopback connections
-A INPUT -i lo -p all -j ACCEPT -m comment --comment "Allow lo to lo traffic all protocols"
-A OUTPUT -o lo -p all -j ACCEPT -m comment --comment "Allow lo to lo traffic all protocols"

# Don't log inbound invalid state packets related to issue #845
-A INPUT -p tcp -m state --state INVALID -j DROP -m comment --comment "drop but do not log inbound invalid state packets"

# Catch all drop rule
-A INPUT -j LOGNDROP -m comment --comment "Drop and log all other incoming traffic"
-A OUTPUT -j DROP -m comment --comment "Drop all other outgoing traffic"

# LOGNDROP everything else
-A LOGNDROP -p tcp -m limit --limit 5/min -j LOG --log-ip-options --log-tcp-options --log-uid --log-level 4
-A LOGNDROP -p udp -m limit --limit 5/min -j LOG --log-ip-options --log-uid --log-level 4
-A LOGNDROP -p icmp -m limit --limit 5/min -j LOG --log-ip-options --log-uid --log-level 4
-A LOGNDROP -j DROP
COMMIT
