k8s5 min readKubernetes Ingress and API Gateway Security: TLS, Auth, and Rate LimitingSecure your Kubernetes ingress and API gateway with this complete guide covering TLS, authentication, rate limiting, WAF, and the Gateway API migration. Ten critical mistakes and how to fix them.ShieldOps AI2026-07-24 ·1Your Kubernetes ingress is the front door to every service in your cluster — and most teams leave it unlocked, unmonitored, and wide open to attackers. A misconfigured Ingress controller or an API gateway with default settings can expose internal services to the internet, bypass authentication, and leak sensitive data through improperly terminated TLS.In the 2026 Cloud Native Security Survey by the CNCF, 68% of respondents reported at least one security incident involving an exposed ingress or API gateway endpoint. The most common root causes were default TLS certificates, missing authentication on admin endpoints, and unrestricted network access from the Ingress controller to all cluster services. This guide walks through the ten most critical mistakes teams make when securing Kubernetes Ingress and API gateways — and exactly how to fix each one.Why Kubernetes Ingress Security MattersAn Ingress controller or API gateway is the single entry point for external traffic into your Kubernetes cluster. Unlike a pod-to-pod connection within the same namespace, Ingress traffic crosses the cluster boundary and enters from the public internet — or at least from an external network you don't fully control. Every request that reaches your Ingress controller has the potential to exploit a misconfiguration and reach a service that was never meant to be public.The Kubernetes Ingress API has evolved significantly. The originalnetworking.k8s.io/v1 Ingress resource is being supplemented — and in many environments replaced — by the Gateway API(gateway.networking.k8s.io), which offers role-oriented configuration, stronger multi-tenancy separation, and first-class support for TLS, HTTP header manipulation, and traffic splitting. Understanding both APIs is essential because most production clusters today run a mix of Ingress and Gateway resources during the migration period. At the same time, third-party API gateways like Kong, Ambassador (now Edge Stack), Traefik, and Gloo add their own CRDs, authentication plugins, and rate-limiting middleware. Each layer you add expands the attack surface unless it is deliberately hardened.Below are the ten most common — and most dangerous — misconfigurations we see in production Kubernetes clusters, with concrete fixes and verification commands for each.Mistake 1: Default TLS Certificate in ProductionEvery major Ingress controller ships with a self-signed or auto-generated TLS certificate for development convenience. NGINX Ingress uses a default certificate stored in theingress-nginx namespace; Traefik generates one at startup; Kong creates a default SNI certificate. Using any of these in production means every client that connects to your services receives a browser warning — or worse, silently accepts a certificate that an attacker could also generate if they know the controller version. The fix:Always provision a TLS certificate from a trusted Certificate Authority (Let's Encrypt, a commercial CA, or an internal PKI for private services). Usecert-manager for automated certificate issuance and renewal: apiVersion: cert-manager.io/v1 kind: Issuer metadata: name: letsencrypt-prod namespace: ingress-nginx spec: acme: server: https://acme-v02.api.letsencrypt.org/directory privateKeySecretRef: name: letsencrypt-prod-key solvers: - http01: ingress: class: nginx --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: my-app annotations: cert-manager.io/cluster-issuer: letsencrypt-prod spec: tls: - hosts: - app.example.com secretName: app-tls rules: - host: app.example.com http: paths: - path: / pathType: Prefix backend: service: name: my-app port: number: 80 Verify that the certificate is valid:openssl s_client -connect app.example.com:443 -servername app.example.com | openssl x509 -noout -dates Mistake 2: Missing Authentication on the Ingress Controller's Own EndpointsThe NGINX Ingress controller exposes a/metrics endpoint, a /healthz endpoint, and a /nginx-statuspage on port 10254 by default. Traefik exposes a dashboard on port 9000. Kong has an Admin API on port 8001. These internal endpoints are intended for cluster-internal monitoring — but if your Ingress controller's pod network policy is too permissive, or if you've inadvertently exposed the dashboard through a Service of type LoadBalancer, an attacker on the internet can enumerate every upstream service, inspect TLS certificates, and read real-time traffic metrics.The fix:Restrict access to these endpoints using Kubernetes Network Policies. For the NGINX Ingress controller:apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: restrict-ingress-nginx-metrics namespace: ingress-nginx spec: podSelector: matchLabels: app.kubernetes.io/component: controller policyTypes: - Ingress ingress: - from: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: monitoring podSelector: matchLabels: app.kubernetes.io/name: prometheus ports: - protocol: TCP port: 10254 Also disable the default server that responds to requests with no matching hostname:# In the NGINX Ingress ConfigMap: data: enable-annotation-validation: "true" default-backend-service: "my-safe-default" # or disable: --default-ssl-certificate: "" Mistake 3: No Rate Limiting on Public EndpointsWithout rate limiting, an attacker can brute-force login endpoints, enumerate valid usernames, or exhaust cluster resources with a simple script. The Kubernetes Ingress resource does not natively support rate limiting — you must configure it at the Ingress controller or API gateway layer. NGINX Ingress provides annotations for this; Kong and Ambassador include rate-limiting plugins.The fix:Use NGINX Ingress annotations to enforce per-IP or per-connection limits:apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: api-gateway annotations: nginx.ingress.kubernetes.io/limit-rps: "10" nginx.ingress.kubernetes.io/limit-burst-multiplier: "3" nginx.ingress.kubernetes.io/limit-whitelist: "10.0.0.0/8, 172.16.0.0/12" spec: ingressClassName: nginx tls: - hosts: - api.example.com secretName: api-tls rules: - host: api.example.com http: paths: - path: /login pathType: Prefix backend: service: name: auth-service port: number: 8080 For Kong Gateway, use the rate-limiting plugin in declarative config:plugins: - name: rate-limiting service: auth-service config: minute: 20 hour: 500 policy: local Mistake 4: Allowing Host Header Injection and Routing BypassWhen an Ingress controller processes an incoming request, it selects the correct backend based on theHost header. If the controller's default backend serves a catch-all response, an attacker can send a request with a Host header that doesn't match any rule and potentially reach internal services or get a detailed error page that reveals stack traces and internal IP addresses. The fix:Always set a safe default backend and reject unknown hosts at the firewall level. For NGINX Ingress:# In the NGINX Ingress ConfigMap data: default-backend-service: ingress-nginx/404-default enable-underscores-in-headers: "false" log-format-escape-json: "true" use-proxy-protocol: "false" # Alternatively, use the --default-backend-service flag # Deploy a simple 404 responder: apiVersion: v1 kind: Service metadata: name: 404-default namespace: ingress-nginx spec: selector: app: 404-default ports: - port: 80 targetPort: 8080 Use cert-manager and Let's Encrypt to enforce TLS on every host, which prevents cleartext host-header manipulation between the client and the controller.Mistake 5: Overly Permissive Ingress Controller RBACThe Ingress controller needs to read Ingress and Service resources across namespaces to function. Many default Helm charts grant cluster-wide permissions far beyond what is necessary. If the controller pod is compromised — through a CVE in NGINX, a supply-chain attack on the controller image, or a misconfigured admission webhook — an attacker inherits the controller's ServiceAccount permissions and can read Secrets, create new Ingress rules, or even escalate to cluster-admin.The fix:Audit the Ingress controller's RBAC bindings and restrict them to the minimum required:# Minimal ClusterRole for NGINX Ingress Controller apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: ingress-nginx-minimal rules: - apiGroups: ["networking.k8s.io", "extensions"] resources: ["ingresses"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["services", "endpoints", "secrets"] verbs: ["get", "list", "watch"] - apiGroups: ["discovery.k8s.io"] resources: ["endpointslices"] verbs: ["get", "list", "watch"] --- # No "secrets" create/update/delete unless you use # the controller for TLS certificate management Verify with:kubectl describe clusterrolebinding ingress-nginx | grep -A5 Subjects and check the rules on the bound ClusterRole. Mistake 6: Disabling TLS Verification Between Ingress and Backend ServicesBy default, the NGINX Ingress controller communicates with backend services over plain HTTP on the service port. Even if the external connection uses HTTPS, the hop between the Ingress controller and your application pod is unencrypted. An attacker who gains access to the cluster network — through a compromised sidecar, a misconfigured network policy, or a pod in the same node — can sniff traffic between the Ingress controller and your backend services.The fix:Configure mTLS between the Ingress controller and backend services where possible, or at minimum use TLS for the internal hop:apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: secure-backend annotations: nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" nginx.ingress.kubernetes.io/ssl-passthrough: "false" nginx.ingress.kubernetes.io/secure-backends: "true" nginx.ingress.kubernetes.io/ssl-verify: "true" nginx.ingress.kubernetes.io/proxy-ssl-secret: "default/backend-ca-secret" nginx.ingress.kubernetes.io/proxy-ssl-verify: "on" spec: tls: - hosts: - app.example.com secretName: app-tls rules: - host: app.example.com http: paths: - path: / pathType: Prefix backend: service: name: my-app port: number: 443 For service mesh environments (Istio, Linkerd), enableStrict mTLSmode on the mesh, which encrypts all inter-pod traffic automatically:apiVersion: security.istio.io/v1beta1 kind: PeerAuthentication metadata: name: default-strict namespace: istio-system spec: mtls: mode: STRICT Mistake 7: Exposing Internal Services Through Wildcard or Catch-All Ingress RulesA single Ingress rule with a wildcard host (*.example.com) or a catch-all path (/) that matches every request can inadvertently expose internal dashboards, CI/CD tools, or monitoring interfaces. We have seen production incidents where a Grafana dashboard, a Jenkins controller, or a RabbitMQ management UI was accessible from the internet because the team relied on "security through obscurity" (no DNS record, no public knowledge of the subdomain) instead of actual access controls. The fix:Instead of a single catch-all Ingress, create separate Ingress resources for each subdomain or path prefix, and use network policies to limit egress from the Ingress controller to only the required services:# Bad: single catch-all # apiVersion: networking.k8s.io/v1 # kind: Ingress # spec: # rules: # - host: *.example.com # DANGEROUS # http: # paths: # - path: / # backend: # service: # name: any-service # port: # number: 80 # Good: explicit per-service Ingress apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: app-ingress annotations: nginx.ingress.kubernetes.io/whitelist-source-range: "0.0.0.0/0" # public cert-manager.io/cluster-issuer: letsencrypt-prod spec: ingressClassName: nginx tls: - hosts: - app.example.com secretName: app-tls rules: - host: app.example.com http: paths: - path: / pathType: Prefix backend: service: name: app-service port: number: 80 --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: internal-tools annotations: nginx.ingress.kubernetes.io/whitelist-source-range: "10.0.0.0/8, 192.168.0.0/16" spec: ingressClassName: nginx tls: - hosts: - grafana.internal.example.com secretName: internal-tls rules: - host: grafana.internal.example.com http: paths: - path: / pathType: Prefix backend: service: name: grafana port: number: 3000 Mistake 8: Not Using Web Application Firewall (WAF) RulesA vanilla Ingress controller forwards every HTTP request verbatim to the backend service. SQL injection payloads, XSS attempts, path traversal sequences, and large request bodies all pass through unmodified. While the backend application should validate input, defense in depth dictates that the edge layer should also filter malicious traffic before it reaches your pods.The fix:Enable ModSecurity with the OWASP Core Rule Set (CRS) on the NGINX Ingress controller, or use a dedicated WAF like Cloudflare, AWS WAF, or Signal Sciences:# Enable ModSecurity in the NGINX Ingress ConfigMap apiVersion: v1 kind: ConfigMap metadata: name: ingress-nginx-controller namespace: ingress-nginx data: enable-modsecurity: "true" enable-owasp-modsecurity-crs: "true" modsecurity-snippet: | SecRuleEngine On SecRequestBodyAccess On SecResponseBodyAccess On SecResponseBodyMimeType text/plain text/html text/xml SecDefaultAction "phase:1,log,auditlog,pass" SecAuditEngine RelevantOnly SecAuditLog /var/log/modsec_audit.log # Verify with: # curl -X POST https://app.example.com/search -d "q=1' OR '1'='1" # Should return 403 Forbidden For the Gateway API, use policy attachment to apply WAF rules at the gateway level. Thev1alpha2 HTTPRouteresource supports filter rules that can redirect, rewrite, or reject requests based on headers, path, or query parameters.Mistake 9: Ignoring the Gateway API Migration PathThe original Ingress API (networking.k8s.io/v1) has several limitations: it cannot express cross-namespace routing, header-based routing, or weighted traffic splitting without controller-specific annotations. The Gateway API(gateway.networking.k8s.io) was designed as the successor with role-oriented resources (Gateway, GatewayClass, HTTPRoute, TLSRoute) that separate infrastructure concerns from application routing. Clusters still using only the Ingress API are missing built-in support for advanced security patterns like per-route authentication, request mirroring for security analysis, and fine-grained TLS configuration. The fix:Start migrating to the Gateway API. Install the Gateway API CRDs and begin with a simple HTTPRoute for a non-critical service:# Install Gateway API CRDs # kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/experimental-install.yaml apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: production-gateway spec: gatewayClassName: nginx listeners: - name: https protocol: HTTPS port: 443 tls: mode: Terminate certificateRefs: - name: app-tls allowedRoutes: namespaces: from: Selector selector: matchLabels: security-tier: "trusted" --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: app-route spec: parentRefs: - name: production-gateway hostnames: - app.example.com rules: - matches: - path: value: /api filters: - type: RequestHeaderModifier requestHeaderModifier: add: - name: X-Frame-Options value: DENY backendRefs: - name: api-service port: 8080 - matches: - path: value: /login filters: - type: RequestHeaderModifier requestHeaderModifier: add: - name: Strict-Transport-Security value: max-age=31536000; includeSubDomains backendRefs: - name: auth-service port: 8080 Mistake 10: Disabling Access Logs and Monitoring on the Ingress ControllerWithout access logs, you cannot detect ongoing attacks — credential stuffing, SQL injection probes, path traversal attempts — against your services. Many production clusters run with default logging settings that either produce too little detail (no request body, no response status) or log everything to stdout without structured formats, making analysis in SIEM tools like Splunk, Elastic, or Loki impractical.The fix:Enable structured JSON logging on the Ingress controller and ship logs to a centralized monitoring system:# NGINX Ingress ConfigMap for structured logging apiVersion: v1 kind: ConfigMap metadata: name: ingress-nginx-controller namespace: ingress-nginx data: log-format-escape-json: "true" log-format-upstream: '{"time": "$time_iso8601", "remote_addr": "$remote_addr", "host": "$host", "method": "$request_method", "path": "$uri", "status": $status, "body_bytes_sent": $body_bytes_sent, "referer": "$http_referer", "user_agent": "$http_user_agent", "request_length": $request_length, "upstream_addr": "$upstream_addr", "upstream_response_time": "$upstream_response_time", "ssl_protocol": "$ssl_protocol", "ssl_cipher": "$ssl_cipher"}' Set up alerts for HTTP 4xx and 5xx spikes, unusual request patterns (same path repeated >100 times from one IP), and requests with suspicious User-Agent strings.Monitoring hint: deploy Prometheus with the NGINX Ingress metrics exporter and create Grafana dashboards for request rate, error rate, latency (P99), and TLS certificate expiry.Complete Kubernetes Ingress Security Checklist⬜ All Ingress and Gateway resources use TLS from a trusted CA (not self-signed)⬜ TLS certificates are managed by cert-manager with auto-renewal⬜ Ingress controller's admin/metrics endpoints are firewalled with NetworkPolicies⬜ Rate limiting is enabled on all public-facing endpoints⬜ Default backend returns 404 for unmatched hosts and paths⬜ Ingress controller ServiceAccount has least-privilege RBAC (no cluster-admin)⬜ mTLS or HTTPS is enforced between the Ingress controller and backend services⬜ Internal dashboards and tools are NOT accessible through the same Ingress that serves public traffic⬜ WAF rules (ModSecurity + OWASP CRS) are enabled on the edge⬜ Structured access logs are shipped to a SIEM or centralized log system⬜ Alerts are configured for 4xx/5xx surges and anomalous traffic patterns⬜ Ingress and Gateway API resources are audited weekly for unused routes⬜ Host header validation prevents routing bypass attacks⬜ Migration plan exists from Ingress v1 to the Gateway APIRelated ShieldOps ReadsStrengthen your Kubernetes security posture with these related articles:Kubernetes RBAC Deep Dive: Least Privilege Access ControlKubernetes Network Policies: Enforcing Zero-Trust at the Network LayerKubernetes Audit Logging: Detecting IntrusionsContainer Security Architecture: The 4 PillarsKubernetes Supply Chain SecurityYour First Security Scan With ShieldOpsShieldOps Security OverviewShieldOps AI AssistantCompliance AutomationPlans & PricingRegister for ShieldOpsFrequently Asked QuestionsWhat is the difference between Ingress and the Gateway API?The Ingress API (networking.k8s.io/v1) is a single flat resource that combines infrastructure and routing configuration. The Gateway API (gateway.networking.k8s.io) separates concerns into GatewayClass (infrastructure provider), Gateway (instance), and HTTPRoute/TLSRoute (application routing), enabling better multi-team isolation, cross-namespace routing, and richer security policies. Should I use NGINX Ingress, Traefik, or Kong for production?All three are production-grade. NGINX Ingress is the most widely deployed, with the largest ecosystem of annotations and community support. Traefik excels in dynamic environments with automatic service discovery and Let's Encrypt integration. Kong offers a plugin ecosystem for authentication, rate limiting, and logging at the gateway layer. Choose based on your team's familiarity and whether you need advanced plugin capabilities.How do I enforce HTTPS-only access on my Ingress?Usecert-manager with Let's Encrypt to provision TLS certificates automatically, then set nginx.ingress.kubernetes.io/ssl-redirect: "true" on each Ingress resource. For a cluster-wide redirect, configure the default backend to return a 308 redirect status code for HTTP requests. The Gateway API's HTTPRoute supports redirect filters natively. Can I use a single Ingress controller for both public and private services?Yes — but configure two separate Ingress resources: one for public services withwhitelist-source-range: "0.0.0.0/0" and one for private services with a restricted CIDR range (e.g., "10.0.0.0/8"). For stronger isolation, deploy separate Ingress controller instances — one for internet-facing traffic and one for internal traffic — each with its own NetworkPolicy and RBAC. How do I detect an Ingress misconfiguration before it reaches production?Usekubectl ingress-nginx lint or a policy engine like OPA Gatekeeper or Kyverno to validate Ingress resources against your organization's security policies. For example, enforce that every Ingress has a tls block, a cert-manager.io/cluster-issuer annotation, and a rate-limiting annotation. Use admission webhooks to reject resources that don't meet these requirements. What is the impact of a compromised Ingress controller?A compromised Ingress controller can read TLS certificates (potentially decrypting traffic across all services), redirect traffic to attacker-controlled backends, modify responses to inject malicious content, and, if RBAC is over-permissive, access Secrets and create or modify Ingress resources across namespaces. This is why least-privilege RBAC and strict NetworkPolicies around the controller are critical controls.Should I use mTLS for all ingress-to-backend communication?Yes, whenever possible. If your backend services support HTTPS, configure the Ingress controller to usebackend-protocol: HTTPS with certificate verification. In a service mesh (Istio, Linkerd, Cilium), enable strict mTLS mode to encrypt all inter-pod traffic automatically without modifying application code. ConclusionKubernetes Ingress and API gateway security is not optional — it is the first line of defense for every external-facing service in your cluster. The ten mistakes covered in this guide represent the most common misconfigurations we see in production environments, from default TLS certificates and missing authentication to unmonitored access logs and over-privileged RBAC.The path to a hardened ingress layer is clear: enforce TLS with cert-manager, restrict the controller's network and RBAC permissions, enable rate limiting and WAF rules, and monitor every request through structured logging and alerting. As the Kubernetes ecosystem evolves toward the Gateway API, each of these controls becomes simpler to express and enforce at the platform level rather than per-application.Start your security audit today: runkubectl get ingress --all-namespaces and check every resource against the checklist above. Use ShieldOpsto automate policy enforcement, vulnerability scanning, and compliance reporting for your Kubernetes clusters — so you catch these mistakes before attackers do.#kubernetes#ingress#api-gateway#tls#rate-limitingReady to apply these concepts?Scan your Kubernetes manifests for RBAC gaps, policy issues, and misconfigurations.Scan Your Kubernetes ClusterRelated PostsKubernetes Audit Logging: Detecting Intrusions Through API Server Trails2026-07-23Kubernetes Supply Chain Security: From Git to Cluster With Sigstore2026-06-23Kubernetes Network Policies: Enforcing Zero-Trust at the Network Layer2026-06-21Your takeRate this article or leave a commentShare Submit commentHave more questions? Check ourFAQ