API Gateway Security Patterns
The API Gateway as Security Perimeter
An API gateway acts as the single entry point for all client-to-service communication in a microservices architecture. It is uniquely positioned to enforce security policies centrally, reducing complexity in individual services and providing a consistent security layer.
Core Security Functions
Authentication and Authorization
The gateway validates tokens before requests reach backend services, offloading this responsibility from individual services.
# Kong Gateway authentication configuration
services:
- name: user-service
url: http://user-svc.internal:8080
routes:
- name: user-routes
paths:
- /api/users
plugins:
- name: jwt
config:
key_claim_name: iss
secret_is_base64: false
claims_to_verify:
- exp
- nbf
run_on_preflight: true
// Custom auth middleware in Express Gateway
const jwt = require('jsonwebtoken');
async function gatewayAuth(req, res, next) {
const token = req.headers.authorization?.replace('Bearer ', '');
try {
const decoded = jwt.verify(token, PUBLIC_KEY, {
algorithms: ['RS256'],
issuer: 'https://auth.example.com'
});
// Inject validated claims into downstream request
req.headers['x-user-id'] = decoded.sub;
req.headers['x-user-roles'] = decoded.roles.join(',');
req.headers['x-authenticated'] = 'true';
// Strip the original token from downstream
delete req.headers.authorization;
next();
} catch (err) {
return res.status(401).json({ error: 'Invalid token' });
}
}
Rate Limiting and Throttling
The gateway enforces global and per-service rate limits:
plugins:
- name: rate-limiting
config:
second: null
minute: 1000
hour: 50000
policy: local
fault_tolerant: true
hide_client_headers: false
redis:
host: redis.internal
port: 6379
IP Allowlisting and Blocklisting
plugins:
- name: ip-restriction
config:
allow:
- 10.0.0.0/8
- 172.16.0.0/12
deny:
- 10.0.0.42 # Specific blocked IP
Request Validation
Schema Validation
Validate request bodies against OpenAPI schemas at the gateway:
plugins:
- name: request-validator
config:
body_schema:
type: object
required:
- password
properties:
email:
type: string
format: email
maxLength: 255
password:
type: string
minLength: 8
maxLength: 128
parameter_schema:
- in: query
name: page
schema:
type: integer
minimum: 1
Request Size Limiting
# Nginx as API gateway
http {
client_body_buffer_size 128k;
client_max_body_size 10M;
client_body_timeout 30s;
server {
listen 443 ssl;
server_name api.example.com;
location /api/ {
# Limit request size per endpoint
location /api/upload {
client_max_body_size 100M;
}
location /api/query {
client_max_body_size 1K;
}
}
}
}
TLS Termination
Terminate TLS at the gateway to encrypt traffic between clients and the gateway, and optionally re-encrypt between gateway and services:
server {
listen 443 ssl http2;
server_name api.example.com;
ssl_certificate /etc/ssl/certs/api.example.com.pem;
ssl_certificate_key /etc/ssl/private/api.example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Backend communication (re-encrypt)
location /api/internal/ {
proxy_pass https://internal-services;
proxy_ssl_verify on;
proxy_ssl_trusted_certificate /etc/ssl/certs/ca.crt;
}
}
CORS Management
Centrally manage CORS policies:
plugins:
- name: cors
config:
origins:
- https://app.example.com
- https://admin.example.com
methods:
- GET
- POST
- PUT
- DELETE
- PATCH
headers:
- Authorization
- Content-Type
exposed_headers:
- X-RateLimit-Remaining
credentials: true
max_age: 3600
Threat Detection and WAF
ModSecurity with OWASP CRS
# Enable WAF on the gateway
location /api/ {
modsecurity on;
modsecurity_rules_file /etc/nginx/modsecurity/owasp-crs/crs-setup.conf;
# Custom rules
modsecurity_rules '
# Block SQL injection patterns
SecRule REQUEST_URI "@rx (?i:(?:union[\s]+select|select[\s]+from))" \
"id:1000,deny,status:403,msg:\'SQL Injection blocked\'"
# Block common XSS attempts
SecRule ARGS "@rx