# 01 - Private Network Port Matrix This file defines the ports that must be opened inside the Hetzner private network for test and prod environments. Public ingress is limited to `22/tcp`, `80/tcp`, and `443/tcp`, with one current test-only exception: `51820/udp` is public on the test DB node for WireGuard. Vault `8200/tcp` will not be opened publicly. This matrix must be treated as the source for Terraform Hetzner firewall and Ansible `firewalld` rules. ## Network Plan ### Test | Subnet | CIDR | Purpose | | --- | --- | --- | | App/Swarm | `10.10.10.0/24` | `iklim-app-01` | | DB | `10.10.20.0/24` | `iklim-db-01` | ### Prod | Subnet | CIDR | Purpose | | --- | --- | --- | | App/Swarm | `10.20.10.0/24` | `iklim-app-01/02/03` | | DB | `10.20.20.0/24` | `iklim-db-01/02/03` | ## Public Ingress Standard Public ingress: | Port | Protocol | Source | Target | Requirement | | --- | --- | --- | --- | --- | | `22` | TCP | Admin IP/CIDR | All nodes | SSH management | | `80` | TCP | Internet | `iklim-app-01` (gateway) | HTTP / ACME redirect | | `443` | TCP | Internet | `iklim-app-01` (gateway) | HTTPS | | `51820` | UDP | `0.0.0.0/0`, `::/0` | `iklim-db-01` in test only | WireGuard VPN — authentication with cryptographic key | Critical ports that will not be opened publicly: | Port | Service | | --- | --- | | `8200/tcp` | Vault | | `5432/tcp` | PostgreSQL | | `27017/tcp` | MongoDB | | `6379/tcp` | Redis | | `5672/tcp`, `15672/tcp`, `61613/tcp`, `15674/tcp` | RabbitMQ | | `2377/tcp`, `7946/tcp`, `7946/udp`, `4789/udp` | Docker Swarm | | `9180/tcp` | APISIX Admin API | | `9090/tcp` | Prometheus | | `3000/tcp` | Grafana | ## Docker Swarm Private Ports Required ports between Docker Swarm nodes: | Port | Protocol | Source | Target | Description | | --- | --- | --- | --- | --- | | `2377` | TCP | Swarm nodes | Swarm manager nodes | Swarm control plane / join | | `7946` | TCP | All Swarm nodes | All Swarm nodes | Node discovery / gossip | | `7946` | UDP | All Swarm nodes | All Swarm nodes | Node discovery / gossip | | `4789` | UDP | All Swarm nodes | All Swarm nodes | Overlay VXLAN data path | In test, these ports are effectively required for a single Swarm node, but they can be defined inside the app subnet to make adding workers easier later. In prod, these ports must be open between all `iklim-app-*` nodes inside the `10.20.10.0/24` app/swarm subnet. Source: Docker overlay network documentation, https://docs.docker.com/engine/network/drivers/overlay/ ## Application and Infra Service Private Ports These ports will not be opened publicly. Access will be allowed only from required sources inside the private network or Docker overlay. | Port | Protocol | Service | Source | Target | Note | | --- | --- | --- | --- | --- | --- | | `8200` | TCP | Vault API/UI | Swarm app nodes / runner | Vault service/node | Public closed. Runtime services must reach Vault through private/overlay | | `6379` | TCP | Redis | Swarm app nodes | Redis service/node | Public closed | | `5672` | TCP | RabbitMQ AMQP | Swarm app nodes | RabbitMQ service/node | Public closed | | `15672` | TCP | RabbitMQ Management | Admin CIDR or private ops | RabbitMQ service/node | Public closed; preferably VPN/bastion | | `61613` | TCP | RabbitMQ STOMP | Required app nodes | RabbitMQ service/node | Public closed | | `15674` | TCP | RabbitMQ Web STOMP | Required app/gateway nodes | RabbitMQ service/node | Public closed | | `2379` | TCP | etcd client | APISIX service/node | etcd service/node | Public closed | | `2380` | TCP | etcd peer | etcd cluster nodes | etcd cluster nodes | May not be needed for a single replica; required if clustered | | `9180` | TCP | APISIX Admin API | Admin CIDR or private ops | APISIX service/node | Public closed | | `9090` | TCP | Prometheus UI/API | Admin CIDR or private ops | Prometheus service/node | Public closed | | `3000` | TCP | Grafana UI | Admin CIDR or private ops | Grafana service/node | Public closed | The current prod root stack is `docker-stack-infra_db-prod.yml`; Vault is deployed separately with `docker-stack-vault.yml` through `vault-bootstrap.sh`. Public traffic is expected to enter through SWAG on 80/443. Private service reachability is provided by the `iklimco-net` overlay and by the explicit host-mode DB/cluster ports listed below. ## DB Node Ports DB runtime services are deployed as Docker Swarm services. Prod currently uses Patroni/PostgreSQL, etcd, and a MongoDB replica set in `docker-stack-infra_db-prod.yml`; the required firewall ports are below. ### PostgreSQL / PostGIS (Patroni + etcd) The prod environment uses PostgreSQL managed with Patroni + etcd. In the test environment, replication and HA ports are not required because there is a single node. | Port | Protocol | Source | Target | Note | | --- | --- | --- | --- | --- | | `5432` | TCP | App/Swarm subnet | PostgreSQL nodes (Patroni-managed) | Application JDBC — connects to all nodes, driver finds the primary | | `5432` | TCP | DB subnet | PostgreSQL nodes | Patroni replication (pg_basebackup and WAL streaming) | | `8008` | TCP | DB subnet | PostgreSQL nodes | Patroni REST API — leader election, health check | | `2379` | TCP | DB subnet | etcd nodes | etcd client — Patroni -> etcd access | | `2380` | TCP | DB subnet | etcd nodes | etcd peer — raft protocol inside the etcd cluster | ### MongoDB | Port | Protocol | Source | Target | Note | | --- | --- | --- | --- | --- | | `27017` | TCP | App/Swarm subnet | MongoDB node/replica set endpoint | Application DB connection | | `27017` | TCP | DB subnet | MongoDB replica set nodes | Replica set internal traffic | If sharding is added later, additional MongoDB roles such as `27018/27019` may come up; they will not be opened at this stage. ## Test Private Rules Minimum for the test environment: | Source | Target | Ports | | --- | --- | --- | | `10.10.10.0/24` | `10.10.10.0/24` | `2377/tcp`, `7946/tcp`, `7946/udp`, `4789/udp` | | `10.10.10.0/24` | `10.10.20.0/24` | `5432/tcp`, `27017/tcp` | | `10.10.10.0/24` | `10.10.10.0/24` | `8200/tcp`, `6379/tcp`, `5672/tcp`, `61613/tcp`, `15674/tcp` | | Admin CIDR or VPN | `10.10.10.0/24` | `9000/tcp`, `15672/tcp`, `9180/tcp`, `9090/tcp`, `3000/tcp` | Because the DB node is single-node in test, PostgreSQL/MongoDB replication ports inside the DB subnet may not be actively used. ## Prod Private Rules Minimum for the prod environment, including Patroni + etcd: App subnet (swarm firewall) — traffic inside itself: | Source | Target | Ports | | --- | --- | --- | | `10.20.10.0/24` | `10.20.10.0/24` | `2377/tcp`, `7946/tcp`, `7946/udp`, `4789/udp` (Swarm) | | `10.20.10.0/24` | `10.20.10.0/24` | `8200/tcp`, `5672/tcp`, `61613/tcp`, `15674/tcp` (application services) | | Admin CIDR or VPN | `10.20.10.0/24` | `15672/tcp`, `9180/tcp`, `9090/tcp`, `3000/tcp` | App -> DB traffic (there is no related rule in the swarm firewall; it is allowed in the db firewall): | Source | Target | Ports | | --- | --- | --- | | `10.20.10.0/24` | `10.20.20.0/24` | `5432/tcp`, `27017/tcp` (DB access) | | `10.20.10.0/24` | `10.20.20.0/24` | `2377/tcp`, `7946/tcp`, `7946/udp`, `4789/udp` (Swarm — DB worker join) | DB subnet (db firewall) — traffic between DB nodes: | Source | Target | Ports | | --- | --- | --- | | `10.20.20.0/24` | `10.20.20.0/24` | `5432/tcp`, `27017/tcp` (DB replication) | | `10.20.20.0/24` | `10.20.20.0/24` | `2379/tcp`, `2380/tcp` (etcd client/peer) | | `10.20.20.0/24` | `10.20.20.0/24` | `8008/tcp` (Patroni REST API) | DB -> App traffic (allowed in the swarm firewall): | Source | Target | Ports | | --- | --- | --- | | `10.20.20.0/24` | `10.20.10.0/24` | `2377/tcp`, `7946/tcp`, `7946/udp`, `4789/udp` (Swarm — manager ports) | ## Acceptance Criteria - The public firewall does not open `8200/tcp`. - DB ports are not open publicly. - Swarm ports are open only between Swarm app and DB subnets. - The App/Swarm subnet reaches the DB subnet only through required DB ports. - The DB subnet is not opened to the app subnet with broad permissions. - Admin UI ports are restricted through admin CIDR/VPN/private ops instead of public access.