Skip to main content

05. API Gateway & Defense Patterns

Enforcing security controls exclusively within individual application microservices leads to inconsistent security coverage, configuration drift, and duplicate logic. A resilient security architecture adopts a Defense-in-Depth model: offloading central traffic policies, schema validation, rate limiting, and mTLS to an API Gateway Tier before requests reach backend application microservices.


1. Gateway Schema Validation (OpenAPI 3.1 Contract Enforcement)

Validating incoming JSON request payloads against strict OpenAPI specs at the gateway layer drops malformed, extra-property, or unexpected parameter attacks before they reach backend microservices, neutralizing Mass Assignment vectors at the perimeter.

Production OpenAPI Schema (user_request_schema.json)

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email",
"maxLength": 100
},
"username": {
"type": "string",
"pattern": "^[a-zA-Z0-9_]{3,30}$"
},
"age": {
"type": "integer",
"minimum": 18,
"maximum": 120
}
},
"required": ["email", "username"],
"additionalProperties": false
}

[!IMPORTANT] Key Schema Rule: Setting "additionalProperties": false is vital. It instructs the schema validator to reject payloads containing unexpected internal fields like "is_admin": true or "role": "superuser".


2. Hardened Production Gateway Configurations

A. Hardened Nginx API Gateway Configuration (nginx.conf)

# nginx_api_gateway.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
worker_connections 2048;
}

http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

# Hide Nginx version banner
server_tokens off;

# Rate Limiting Zone (10 requests/sec per IP, 10MB zone memory)
limit_req_zone $binary_remote_addr zone=api_ip_limit:10m rate=10r/s;
limit_req_status 429;

# Request Body Size Limitation (Prevent DoS buffer overflow)
client_max_body_size 1M;
client_body_buffer_size 16k;
client_header_buffer_size 1k;
large_client_header_buffers 4 8k;

# Timeout limits to prevent Slowloris attacks
client_body_timeout 10s;
client_header_timeout 10s;
keepalive_timeout 15s;
send_timeout 10s;

# Upstream Microservice Cluster
upstream backend_api_cluster {
server 10.0.1.50:8080 max_fails=3 fail_timeout=10s;
server 10.0.1.51:8080 max_fails=3 fail_timeout=10s;
keepalive 32;
}

server {
listen 443 ssl http2;
server_name api.company.com;

# TLS Hardening (TLS 1.2 & 1.3 only, strong ciphers)
ssl_certificate /etc/ssl/certs/api_gateway.crt;
ssl_certificate_key /etc/ssl/private/api_gateway.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;

# Security Headers
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header X-XSS-Protection "0" always;
add_header Content-Security-Policy "default-src 'none';" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

# CORS Policy (Restrict to authorized client origins)
location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' 'https://app.company.com' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, X-Requested-With' always;
add_header 'Access-Control-Max-Age' 86400;
add_header 'Content-Length' 0;
return 204;
}

add_header 'Access-Control-Allow-Origin' 'https://app.company.com' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;

# Enforce Rate Limiting
limit_req zone=api_ip_limit burst=20 nodelay;

# Proxy Headers & Forwarding
proxy_pass http://backend_api_cluster;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
}
}

B. Kong Declarative Gateway Security Configuration (kong.yml)

_format_version: "3.0"

services:
- name: user-service
url: http://user-service.internal:8080
routes:
- name: user-routes
paths:
- /v1/users
strip_path: false

plugins:
# 1. Global Rate Limiting Plugin
- name: rate-limiting
config:
minute: 100
hour: 5000
policy: redis
redis_host: redis.internal
redis_port: 6379
fault_tolerant: false

# 2. JWT Authentication Plugin
- name: jwt
config:
claims_to_verify:
- exp
key_claim_name: iss
secret_is_base64: false

# 3. CORS Hardening Plugin
- name: cors
config:
origins:
- https://app.company.com
methods:
- GET
- POST
- PUT
- DELETE
headers:
- Authorization
- Content-Type
credentials: true
max_age: 3600

# 4. Request Size Limiting Plugin
- name: request-size-limiting
config:
allowed_payload_size: 1 # Max 1MB

C. Envoy Proxy Configuration for gRPC & mTLS (envoy.yaml)

static_resources:
listeners:
- name: grpc_listener
address:
socket_address:
address: 0.0.0.0
port_value: 10000
filter_chains:
- transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
common_tls_context:
tls_certificates:
- certificate_chain: { filename: "/etc/envoy/certs/server.crt" }
private_key: { filename: "/etc/envoy/certs/server.key" }
validation_context:
trusted_ca: { filename: "/etc/envoy/certs/ca.crt" }
# Require and verify client certificate (mTLS)
require_client_certificate: true
filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: grpc_json
codec_type: AUTO
route_config:
name: local_route
virtual_hosts:
- name: grpc_service
domains: ["*"]
routes:
- match: { prefix: "/" }
route: { cluster: internal_grpc_service }
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

clusters:
- name: internal_grpc_service
type: STRICT_DNS
lb_policy: ROUND_ROBIN
http2_protocol_options: {}
load_assignment:
cluster_name: internal_grpc_service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 50051

3. CORS Security & Common Misconfigurations

Cross-Origin Resource Sharing (CORS) is a browser enforcement mechanism that dictates whether web applications hosted on one origin can read responses from another origin.

[!WARNING] CORS is NOT an API security control against automated scripts or curl attacks. It is purely a browser policy to protect browser users from cross-origin data theft.

Dangerous CORS Misconfigurations

  1. Arbitrary Origin Reflection with Credentials:

    # VULNERABLE: Reflects any incoming Origin header back to client with credentials!
    add_header Access-Control-Allow-Origin $http_origin;
    add_header Access-Control-Allow-Credentials 'true';

    Exploit: An attacker tricks a logged-in user into visiting evil.com. JavaScript on evil.com sends a fetch('https://api.company.com/user/data', {credentials: 'include'}). The server reflects Access-Control-Allow-Origin: https://evil.com, allowing evil.com to read private user responses!

  2. Trusting null Origin:

    # VULNERABLE: Trusting 'null' origin
    add_header Access-Control-Allow-Origin 'null';

    Exploit: Attackers execute requests from sandboxed <iframe> tags or local file origins (file://), which emit Origin: null.


4. Defense-in-Depth Layering Matrix

Security LayerResponsible ComponentKey Security Controls Applied
1. Edge NetworkWAF / CDN (Cloudflare, AWS Shield)DDoS mitigation, IP Reputation, Bot score management, Geo-blocking.
2. API GatewayNginx / Kong / EnvoyTLS termination, mTLS, OpenAPI schema validation, global rate limiting, CORS.
3. Identity ProviderKeycloak / Auth0 / OktaOAuth2 token issuance, MFA, SAML, PKCE code challenge verification.
4. App MicroserviceApplication MiddlewareFine-grained BOLA checks (user_id = auth_id), BFLA RBAC decorators, DTO binding.
5. Database TierDB / ORMEncrypted storage, parameterized queries (SQLi prevention), column-level access controls.

Next Chapter: 06. Hands-On Vulnerability Lab →

Share this guide