From 630141436eae20baddf196321ec6708cd2ba103b Mon Sep 17 00:00:00 2001 From: jgrusewski Date: Sun, 1 Mar 2026 23:27:39 +0100 Subject: [PATCH] infra: add per-service NetworkPolicy rules Least-privilege ingress/egress for all 8 services + IB gateway + infrastructure pods (postgres, redis, minio, questdb). Each policy restricts which pods can communicate on which ports, limiting lateral movement in the cluster. Co-Authored-By: Claude Opus 4.6 --- infra/k8s/network-policies/api-gateway.yaml | 83 +++++++++++++++++ .../network-policies/backtesting-service.yaml | 42 +++++++++ .../k8s/network-policies/broker-gateway.yaml | 52 +++++++++++ .../data-acquisition-service.yaml | 53 +++++++++++ infra/k8s/network-policies/ib-gateway.yaml | 41 +++++++++ .../k8s/network-policies/infrastructure.yaml | 89 +++++++++++++++++++ .../network-policies/ml-training-service.yaml | 49 ++++++++++ .../trading-agent-service.yaml | 49 ++++++++++ .../k8s/network-policies/trading-service.yaml | 59 ++++++++++++ infra/k8s/network-policies/web-gateway.yaml | 69 ++++++++++++++ 10 files changed, 586 insertions(+) create mode 100644 infra/k8s/network-policies/api-gateway.yaml create mode 100644 infra/k8s/network-policies/backtesting-service.yaml create mode 100644 infra/k8s/network-policies/broker-gateway.yaml create mode 100644 infra/k8s/network-policies/data-acquisition-service.yaml create mode 100644 infra/k8s/network-policies/ib-gateway.yaml create mode 100644 infra/k8s/network-policies/infrastructure.yaml create mode 100644 infra/k8s/network-policies/ml-training-service.yaml create mode 100644 infra/k8s/network-policies/trading-agent-service.yaml create mode 100644 infra/k8s/network-policies/trading-service.yaml create mode 100644 infra/k8s/network-policies/web-gateway.yaml diff --git a/infra/k8s/network-policies/api-gateway.yaml b/infra/k8s/network-policies/api-gateway.yaml new file mode 100644 index 000000000..0ace8e477 --- /dev/null +++ b/infra/k8s/network-policies/api-gateway.yaml @@ -0,0 +1,83 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: api-gateway + namespace: foxhunt +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: api-gateway + policyTypes: + - Ingress + - Egress + ingress: + # Tailscale ingress proxy + - from: + - podSelector: + matchLabels: + app: tailscale + ports: + - protocol: TCP + port: 50051 + egress: + # Postgres + - to: + - podSelector: + matchLabels: + app: postgres + ports: + - protocol: TCP + port: 5432 + # Redis + - to: + - podSelector: + matchLabels: + app: redis + ports: + - protocol: TCP + port: 6379 + # Web gateway + - to: + - podSelector: + matchLabels: + app.kubernetes.io/name: web-gateway + ports: + - protocol: TCP + port: 3000 + # Downstream gRPC services + - to: + - podSelector: + matchLabels: + app.kubernetes.io/name: trading-service + ports: + - protocol: TCP + port: 50051 + - to: + - podSelector: + matchLabels: + app.kubernetes.io/name: backtesting-service + ports: + - protocol: TCP + port: 50053 + - to: + - podSelector: + matchLabels: + app.kubernetes.io/name: ml-training-service + ports: + - protocol: TCP + port: 50053 + - to: + - podSelector: + matchLabels: + app.kubernetes.io/name: trading-agent-service + ports: + - protocol: TCP + port: 50055 + # Minio (initContainer binary fetch) + - to: + - podSelector: + matchLabels: + app: minio + ports: + - protocol: TCP + port: 9000 diff --git a/infra/k8s/network-policies/backtesting-service.yaml b/infra/k8s/network-policies/backtesting-service.yaml new file mode 100644 index 000000000..2dce0ae0e --- /dev/null +++ b/infra/k8s/network-policies/backtesting-service.yaml @@ -0,0 +1,42 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: backtesting-service + namespace: foxhunt +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: backtesting-service + policyTypes: + - Ingress + - Egress + ingress: + - from: + - podSelector: + matchLabels: + app.kubernetes.io/name: api-gateway + ports: + - protocol: TCP + port: 50053 + egress: + - to: + - podSelector: + matchLabels: + app: postgres + ports: + - protocol: TCP + port: 5432 + - to: + - podSelector: + matchLabels: + app: redis + ports: + - protocol: TCP + port: 6379 + - to: + - podSelector: + matchLabels: + app: minio + ports: + - protocol: TCP + port: 9000 diff --git a/infra/k8s/network-policies/broker-gateway.yaml b/infra/k8s/network-policies/broker-gateway.yaml new file mode 100644 index 000000000..c3ebda7fb --- /dev/null +++ b/infra/k8s/network-policies/broker-gateway.yaml @@ -0,0 +1,52 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: broker-gateway + namespace: foxhunt +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: broker-gateway + policyTypes: + - Ingress + - Egress + ingress: + - from: + - podSelector: + matchLabels: + app.kubernetes.io/name: trading-service + - podSelector: + matchLabels: + app.kubernetes.io/name: web-gateway + ports: + - protocol: TCP + port: 50056 + egress: + - to: + - podSelector: + matchLabels: + app: ib-gateway + ports: + - protocol: TCP + port: 4002 + - to: + - podSelector: + matchLabels: + app: postgres + ports: + - protocol: TCP + port: 5432 + - to: + - podSelector: + matchLabels: + app: redis + ports: + - protocol: TCP + port: 6379 + - to: + - podSelector: + matchLabels: + app: minio + ports: + - protocol: TCP + port: 9000 diff --git a/infra/k8s/network-policies/data-acquisition-service.yaml b/infra/k8s/network-policies/data-acquisition-service.yaml new file mode 100644 index 000000000..baa7c42bd --- /dev/null +++ b/infra/k8s/network-policies/data-acquisition-service.yaml @@ -0,0 +1,53 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: data-acquisition-service + namespace: foxhunt +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: data-acquisition-service + policyTypes: + - Ingress + - Egress + ingress: + - from: + - podSelector: + matchLabels: + app.kubernetes.io/name: api-gateway + ports: + - protocol: TCP + port: 50057 + egress: + - to: + - podSelector: + matchLabels: + app: postgres + ports: + - protocol: TCP + port: 5432 + - to: + - podSelector: + matchLabels: + app: redis + ports: + - protocol: TCP + port: 6379 + # External HTTPS (Databento, Benzinga APIs) + - to: + - ipBlock: + cidr: 0.0.0.0/0 + except: + - 10.0.0.0/8 + - 172.16.0.0/12 + - 192.168.0.0/16 + ports: + - protocol: TCP + port: 443 + - to: + - podSelector: + matchLabels: + app: minio + ports: + - protocol: TCP + port: 9000 diff --git a/infra/k8s/network-policies/ib-gateway.yaml b/infra/k8s/network-policies/ib-gateway.yaml new file mode 100644 index 000000000..57632a518 --- /dev/null +++ b/infra/k8s/network-policies/ib-gateway.yaml @@ -0,0 +1,41 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: ib-gateway + namespace: foxhunt +spec: + podSelector: + matchLabels: + app: ib-gateway + policyTypes: + - Ingress + - Egress + ingress: + - from: + - podSelector: + matchLabels: + app.kubernetes.io/name: trading-service + - podSelector: + matchLabels: + app.kubernetes.io/name: broker-gateway + ports: + - protocol: TCP + port: 4002 + - protocol: TCP + port: 4004 + egress: + # IBKR external servers + - to: + - ipBlock: + cidr: 0.0.0.0/0 + except: + - 10.0.0.0/8 + - 172.16.0.0/12 + - 192.168.0.0/16 + ports: + - protocol: TCP + port: 443 + - protocol: TCP + port: 4000 + - protocol: TCP + port: 4001 diff --git a/infra/k8s/network-policies/infrastructure.yaml b/infra/k8s/network-policies/infrastructure.yaml new file mode 100644 index 000000000..0d828e3a5 --- /dev/null +++ b/infra/k8s/network-policies/infrastructure.yaml @@ -0,0 +1,89 @@ +# Postgres: accepts connections from all foxhunt app pods +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: postgres + namespace: foxhunt +spec: + podSelector: + matchLabels: + app: postgres + policyTypes: + - Ingress + ingress: + - from: + - podSelector: + matchExpressions: + - key: app.kubernetes.io/part-of + operator: In + values: ["foxhunt"] + ports: + - protocol: TCP + port: 5432 +--- +# Redis: accepts connections from foxhunt app pods +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: redis + namespace: foxhunt +spec: + podSelector: + matchLabels: + app: redis + policyTypes: + - Ingress + ingress: + - from: + - podSelector: + matchExpressions: + - key: app.kubernetes.io/part-of + operator: In + values: ["foxhunt"] + ports: + - protocol: TCP + port: 6379 +--- +# Minio: accepts connections from foxhunt app pods (S3 API) +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: minio + namespace: foxhunt +spec: + podSelector: + matchLabels: + app: minio + policyTypes: + - Ingress + ingress: + - from: + - podSelector: + matchExpressions: + - key: app.kubernetes.io/part-of + operator: In + values: ["foxhunt"] + ports: + - protocol: TCP + port: 9000 +--- +# QuestDB: accepts ILP writes from trading-service +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: questdb + namespace: foxhunt +spec: + podSelector: + matchLabels: + app: questdb + policyTypes: + - Ingress + ingress: + - from: + - podSelector: + matchLabels: + app.kubernetes.io/name: trading-service + ports: + - protocol: TCP + port: 9009 diff --git a/infra/k8s/network-policies/ml-training-service.yaml b/infra/k8s/network-policies/ml-training-service.yaml new file mode 100644 index 000000000..f87a5cf7a --- /dev/null +++ b/infra/k8s/network-policies/ml-training-service.yaml @@ -0,0 +1,49 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: ml-training-service + namespace: foxhunt +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: ml-training-service + policyTypes: + - Ingress + - Egress + ingress: + - from: + - podSelector: + matchLabels: + app.kubernetes.io/name: api-gateway + ports: + - protocol: TCP + port: 50053 + egress: + - to: + - podSelector: + matchLabels: + app: postgres + ports: + - protocol: TCP + port: 5432 + - to: + - podSelector: + matchLabels: + app: redis + ports: + - protocol: TCP + port: 6379 + - to: + - podSelector: + matchLabels: + app: minio + ports: + - protocol: TCP + port: 9000 + # Kubernetes API (for job creation — ml-training-service has RBAC for batch/jobs) + - to: + - ipBlock: + cidr: 0.0.0.0/0 + ports: + - protocol: TCP + port: 443 diff --git a/infra/k8s/network-policies/trading-agent-service.yaml b/infra/k8s/network-policies/trading-agent-service.yaml new file mode 100644 index 000000000..f34a20940 --- /dev/null +++ b/infra/k8s/network-policies/trading-agent-service.yaml @@ -0,0 +1,49 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: trading-agent-service + namespace: foxhunt +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: trading-agent-service + policyTypes: + - Ingress + - Egress + ingress: + - from: + - podSelector: + matchLabels: + app.kubernetes.io/name: api-gateway + ports: + - protocol: TCP + port: 50055 + egress: + - to: + - podSelector: + matchLabels: + app.kubernetes.io/name: trading-service + ports: + - protocol: TCP + port: 50051 + - to: + - podSelector: + matchLabels: + app: postgres + ports: + - protocol: TCP + port: 5432 + - to: + - podSelector: + matchLabels: + app: redis + ports: + - protocol: TCP + port: 6379 + - to: + - podSelector: + matchLabels: + app: minio + ports: + - protocol: TCP + port: 9000 diff --git a/infra/k8s/network-policies/trading-service.yaml b/infra/k8s/network-policies/trading-service.yaml new file mode 100644 index 000000000..e85efb55e --- /dev/null +++ b/infra/k8s/network-policies/trading-service.yaml @@ -0,0 +1,59 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: trading-service + namespace: foxhunt +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: trading-service + policyTypes: + - Ingress + - Egress + ingress: + - from: + - podSelector: + matchLabels: + app.kubernetes.io/name: api-gateway + - podSelector: + matchLabels: + app.kubernetes.io/name: trading-agent-service + ports: + - protocol: TCP + port: 50051 + egress: + - to: + - podSelector: + matchLabels: + app: postgres + ports: + - protocol: TCP + port: 5432 + - to: + - podSelector: + matchLabels: + app: redis + ports: + - protocol: TCP + port: 6379 + - to: + - podSelector: + matchLabels: + app: ib-gateway + ports: + - protocol: TCP + port: 4002 + - to: + - podSelector: + matchLabels: + app: questdb + ports: + - protocol: TCP + port: 9009 + - to: + - podSelector: + matchLabels: + app: minio + ports: + - protocol: TCP + port: 9000 diff --git a/infra/k8s/network-policies/web-gateway.yaml b/infra/k8s/network-policies/web-gateway.yaml new file mode 100644 index 000000000..9ec9efde6 --- /dev/null +++ b/infra/k8s/network-policies/web-gateway.yaml @@ -0,0 +1,69 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: web-gateway + namespace: foxhunt +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: web-gateway + policyTypes: + - Ingress + - Egress + ingress: + - from: + - podSelector: + matchLabels: + app.kubernetes.io/name: api-gateway + - podSelector: + matchLabels: + app: tailscale + ports: + - protocol: TCP + port: 3000 + egress: + # api-gateway gRPC upstream + - to: + - podSelector: + matchLabels: + app.kubernetes.io/name: api-gateway + ports: + - protocol: TCP + port: 50051 + # Direct gRPC to downstream services + - to: + - podSelector: + matchLabels: + app.kubernetes.io/name: backtesting-service + ports: + - protocol: TCP + port: 50053 + - to: + - podSelector: + matchLabels: + app.kubernetes.io/name: ml-training-service + ports: + - protocol: TCP + port: 50053 + - to: + - podSelector: + matchLabels: + app.kubernetes.io/name: trading-agent-service + ports: + - protocol: TCP + port: 50055 + - to: + - podSelector: + matchLabels: + app.kubernetes.io/name: broker-gateway + ports: + - protocol: TCP + port: 50056 + # Minio (initContainer binary fetch) + - to: + - podSelector: + matchLabels: + app: minio + ports: + - protocol: TCP + port: 9000