mirror of
https://github.com/Security-Onion-Solutions/securityonion.git
synced 2026-09-20 14:49:38 +02:00
The Kratos admin API is unauthenticated by design and relies on network isolation, but so-kratos published 0.0.0.0:4434:4434 and daemon.json leaves userland-proxy at its default of true. Docker therefore ran a proxy listener on the host, and any container reached the admin API through the manager IP or the bridge gateway regardless of its docker network. so-kratos now sits alone on a new soauth network and no longer publishes 4434. 4433 is still published, so nginx is unchanged. so-soc is dual homed and reaches the admin API over soauth, with publicHostUrl set explicitly. so-user reaches it through docker exec, and wait_for_kratos polls the container address instead of the host port. firewall/iptables.jinja hardcoded sobridge in every generated DNAT, ACCEPT, masquerade and isolation rule, so it is now driven by a docker:networks map and a per-container networks list. Containers that do not declare one default to sobridge, and .ip still resolves to the primary network's address. soauth is only created on the roles that run so-kratos. Setup already allows a custom docker range, so it now also prompts for the auth network range and writes it to the docker pillar. Grids on the default range need no decision during soup, since they get the same 172.17.2.0/24 a fresh install would. Grids that set a custom range are prompted, defaulting to the adjacent /24, and unattended upgrades take that default with a notice rather than blocking. so-kratos and so-soc are removed in up_to_3.4.0 so the highstate recreates them with the correct network membership.
145 lines
5.7 KiB
Django/Jinja
145 lines
5.7 KiB
Django/Jinja
{%- from 'vars/globals.map.jinja' import GLOBALS %}
|
|
{%- from 'docker/docker.map.jinja' import DOCKERMERGED %}
|
|
{%- from 'firewall/map.jinja' import FIREWALL_MERGED %}
|
|
{%- set role = GLOBALS.role.split('-')[1] %}
|
|
{%- from 'firewall/containers.map.jinja' import NODE_CONTAINERS %}
|
|
|
|
{%- set NODE_NETWORKS = [] %}
|
|
{%- for NETNAME, NETWORK in DOCKERMERGED.networks.items() %}
|
|
{%- if not NETWORK.get('manager_only') or GLOBALS.get('is_manager', False) %}
|
|
{%- do NODE_NETWORKS.append(NETNAME) %}
|
|
{%- endif %}
|
|
{%- endfor %}
|
|
|
|
{%- set PR = [] %}
|
|
{%- set D1 = [] %}
|
|
{%- set D2 = [] %}
|
|
{%- for container in NODE_CONTAINERS %}
|
|
{%- set IP = DOCKERMERGED.containers[container].ip %}
|
|
{%- set BRIDGE = DOCKERMERGED.containers[container].network %}
|
|
{%- if DOCKERMERGED.containers[container].port_bindings is defined %}
|
|
{%- for binding in DOCKERMERGED.containers[container].port_bindings %}
|
|
{#- cant split int so we convert to string #}
|
|
{%- set binding = binding|string %}
|
|
{#- split the port binding by /. if proto not specified, default is tcp #}
|
|
{%- set binding_split = binding.split('/') %}
|
|
{%- if binding_split | length > 1 %}
|
|
{%- set proto = binding_split[1] %}
|
|
{%- else %}
|
|
{%- set proto = 'tcp' %}
|
|
{%- endif %}
|
|
{%- set bsa = binding_split[0].split(':') %}
|
|
{%- set bindip = '' %}
|
|
{%- set hostPort = '' %}
|
|
{%- set containerPort = '' %}
|
|
{%- if bsa | length == 3 %}
|
|
{%- set bindip = bsa[0] %}
|
|
{%- set hostPort = bsa[1] %}
|
|
{%- set containerPort = bsa[2] %}
|
|
{%- endif %}
|
|
{%- if bsa | length == 2 %}
|
|
{%- set hostPort = bsa[0] %}
|
|
{%- set containerPort = bsa[1] %}
|
|
{%- endif %}
|
|
{%- do PR.append("-A POSTROUTING -s " ~ DOCKERMERGED.containers[container].ip ~ "/32 -d " ~ DOCKERMERGED.containers[container].ip ~ "/32 -p " ~ proto ~ " -m " ~ proto ~ " --dport " ~ containerPort ~ " -j MASQUERADE") %}
|
|
{%- if bindip | length and bindip != '0.0.0.0' %}
|
|
{%- do D1.append("-A DOCKER -d " ~ bindip ~ "/32 ! -i " ~ BRIDGE ~ " -p " ~ proto ~ " -m " ~ proto ~ " --dport " ~ hostPort ~ " -j DNAT --to-destination " ~ DOCKERMERGED.containers[container].ip ~ ":" ~ containerPort) %}
|
|
{%- else %}
|
|
{%- do D1.append("-A DOCKER ! -i " ~ BRIDGE ~ " -p " ~ proto ~ " -m " ~ proto ~ " --dport " ~ hostPort ~ " -j DNAT --to-destination " ~ DOCKERMERGED.containers[container].ip ~ ":" ~ containerPort) %}
|
|
{%- endif %}
|
|
{%- do D2.append("-A DOCKER -d " ~ DOCKERMERGED.containers[container].ip ~ "/32 ! -i " ~ BRIDGE ~ " -o " ~ BRIDGE ~ " -p " ~ proto ~ " -m " ~ proto ~ " --dport " ~ containerPort ~ " -j ACCEPT") %}
|
|
{%- endfor %}
|
|
{%- endif %}
|
|
{%- endfor %}
|
|
|
|
*nat
|
|
:PREROUTING ACCEPT [0:0]
|
|
:INPUT ACCEPT [0:0]
|
|
:OUTPUT ACCEPT [0:0]
|
|
:POSTROUTING ACCEPT [0:0]
|
|
:DOCKER - [0:0]
|
|
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
|
|
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
|
|
{%- for NETNAME in NODE_NETWORKS %}
|
|
-A POSTROUTING -s {{ DOCKERMERGED.networks[NETNAME].range }} ! -o {{ NETNAME }} -j MASQUERADE
|
|
{%- endfor %}
|
|
{%- for rule in PR %}
|
|
{{ rule }}
|
|
{%- endfor %}
|
|
{%- for NETNAME in NODE_NETWORKS %}
|
|
-A DOCKER -i {{ NETNAME }} -j RETURN
|
|
{%- endfor %}
|
|
{%- for rule in D1 %}
|
|
{{ rule }}
|
|
{%- endfor %}
|
|
|
|
COMMIT
|
|
*filter
|
|
:INPUT ACCEPT [0:0]
|
|
:FORWARD DROP [0:0]
|
|
:OUTPUT ACCEPT [0:0]
|
|
:DOCKER - [0:0]
|
|
:DOCKER-ISOLATION-STAGE-1 - [0:0]
|
|
:DOCKER-ISOLATION-STAGE-2 - [0:0]
|
|
:DOCKER-USER - [0:0]
|
|
:LOGGING - [0:0]
|
|
|
|
{%- for chn, hostgroups in FIREWALL_MERGED.role[role].chain.items() %}
|
|
{%- for hostgroup, portgroups in hostgroups['hostgroups'].items() %}
|
|
{%- for ip in FIREWALL_MERGED.hostgroups[hostgroup] %}
|
|
{%- for groupname in portgroups['portgroups'] %}
|
|
{%- for proto, ports in FIREWALL_MERGED['portgroups'][groupname].items() %}
|
|
{%- for port in ports %}
|
|
-A {{chn}} -s {{ip}} -p {{proto}} -m {{proto}} --dport {{port}} -j ACCEPT
|
|
{%- endfor %}
|
|
{%- endfor %}
|
|
{%- endfor %}
|
|
{%- endfor %}
|
|
{%- endfor %}
|
|
{%- endfor %}
|
|
|
|
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
|
-A INPUT -i lo -j ACCEPT
|
|
-A INPUT -m conntrack --ctstate INVALID -j DROP
|
|
-A INPUT -p icmp -j ACCEPT
|
|
-A INPUT -j LOGGING
|
|
{% if GLOBALS.role in ['so-hypervisor', 'so-managerhype'] -%}
|
|
-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
|
|
-A FORWARD -i br0 -o br0 -j ACCEPT
|
|
{%- endif %}
|
|
-A FORWARD -j DOCKER-USER
|
|
-A FORWARD -j DOCKER-ISOLATION-STAGE-1
|
|
{%- for NETNAME in NODE_NETWORKS %}
|
|
-A FORWARD -o {{ NETNAME }} -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
|
-A FORWARD -o {{ NETNAME }} -j DOCKER
|
|
-A FORWARD -i {{ NETNAME }} ! -o {{ NETNAME }} -j ACCEPT
|
|
-A FORWARD -i {{ NETNAME }} -o {{ NETNAME }} -j ACCEPT
|
|
{%- endfor %}
|
|
-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
|
-A FORWARD -i lo -j ACCEPT
|
|
-A FORWARD -m conntrack --ctstate INVALID -j DROP
|
|
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
|
|
-A OUTPUT -o lo -j ACCEPT
|
|
# block icmp timestamp reply
|
|
-A OUTPUT -p icmp -m icmp --icmp-type 14 -j DROP
|
|
|
|
{%- for rule in D2 %}
|
|
{{ rule }}
|
|
{%- endfor %}
|
|
{% for NETNAME in NODE_NETWORKS %}
|
|
-A DOCKER-ISOLATION-STAGE-1 -i {{ NETNAME }} ! -o {{ NETNAME }} -j DOCKER-ISOLATION-STAGE-2
|
|
{%- endfor %}
|
|
-A DOCKER-ISOLATION-STAGE-1 -j RETURN
|
|
{%- for NETNAME in NODE_NETWORKS %}
|
|
-A DOCKER-ISOLATION-STAGE-2 -o {{ NETNAME }} -j DROP
|
|
{%- endfor %}
|
|
-A DOCKER-ISOLATION-STAGE-2 -j RETURN
|
|
{%- for NETNAME in NODE_NETWORKS %}
|
|
-A DOCKER-USER ! -i {{ NETNAME }} -o {{ NETNAME }} -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
|
-A DOCKER-USER ! -i {{ NETNAME }} -o {{ NETNAME }} -j LOGGING
|
|
{%- endfor %}
|
|
-A DOCKER-USER -j RETURN
|
|
-A LOGGING -m limit --limit 2/min -j LOG --log-prefix "IPTables-dropped: "
|
|
-A LOGGING -j DROP
|
|
COMMIT
|