Kubernetes Ingress & Gateway API
Synapse can act as a native Kubernetes Ingress controller and
Gateway API implementation. The synapse-operator watches your
Ingress, IngressClass, Gateway, and HTTPRoute resources and
programs the Synapse reverse proxy in real time — so Synapse becomes a
drop-in replacement for Traefik / ingress-nginx while keeping its
eBPF firewall, WAF, and JA4+ fingerprinting on the same data path.
It integrates with cert-manager for automatic TLS, serves many domains from one proxy via SNI, and picks up new or rotated certificates without a restart.
This page covers the controller. To install the Synapse stack itself, see Installation.
How it works
synapse-operator runs in ingress mode alongside the Synapse
proxy. On every change to the resources it owns it re-renders
Synapse's upstream configuration and triggers a hot reload — no proxy
restart, no dropped connections.
- Ingress + Gateway API are reconciled into the same routing table, so you can mix both.
- Backends are addressed by in-cluster DNS
(
svc.namespace.svc.cluster.local:port); named Service ports are resolved automatically and a Service change re-renders. - Routing is deterministic: sources are processed in a stable order (Ingresses before HTTPRoutes, each sorted by namespace/name) with first-writer-wins on a host+path conflict, so the result is reproducible regardless of watch ordering.
Deploy the controller
Run the operator in ingress mode (it co-locates with the proxy and writes the proxy's upstreams + certificates):
--ingress-mode
--gateway-api # also reconcile Gateway API (optional)
--ingress-class=synapse # spec.ingressClassName this controller serves
--certs-out=/certs # project referenced TLS Secrets here (optional)
--status-leader-election # see "Scaling" below (multi-replica)
Create the IngressClass:
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: synapse
# Optional: make Synapse the default for class-less Ingresses
annotations:
ingressclass.kubernetes.io/is-default-class: "true"
spec:
controller: gen0sec.com/synapse
The controller needs RBAC to get/list/watch ingresses,
ingressclasses, services, secrets (and the Gateway API resources when
--gateway-api is set), plus update on their /status,
create/patch on events, and coordination.k8s.io/leases when
leader election is enabled.
Routing with Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app
spec:
ingressClassName: synapse
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app
port:
number: 80
Class selection follows Kubernetes precedence: an explicit
spec.ingressClassName wins; otherwise the legacy
kubernetes.io/ingress.class annotation; otherwise the default
IngressClass (when annotated is-default-class: "true").
Exact path types and HTTPRoute header/method/query matches are
approximated or ignored (Synapse routes on host + longest-prefix
path); the controller logs a warning and emits a Kubernetes event so
the behaviour is never silent.
Upstream settings via annotations
Annotations on the Ingress (or HTTPRoute) tune the upstream. The
synapse.gen0sec.com/ prefix is canonical; a small
nginx.ingress.kubernetes.io/ compatibility subset is also accepted.
| Annotation | Effect |
|---|---|
backend-protocol: HTTP|HTTPS | TLS to the upstream |
http2: "true" | HTTP/2 to the upstream |
force-https / ssl-redirect: "true" | redirect HTTP→HTTPS |
connect-timeout / read-timeout / write-timeout / idle-timeout | seconds |
healthcheck: "true" | upstream health checking |
disable-access-log: "true" | drop access logs for this route |
request-headers / response-headers | comma-separated Name: value injection |
sticky-sessions: "true" | sticky upstream selection |
Routing with Gateway API
Create a GatewayClass whose controllerName is gen0sec.com/synapse,
a Gateway, and HTTPRoutes bound to it:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: app
spec:
parentRefs:
- name: synapse-gw
hostnames: ["app.example.com"]
rules:
- matches:
- path: { type: PathPrefix, value: / }
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
set: [{ name: X-From, value: gateway }]
backendRefs:
- { name: app-v1, port: 80, weight: 90 }
- { name: app-v2, port: 80, weight: 10 }
- Weighted
backendRefsare honored, including Gateway API semantics whereweight: 0means receive no traffic (the backend is excluded). RequestHeaderModifier/ResponseHeaderModifierfilters are translated to header injection.- The controller maintains
GatewayClass,Gateway, andHTTPRoutestatus conditions (Accepted,Programmed,ResolvedRefs).
Smart firewall, WAF & IDS on ingress traffic
Because Synapse is the proxy, its eBPF smart firewall, WAF, and signature IDS/IPS run on the very same data path as the Ingress/Gateway traffic — no sidecar, no second hop. These are configured on the Synapse side (config file + rules), not via Ingress annotations (the controller annotations above only tune the upstream); they then apply to every route the controller programs.
Smart firewall (eBPF)
Set in the Synapse config:
firewall:
mode: "auto" # auto | xdp | nftables | iptables | none
enabled: true # false → pass all traffic, rules not evaluated
default_action: "allow" # action when no rule matches: allow | drop
Kernel firewall rules are evaluated in ascending order, first match
wins (action: allow/drop), matching on src_ip/dst_ip
(+src_ip_prefix/dst_ip_prefix), src_*_port/dst_*_port,
ip_version, ip_protocol. The JA4/JA4T/JA4H smart-firewall plus
threat- and anomaly-detection scoring also evaluate ingress clients on
this path. See
Firewall Rules,
Threat Detection, and
Anomaly Detection.
WAF
The WAF inspects ingress HTTP requests using Wirefilter-compatible
expression rules (Cloudflare Ruleset-Engine style) with OWASP Top 10
coverage — e.g. matching on http.request.method, http.request.host,
http.request.path, http.request.uri, http.request.user_agent,
with and/or/not, contains, matches, in, etc., and an
action on match. Rules are managed centrally (per organization), not
per-Ingress. See WAF and
Access Rules.
Intrusion detection (IDS / IPS)
Synapse runs a signature IDS/IPS engine (thalamus) that inspects
decrypted, post-TLS HTTP on the same path as ingress traffic — so
it sees real requests even for HTTPS that Synapse terminates.
Configured under ids: in the Synapse config:
ids:
enabled: true
rule_paths: # signature rule files (Suricata / Emerging Threats compatible)
- /etc/synapse/rules/emerging-all.rules
address_vars: { HOME_NET: "10.0.0.0/8" } # rule $VARS
port_vars: { HTTP_PORTS: "80,8080" }
enforce_block: false # false = IDS (detect/alert); true = IPS (drop on match)
post_tls:
mode: inline # inline | offload | off
socket: /run/synapse/ids.sock # offload: per-node consumer UDS
# flow/capture tuning: snaplen, poll_timeout_ms, flow_timeout_secs,
# max_flows, cleanup_interval_secs, stats_log_interval_secs
enabledturns the engine on.rule_pathspoint at signature files;address_vars/port_varspopulate rule variables (e.g.$HOME_NET,$HTTP_PORTS).enforce_block:false= detect & alert (IDS);true= block matched requests (IPS).post_tls.mode:inlineruns the engine in every proxy process (simple, but a horizontally-scaled proxy holds the ruleset in every replica — O(replicas));offloadkeeps the proxy light and taps decrypted HTTP to an out-of-process per-node consumer overpost_tls.socket(ruleset cost O(nodes));offdisables post-TLS inspection. With>1replica, preferoffload.- Advanced:
post_tls.enforce(default off) additionally bans the proxy-observed source IP in the agent firewall on a block detection — guarded against shared/NAT IPs; distinct fromenforce_block.
See Architecture overview and Data flow for where IDS/IPS sits, and Threat Feeds API to feed blocklists.
Rate limiting
The Synapse upstreams routing config (which the controller renders)
supports a global_rate_limit and per-host / per-path rate_limit;
these bound request rates on the programmed ingress routes. See
Configuration.
Firewall mode, firewall/WAF/IDS rules, and rate limits are Synapse configuration — they are not expressed as Ingress annotations. The controller renders routing/upstreams; the firewall, WAF, and IDS apply globally to the proxy and therefore to all ingress traffic.
TLS with cert-manager
Automatic certificates (HTTP-01)
Annotate the Ingress for cert-manager and declare spec.tls. The
HTTP-01 challenge is served straight through Synapse:
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: synapse
tls:
- hosts: [app.example.com]
secretName: app-tls
rules:
- host: app.example.com
http:
paths:
- { path: /, pathType: Prefix, backend: { service: { name: app, port: { number: 80 } } } }
Multi-domain TLS via SNI, no restart
When --certs-out is set, the controller projects every referenced
TLS Secret (Ingress spec.tls, Gateway listener certificateRefs)
into Synapse's certificate directory. Synapse then selects the right
certificate per SNI hostname, so a single proxy serves many
domains. Adding, rotating (cert-manager renewal), or removing a
certificate is picked up live — no pod restart; an unreferenced
certificate is pruned and that hostname falls back to the default
certificate.
This works per-pod and is never gated by leader election, so every replica serves correct certificates immediately.
Scaling (multiple replicas)
Every proxy replica renders its own local config and reloads its
own Synapse — that is never gated. To avoid replicas racing on
shared cluster status, enable --status-leader-election: only the
lease holder writes Gateway/HTTPRoute/Ingress status, and
leadership fails over automatically if the holder dies.
Observability
- Kubernetes events on the Ingress/HTTPRoute:
Programmed,RouteConflict,BackendUnresolved,UnsupportedMatch. - Prometheus metrics on the metrics endpoint: renders, changes, reload signals, route conflicts, unresolved backends, projected certs, hosts/routes gauges, and a readiness gauge.
- Readiness is gated on the first successful render, so the proxy is not advertised ready before it has correct upstreams.
Migrating from Traefik
- Deploy
synapse-operatorin ingress mode and create thesynapseIngressClass. - Repoint Ingresses by setting
spec.ingressClassName: synapse(or make Synapse the default class). - Move Traefik-specific annotations to the
synapse.gen0sec.com/equivalents above. - cert-manager
Certificate/Issuerresources are unchanged — HTTP-01 via the ingress solver works as-is. - Remove Traefik once traffic is verified on Synapse.