Failure injection có verification rõ ràng
Các lệnh là fixture tái lập cho Linux/WSL/Docker có Nginx và curl. Chưa claim executed; lưu output thật, version và config render khi chạy.
8 labs
Lab 1 · Location precedence trap
Mục tiêu: chứng minh exact/prefix/regex/^~ selection.
location /api/ { return 200 "prefix\n"; }
location ^~ /api/static/ { return 200 "static\n"; }
location ~* \.json$ { return 200 "regex\n"; }
location = /api/health { return 200 "exact\n"; }
# curl -i localhost:8080/api/health
# curl -i localhost:8080/api/x.json
# curl -i localhost:8080/api/static/x.jsonFailure case: bỏ ^~, regex chiếm request static JSON.
Verification: status/body đúng matrix; lưu nginx -T và access log có URI.
Lab 2 · Upstream failure và retry
Mục tiêu: quan sát multiple attempts và giới hạn retry.
upstream demo { server 127.0.0.1:9001; server 127.0.0.1:9002; }
location / { proxy_pass http://demo; proxy_next_upstream error timeout http_502; proxy_next_upstream_tries 2; }
# Start one healthy HTTP server on 9002; leave 9001 closed
# curl -i localhost:8080/Failure case: endpoint POST không-idempotent bị retry.
Verification: log $upstream_addr $upstream_status thấy hai attempts; tắt retry cho unsafe method hoặc chứng minh idempotency key.
Lab 3 · Read timeout không phải total deadline
Mục tiêu: phân biệt inactivity timeout và total latency.
location /slow { proxy_pass http://127.0.0.1:9000; proxy_read_timeout 2s; }
# Upstream sends one byte every 1 second for 10 seconds
# curl -v localhost:8080/slowFailure case: slow trickle không chạm inactivity timeout nhưng vượt SLO.
Verification: curl time_total xấp xỉ 10s; đổi interval 3s nhận 504 và log upstream_response_time.
Lab 4 · Buffering và slow client
Mục tiêu: so sánh upstream occupancy/temp file khi buffering on/off.
location /large { proxy_pass http://127.0.0.1:9000; proxy_buffering on; }
# curl --limit-rate 10k -o /dev/null localhost:8080/large
# Repeat with proxy_buffering offFailure case: nhiều slow clients giữ upstream connections hoặc làm đầy temp disk.
Verification: ghi upstream completion time, active connections, temp path size và p99 cho cả hai mode.
Lab 5 · Cache key cross-tenant leak
Mục tiêu: chứng minh cache key phải chứa identity dimension khi response phụ thuộc identity.
proxy_cache_path /tmp/nginx-cache keys_zone=demo:10m;
location /profile { proxy_cache demo; proxy_cache_key "$scheme$host$uri"; proxy_pass http://127.0.0.1:9000; proxy_set_header X-Tenant $http_x_tenant; add_header X-Cache $upstream_cache_status; }
# curl -H 'X-Tenant: A' localhost:8080/profile
# curl -H 'X-Tenant: B' localhost:8080/profileFailure case: tenant B nhận body của A do key thiếu tenant.
Verification: tái hiện HIT sai, sau đó thêm trusted tenant key hoặc bypass private response và chứng minh isolation.
Lab 6 · Rate limit và spoofed client IP
Mục tiêu: kiểm trust boundary của real IP và limiter key.
limit_req_zone $binary_remote_addr zone=perip:10m rate=2r/s;
location /api { limit_req zone=perip burst=2 nodelay; return 200 "ok\n"; }
# seq 1 10 | xargs -n1 -P10 curl -s -o /dev/null -w '%{http_code}\n' localhost:8080/api
# Repeat with forged X-Forwarded-ForFailure case: cấu hình trust 0.0.0.0/0 cho realip cho phép attacker xoay key.
Verification: có 429/503 theo cấu hình; forged header không đổi effective IP ngoài trusted proxy path.
Lab 7 · TLS/SNI certificate mismatch
Mục tiêu: xác minh certificate selection theo SNI.
# Configure two TLS server blocks with different self-signed certs
openssl s_client -connect 127.0.0.1:8443 -servername api.local </dev/null 2>/dev/null | openssl x509 -noout -subject -fingerprint
curl -vk --resolve api.local:8443:127.0.0.1 https://api.local:8443/Failure case: thiếu SNI/unknown SNI nhận default certificate.
Verification: fingerprint/SAN đúng từng name; unknown name bị reject hoặc nhận documented default policy.
Lab 8 · Graceful reload và old worker drain
Mục tiêu: chứng minh reload không cắt request dài và phát hiện generation cũ không drain.
nginx -t && nginx -s reload
ps -o pid,ppid,state,etime,cmd -C nginx
# Keep one 30s streaming request open, change response header, reload, send a new requestFailure case: long-lived stream/WebSocket giữ old worker; config lỗi khiến reload bị từ chối.
Verification: request cũ hoàn tất, request mới thấy header mới; error log xác nhận reload; old PID biến mất sau drain. Với config lỗi, generation/PID phục vụ vẫn giữ nguyên.
nginx -V, config đã redact, command, raw output/log, expected vs actual, kết luận và cleanup.