Skip to main content

Internet-Facing Hardening & Fronting Architecture

March 2026

dfe-receiver is the internet-facing ingest component in the DFE stack. dfe-ui, dfe-hyperdx and, where it is deployed, culvert also take untrusted input (dfe-infra docs/threat-model.md).

This document covers application-level hardening (80/20 effort) and cost-effective infrastructure fronting for K8s and AWS deployments. It answers the questions cloud architects and security reviews ask most often.


Current State (What We Already Have)​

ProtectionStatusConfig
Request body size limit (413)10 MiB (HTTP, OTLP HTTP, HEC, RW), 1 MiB (webhook); the body extractors read to the same limitserver.max_body_size (HTTP, OTLP HTTP), splunk_hec.max_body_size, prometheus_rw.max_body_size, webhook.max_body_size
Request timeout (408)30s, every HTTP listenerserver.request_timeout_ms (HTTP, OTLP HTTP), splunk_hec.request_timeout_ms, prometheus_rw.request_timeout_ms, webhook.request_timeout_ms
Slowloris protection5s header_read_timeout, every HTTP listener (hyper)HEADER_READ_TIMEOUT
Connections closed for a limitCounted by transport and reason (over_limit, no_first_byte, frame_timeout, idle)receiver_connections_closed_total
First byte timeout30s, every TCP listener the receiver accepts on: a connection that sends nothing by then is closedserver.connections.first_byte_timeout_ms
Frame timeout30s, every raw TCP listener (syslog TCP and TLS, Lumberjack, Fluent Forward, GELF): once a frame's first byte arrives, a frame not whole by then closes its connection and frees its place under the cap. An oversize syslog or GELF frame being skipped is still a frame in progress. Time between whole frames and time a frame waits on the pipeline are not counted. A 32 MiB Lumberjack or Fluent frame needs about 1 MiB/s to arrive in timeserver.connections.frame_timeout_ms
Connection idle timeout300s with no request in flight, every HTTP listener, HTTP/1 keep-alive and HTTP/2 alike (an idle HTTP/1 connection can close sooner, on the header read timeout). A peer that does not finish the graceful close is dropped. Lumberjack, Fluent Forward and GELF keep an idle connection, under the cap, since closing one under a sender loses its next lineserver.connections.idle_timeout_ms
Syslog TCP idle timeout and keepaliveSyslog TCP and TLS close a connection with no frame for 600s, a frame part way in being the frame timeout's. Keepalive probes start after 60s quiet and repeat every 60s, so a peer that has gone frees its placesyslog.idle_timeout_ms (0 = keep), syslog.tcp_keepalive_secs (0 = off)
HTTP/2 keep-alivePing every 60s, close after 20s unanswered, every HTTP listener and both gRPC listenersserver.connections.http2_keep_alive_interval_ms
Connection cap10,000 open connections per listener, every TCP listener and both gRPC listeners; one past it is closed as it is acceptedserver.connections.max_per_listener (0 = no cap)
Concurrency limit10,000 in-flight requests default, per HTTP listenerserver.max_concurrent_requests
Per-IP rate limitingGCRA via tower-governor, opt-in, per HTTP listener, keyed on the TCP peer (forwarding headers only from server.trusted_proxies); clients whose budget has refilled are dropped from its key map every 5sserver.rate_limit.*, server.trusted_proxies
Flow per-source rate limitingToken bucket per UDP source, opt-in. The bucket map never holds more than cache_size (default 4096) sources: a new source past it evicts an idle bucket where one is among the first 32 looked at, else the first, counted on flow_rate_limit_evicted_total, so spoofed sources cannot grow itflow.rate_limit.*
IP filter (allowlist/denylist)CIDR trie, connection-level reject, every accept loop; an unknown mode, a bad CIDR or an empty allowlist refuses to startserver.ip_filter.*
503 backpressureHTTP + gRPC ingest shed load when pipeline not readyRetry-After: 5
TLS terminationPer-protocol, hot-reloadable*.tls.enabled
TLS handshake timeout10s, every TLS listener the receiver accepts onserver.connections.tls_handshake_timeout_ms
mTLS client authPer-protocol*.tls.client_auth: required
Bearer token authPer-protocol, hot-reloadable*.auth.mode: bearer
Header authHTTP, against accepted_headers only; an unknown *.auth.mode refuses to startserver.auth.mode: header
Credential-less listenersRefuse to start without client certificates required or the opt-out*.accept_unauthenticated
JSON validationGlobal, always on: a body that is not JSON is refused with a 400Not configurable
Required field checkGlobalvalidation.required_fields
Dead-letter queueGlobalrouting.dlq
Memory pressure backpressure503 / UNAVAILABLE on HTTP and gRPC ingestDFE_RECEIVER_MEMORY_PRESSURE_THRESHOLD, self_regulation.* (buffer.* bounds only the destination queues)
Middleware orderingConcurrency -> Timeout -> BodyLimit -> Auth -> HandlerCorrect for DoS
Frame size validationGELF 1MB, Syslog 64KB, Fluent 32MB. An oversize syslog or GELF message is skipped to its delimiter and counted (receiver_records_dropped_total, reason oversize), and its connection carries on. Fluent Forward has no delimiter to resume at, so an oversize frame closes its connectionPer-protocol limits, syslog.max_message_size, gelf.max_message_size
Decoded-size budgetAn OTLP export, remote-write request or Vector push past 100,000 records, 1,000,000 messages or 64 MiB of resource, scope, metric or series-label bytes copied into its records, or holding a protobuf group, is refused before it decodes: 400 on HTTP, INVALID_ARGUMENT on gRPC. A Fluent Forward message past 1,000,000 values, 100,000 entries or 64 MiB of tag copies closes its connection, found by a scan that reads each byte once. A Splunk HEC request past 100,000 events or raw lines, or 64 MiB of host, source, sourcetype and index copied into its raw lines, is refused with a 400Hard-coded
Zip-bomb rejectionLumberjack nested compression rejected; a compressed frame is decompressed one inner frame at a time and refused past 64 MiBHard-coded
Unsettled bytes per connectionLumberjack settles and ACKs a window in parts past 16 MiB of eventsHard-coded
Health/readiness (K8s)/livez, /readyz: 503 until every enabled listener serves, once one stops (drain included), and under memory pressureMetrics port and the HTTP ingest port
Graceful shutdownCancellationToken + in-flight drainAll handlers
Log spam preventionSampled (1/100) + debounced (5s) logging; a refused credential logs once per 5s per reason, an IP-filter refusal once per 5s per listener, and a counter carries every onePer-protocol
#![forbid(unsafe_code)]Entire crateCargo.toml lints

Part 1: Application-Level Hardening (Complete)​

All planned application-level hardening is implemented. No remaining items.

Which listener gets which control​

server.ip_filter runs in the accept loop, so it reaches anything the receiver accepts itself. server.rate_limit is a tower layer over an HTTP request, so it reaches HTTP only. Each HTTP listener builds its own governor: the configured rate is per source IP PER LISTENER, not a receiver-wide total.

server.rate_limit.requests_per_second is a rate: the limiter replenishes one request of the quota every 1/requests_per_second of a second, with server.rate_limit.burst on top of it.

The limiter keys on the TCP peer; forwarding headers count only from server.trusted_proxies. On Kubernetes, externalTrafficPolicy: Cluster (the default) makes every client behind one node share its budget: set externalTrafficPolicy: Local, or list the fronting proxy as trusted.

Listenerserver.ip_filterserver.rate_limitClient authentication
HTTP /ingestyesyesserver.auth
Webhook (own or shared listener)yesyesper-caller secret
Splunk HEC (TLS and plaintext)yesyessplunk_hec.auth
Prometheus remote writeyesyesprometheus_rw.auth
OTLP HTTP (4318)yesyesotlp.auth
OTLP gRPC (4317)no -- tonic runs the accept loopno -- no HTTP layer thereotlp.auth, bearer or mTLS
gRPC / Vectorno -- tonic runs the accept loopno -- no HTTP layer theregrpc.auth, bearer or mTLS
Syslog UDP / TCP / TLSyes (per datagram on UDP)no -- no HTTP request to countTLS listener only, client_auth: required; starts only with syslog.accept_unauthenticated: true
Lumberjack / Beatsyesno -- no HTTP request to countlumberjack.tls.client_auth: required, or lumberjack.accept_unauthenticated: true
Fluent Forwardyesno -- no HTTP request to countfluent.tls.client_auth: required, or fluent.accept_unauthenticated: true
GELFyesno -- no HTTP request to countgelf.tls.client_auth: required, or gelf.accept_unauthenticated: true
Flow (NetFlow / sFlow)own flow.ip_filterown flow.rate_limitnone -- UDP, restrict by source

An IP allowlist is network admission, not authentication: it says where a client may connect from, not who the client is, which is why it is not in the last column. The opt-out says in the config that anyone who can reach the port is accepted, so pair it with an allowlist.

Known limits​

The decoded-size budget does not count values inside packed scalar repeated fields. Those are the packed arrays in Vector distributions, aggregated histograms and summaries, DDSketch k and n, OTLP histogram buckets, and remote-write native histogram deltas and counts. Each decodes to at most about 8x its wire bytes, and the wire limit (*.max_body_size on HTTP, grpc.max_message_size and otlp.max_message_size on gRPC) already bounds those bytes.

The frame timeout runs above TLS, so a client that finishes the handshake and then sends part of a TLS record is not timed. Requiring client certificates (*.tls.client_auth: required) closes that path.

Upgrade note: one IP filter, every listener​

server.ip_filter used to reach /ingest and the webhook intake and nothing else. It now runs in every accept loop the receiver owns, so a single allowlist governs all of them.

A deployment that set an allowlist for its /ingest senders and receives syslog, Beats, Fluent Forward, GELF, HEC, remote write or OTLP HTTP from a different range starts DROPPING those events in the accept loop. Each drop counts on receiver_ip_filter_rejected_total{transport}, and the filter logs one line naming the listener at most every 5 seconds. Before upgrading, widen server.ip_filter.cidrs to cover every sender on every enabled listener, or set mode: disabled and restrict at the network edge.


Part 2: K8s Fronting Architecture​

When running in Kubernetes, the gateway/ingress layer handles most of what Part 1 describes. This section covers how to configure it properly.

2.1 Ingress Controllers (March 2026)​

The community kubernetes/ingress-nginx is EOL as of March 2026. It was announced at KubeCon NA 2025. No further CVE patches, no K8s compatibility updates. Do not deploy it for new workloads.

The two NGINX ingress controllers are often confused:

ProjectStatus (March 2026)
kubernetes/ingress-nginx (K8s SIG community)EOL. No CVE patches. Chainguard maintains a security-only fork (EmeritOSS) as a stopgap.
nginxinc/kubernetes-ingress (F5)Active. Apache 2.0. NGINX Plus features require JWT license.
Envoy GatewayActive. CNCF project. Gateway API native. Recommended for new deployments.

Prefer Gateway API (Envoy-based) over Ingress for new deployments.

Envoy Gateway is the CNCF reference implementation of the Kubernetes Gateway API, built on Envoy Proxy. Open source, Apache 2.0.

Future path: If service mesh features are ever needed (mTLS between services, traffic shifting, canary deployments), Istio ambient mesh (sidecar-less, GA since Istio 1.22) uses Envoy as its data plane. The Envoy Gateway investment carries over -- same proxy, same config patterns, same operational knowledge.

Security features via CRDs:

ClientTrafficPolicy (downstream -- client-to-Envoy):

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: ClientTrafficPolicy
metadata:
name: dfe-receiver-client-policy
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: dfe-gateway
connection:
# Connection limit -- closes new connections when exceeded
connectionLimit:
value: 10000
# Buffer limit per connection
bufferLimit: 16384
timeout:
http:
# Slowloris protection -- reject if full request not received in 10s
requestReceivedTimeout: 10s

Note: Envoy's native request_headers_timeout (the most precise slowloris defence) is not yet exposed as a named field in ClientTrafficPolicy. requestReceivedTimeout covers the full request (headers + body) which is the next best thing. For exact header-only timeout, use EnvoyPatchPolicy to inject the raw Envoy HCM request_headers_timeout setting.

Rate limiting via BackendTrafficPolicy:

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
name: dfe-receiver-rate-limit
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: dfe-receiver-route
rateLimit:
type: Local
local:
rules:
- limit:
requests: 100
unit: Second

Envoy Gateway supports both local (per-proxy-instance, no external deps) and global (shared across replicas via external rate limit service with Redis) rate limiting. For dfe-receiver, local rate limiting is sufficient unless running many replicas where per-instance limits are too loose.

HTTPRoute for dfe-receiver:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: dfe-receiver-route
spec:
parentRefs:
- name: dfe-gateway
hostnames:
- "ingest.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: dfe-receiver
port: 8080

2.3 CrowdSec (Free Community IP Reputation)​

CrowdSec is an open-source, community-driven IP reputation engine. MIT-licensed, Go-based (60x faster than fail2ban), with a community blocklist updated by thousands of nodes.

The free tier includes the community blocklist.

Envoy Gateway integration: A community envoy-proxy-crowdsec-bouncer exists (Go, updated Feb 2026). It works as an Envoy ext_authz filter via a SecurityPolicy:

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
name: crowdsec-policy
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: dfe-receiver-route
extAuth:
grpc:
backendRef:
name: crowdsec-bouncer
port: 50051

Maturity caveat: The Envoy bouncer is community-maintained and explicitly marked "not tested in production." For production, evaluate carefully. CrowdSec also has mature bouncers for Traefik and nginx (if using F5's NGINX Ingress Controller as a transitional option).

Effectiveness: The community blocklist blocks a significant portion of known scanners, botnets, and credential stuffing sources before they reach the application.

2.4 Separate Gateway Instances (Isolation)​

Run a dedicated Envoy Gateway for dfe-receiver, separate from other services. A DoS against the ingestion endpoint should not cascade to dashboards, APIs, or other services.

apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: dfe-ingest
spec:
controllerName: gateway.envoyproxy.io/dfe-ingest-controller

---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: dfe-gateway
spec:
gatewayClassName: dfe-ingest
listeners:
- name: https
port: 443
protocol: HTTPS
tls:
mode: Terminate
certificateRefs:
- name: ingest-tls

This costs only the extra resource allocation and prevents cross-service impact.


Part 3: AWS Fronting Architecture (Cost-Conscious)​

The cardinal rule: cost scales with traffic volume. At high ingestion volume, per-GB and per-request charges compound. Every layer that touches traffic must be evaluated on its cost per GB.

3.1 What Each Layer Is Billed On​

This table names the billing unit, not a price. Prices differ by region and change often: check the pricing pages linked under References before sizing a deployment. The billing models below are as of March 2026.

ServiceBilled onNotes
NLBPer hour, plus capacity units for data processedCheaper per GB than ALB. Cross-zone traffic adds a per-GB charge each way.
ALBPer hour, plus capacity units for data and requestsHigher capacity-unit rate than NLB.
AWS WAFPer web ACL, per rule, per million requestsBot Control adds a further ACL charge and request charges.
Shield StandardFreeL3/L4 only, no L7.
Shield AdvancedFlat monthly feeIncludes WAF. 12-month commitment.
CloudFront (pay as you go)Per GB out, per request, in volume tiersTiers cheapen with volume but stay the largest line at ingestion volume.
CloudFront (flat-rate plans)Flat monthly fee with a traffic allowancePerformance degrades once the allowance is exceeded.
Cloudflare FreeFlatUnlimited DDoS mitigation, 5 WAF rules.
Cloudflare ProFlat per domainManaged WAF, 20 rules. Not billed per GB of HTTP traffic.
Cloudflare Spectrum (TCP)Per GB, after a small free allowanceProhibitive at ingestion volume.
CrowdSecFree tierCommunity blocklist, K8s native.

3.2 Why CloudFront is Wrong for Ingestion​

CloudFront is a CDN. It's designed to serve content, not receive it.

Problems for data ingestion:

  • Pay-as-you-go pricing is per GB transferred -- brutal at ingestion volume
  • Designed to cache and serve, not proxy POST requests to origin
  • Adds latency (edge -> origin hop) for non-cacheable traffic
  • The flat-rate plans degrade performance (fewer edge locations) when you exceed the allowance
  • You're paying for CDN features (caching, edge compute) you don't use

The one exception: If you need AWS WAF (which only attaches to CloudFront, ALB, or API Gateway), then CloudFront becomes a required intermediary. But question whether you need AWS WAF at all (see 3.4).

Internet
|
+-- [Cloudflare DNS + Proxy] <- flat-rate plan, unlimited DDoS
| L3/L4/L7 DDoS mitigation
| WAF rules (free tier: 5, Pro: 20)
| IP reputation, bot mitigation
|
+-- [AWS NLB] <- same-AZ preferred
L4 load balancing
Static IP (for Cloudflare origin)
Health checks
|
+-- [K8s Service]
|
+-- [Envoy Gateway] <- open source
Rate limiting (local or global)
Connection limits
Request timeout (slowloris)
CrowdSec ext_authz bouncer
|
+-- [dfe-receiver pods]
App-level auth (bearer/mTLS)
JSON validation
Body size limits
Concurrency limits

Cost drivers: the recurring charges are the Cloudflare plan (flat rate) and the NLB (per hour plus data processed). Envoy Gateway and CrowdSec are open source.

Compare to the "just use AWS" approach (ALB, AWS WAF, Shield Standard): the bill is ALB hours and data, plus WAF per-ACL, per-rule and per-request charges. It still lacks L7 DDoS mitigation, IP reputation and bot mitigation.

Cloudflare's HTTP plans are flat-rate rather than per GB or per request, so the Cloudflare + NLB approach gets cheaper than ALB + WAF as volume grows AND provides better protection.

3.4 When You DON'T Need AWS WAF​

AWS WAF is the right choice when:

  • Compliance requires AWS-native security controls
  • You need deep integration with AWS services (API Gateway, AppSync)
  • You're already on Shield Advanced, which includes WAF

AWS WAF is overkill when:

  • Cloudflare (or similar) already handles L7 filtering upstream
  • Your traffic is API/machine-to-machine (not browsers, less attack surface)
  • You have rate limiting + auth at the application/gateway layer
  • Cost is a major constraint

For dfe-receiver specifically: The traffic is structured JSON from known agents (Vector, Beats, etc.), not browser traffic. The attack surface is narrower than a typical web app. Cloudflare + Envoy Gateway rate limiting + application auth covers the 80/20.

3.5 Architecture Variants​

Variant A: Minimum Viable (Dev/Staging)​

Internet -> NLB -> K8s Service -> dfe-receiver
  • Cost driver: the NLB base charge only
  • Protection: Application-level only (auth, body limits, timeouts)
  • Suitable for: Dev, staging, internal networks

Variant B: Production Standard​

Internet -> Cloudflare -> NLB -> Envoy Gateway -> dfe-receiver
  • Cost driver: NLB data processing, plus a flat Cloudflare plan
  • Protection: DDoS, WAF, rate limiting, IP reputation, auth
  • Suitable for: Most production deployments

Variant C: High-Security / Compliance​

Internet -> CloudFront + AWS WAF -> ALB -> Envoy Gateway -> dfe-receiver
  • Cost driver: CloudFront data transfer dominates
  • Protection: Full AWS-native stack, compliance-ready
  • Suitable for: Regulated industries, AWS-mandated security controls

Variant D: Maximum Protection​

Internet -> Cloudflare Enterprise -> NLB -> Envoy Gateway + CrowdSec -> dfe-receiver
  • Cost driver: a Cloudflare Enterprise contract (custom pricing)
  • Protection: Dedicated DDoS team, custom WAF rules, SLA
  • Suitable for: Tier-1 production, SLA-bound deployments

3.6 Non-HTTP Protocols (Syslog, Beats, Fluent, GELF)​

Most cloud WAF/CDN services only handle HTTP/HTTPS traffic. dfe-receiver's TCP protocols need different treatment.

ProtocolPortTransportFronting Option
HTTP/HTTPS8080HTTPCloudflare + NLB/ALB (standard)
gRPC6000HTTP/2Cloudflare + NLB (gRPC passthrough)
OTLP gRPC4317HTTP/2Cloudflare + NLB
OTLP HTTP4318HTTPCloudflare + NLB/ALB
Splunk HEC8088HTTPCloudflare + NLB/ALB
Prometheus RW9091HTTPCloudflare + NLB/ALB
Lumberjack5044TCPNLB only (no L7 proxy)
Syslog UDP514UDPNLB only
Syslog TCP514TCPNLB only
Syslog TLS6514TCP+TLSNLB only
Fluent24224TCPNLB only
GELF12201TCPNLB only

For TCP protocols:

  • NLB handles L4 load balancing natively (TCP/UDP/TLS)
  • No L7 inspection, no WAF, no rate limiting at this layer
  • Defence-in-depth: Application-level auth + TLS + connection limits are the primary protections for these protocols
  • Consider: mTLS for Beats/syslog/fluent clients (known agent fleet)
  • Consider: IP allowlisting for TCP protocols (senders are usually known)

Cloudflare Spectrum proxies arbitrary TCP/UDP but is billed per GB after a tiny free allowance. At ingestion volume, this is prohibitively expensive and not recommended.

3.7 NLB Configuration Notes​

In a DFE deployment, do not write this Service by hand. dfe-infra renders the receiver's public door from exposure.groups.ingest (dfe-infra docs/ingest-edge.md). With door loadbalancer it renders one load balancer for the TCP ports and one for UDP, plus an ingest NetworkPolicy, and only while the allow list names someone. The allow list becomes each load balancer's loadBalancerSourceRanges, a /0 in it marks the Service dfe.hyperi.io/ingest-fence: allow-all, and on AWS exposure.public.eipAllocations pins Elastic IPs per subnet. The Service below is for running the receiver without dfe-infra.

Same-AZ targeting: To avoid the per-GB cross-zone data charge, configure the NLB target group to use same-AZ routing. This requires your receiver pods to be spread across AZs (which they should be for HA anyway).

# Kubernetes Service annotation for NLB
apiVersion: v1
kind: Service
metadata:
name: dfe-receiver
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "external"
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip"
service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
# Disable cross-zone to avoid the per-GB cross-zone data charge
service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "false"
spec:
type: LoadBalancer
ports:
- name: http
port: 8080
targetPort: 8080
protocol: TCP
- name: grpc
port: 6000
targetPort: 6000
protocol: TCP
- name: beats
port: 5044
targetPort: 5044
protocol: TCP
# ... additional ports

Part 4: Defence-in-Depth Summary​

The complete protection stack, from outer to inner:

Layer 0: DNS Cloudflare DNS (proxy mode) -- free DDoS + WAF
Layer 1: Cloud LB AWS NLB -- L4 load balancing, health checks
Layer 2: K8s Gateway Envoy Gateway -- rate limit, conn limit, request timeout
Layer 3: Community CrowdSec -- IP reputation, community blocklist (via ext_authz)
Layer 4: Application dfe-receiver -- auth, body limit, timeout, concurrency limit, 503 backpressure, slowloris protection, JSON validation
Layer 5: Transport TLS/mTLS -- encryption, client verification
Layer 6: Kafka Circuit breaker, backpressure -- downstream protection

Each layer catches what the previous layer missed.

No single layer is perfect. The value is in the combination:

  • Cloudflare stops volumetric DDoS and known-bad IPs
  • Envoy Gateway stops rate abuse, slow clients, connection floods
  • CrowdSec stops emerging threats via community intelligence
  • Application auth stops unauthorised access
  • TLS/mTLS stops eavesdropping and impersonation
  • Circuit breaker stops downstream cascade failures

Infrastructure Fronting (Deployment-Time)​

These are configured during deployment, not in application code:

LayerComponentWhen to Deploy
Envoy Gateway ClientTrafficPolicyConnection limits + request timeout CRDsAny K8s deployment
Envoy Gateway BackendTrafficPolicyRate limiting CRDsProduction K8s
Cloudflare DNS proxyDNS config changeInternet-facing deployments
CrowdSec + Envoy ext_authz bouncerHelm + SecurityPolicy CRDsHigh-security deployments

See Parts 2 and 3 above for configuration details and cost drivers.


References​

Axum/Tower Security​

K8s Ingress/Gateway Lifecycle​

Envoy Gateway​

AWS Pricing (Verify Before Use)​

Cloudflare​

Open Source Security​