Skip to content

Instantly share code, notes, and snippets.

@Havanero
Forked from nginx-gists/api_gateway.conf
Created February 18, 2020 20:37
Show Gist options
  • Save Havanero/065d910f73aa5ddba66abb51d237a792 to your computer and use it in GitHub Desktop.
Save Havanero/065d910f73aa5ddba66abb51d237a792 to your computer and use it in GitHub Desktop.

Revisions

  1. @nginx-gists nginx-gists revised this gist Jul 18, 2018. 2 changed files with 12 additions and 3 deletions.
    10 changes: 8 additions & 2 deletions warehouse_api.conf
    Original file line number Diff line number Diff line change
    @@ -1,13 +1,19 @@
    # API definition
    #
    location /api/warehouse/pricing {
    limit_except GET PATCH {}
    limit_except GET PATCH {
    deny all;
    }
    error_page 403 = @405; # Convert response from '403 (Forbidden)' to '405 (Method Not Allowed)'
    set $upstream pricing_service;
    rewrite ^ /_warehouse last;
    }

    location /api/warehouse/inventory {
    limit_except GET {}
    limit_except GET {
    deny all;
    }
    error_page 403 = @405;
    set $upstream inventory_service;
    rewrite ^ /_warehouse last;
    }
    5 changes: 4 additions & 1 deletion warehouse_api_methods.conf
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,10 @@
    # API definition
    #
    location /api/warehouse/pricing {
    limit_except GET PATCH DELETE {}
    limit_except GET PATCH DELETE {
    deny all;
    }
    error_page 403 = @405; # Convert response from '403 (Forbidden)' to '405 (Method Not Allowed)'
    set $upstream pricing_service;
    rewrite ^ /_warehouse_$request_type last;
    }
  2. @nginx-gists nginx-gists revised this gist Jun 6, 2018. 5 changed files with 7 additions and 0 deletions.
    1 change: 1 addition & 0 deletions warehouse_api.conf
    Original file line number Diff line number Diff line change
    @@ -5,6 +5,7 @@ location /api/warehouse/pricing {
    set $upstream pricing_service;
    rewrite ^ /_warehouse last;
    }

    location /api/warehouse/inventory {
    limit_except GET {}
    set $upstream inventory_service;
    2 changes: 2 additions & 0 deletions warehouse_api_apikeys.conf
    Original file line number Diff line number Diff line change
    @@ -4,10 +4,12 @@ location /api/warehouse/pricing {
    set $upstream pricing_service;
    rewrite ^ /_warehouse last;
    }

    location /api/warehouse/inventory {
    set $upstream inventory_service;
    rewrite ^ /_warehouse last;
    }

    location = /api/warehouse/inventory/audit {
    if ($is_infrastructure = 0) {
    return 403; # Forbidden (not infrastructure)
    1 change: 1 addition & 0 deletions warehouse_api_bodysize.conf
    Original file line number Diff line number Diff line change
    @@ -4,6 +4,7 @@ location /api/warehouse/pricing {
    set $upstream pricing_service;
    rewrite ^ /_warehouse last;
    }

    location /api/warehouse/inventory {
    set $upstream inventory_service;
    rewrite ^ /_warehouse last;
    1 change: 1 addition & 0 deletions warehouse_api_jsonbody.conf
    Original file line number Diff line number Diff line change
    @@ -4,6 +4,7 @@ location /api/warehouse/pricing {
    set $upstream pricing_service;
    rewrite ^ /_warehouse last;
    }

    location /api/warehouse/inventory {
    set $upstream inventory_service;
    rewrite ^ /_warehouse last;
    2 changes: 2 additions & 0 deletions warehouse_api_methods.conf
    Original file line number Diff line number Diff line change
    @@ -5,6 +5,7 @@ location /api/warehouse/pricing {
    set $upstream pricing_service;
    rewrite ^ /_warehouse_$request_type last;
    }

    location /api/warehouse/inventory {
    set $upstream inventory_service;
    rewrite ^ /_warehouse_$request_type last;
    @@ -21,6 +22,7 @@ location = /_warehouse_READ {

    proxy_pass http://$upstream$request_uri;
    }

    location = /_warehouse_WRITE {
    internal;
    set $api_name "Warehouse";
  3. @nginx-gists nginx-gists created this gist Jun 6, 2018.
    59 changes: 59 additions & 0 deletions api_gateway.conf
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,59 @@
    log_format api_main '$remote_addr - $remote_user [$time_local] "$request"'
    '$status $body_bytes_sent "$http_referer" "$http_user_agent"'
    '"$http_x_forwarded_for" "$api_name"';

    include api_backends.conf;
    include api_keys.conf;

    limit_req_zone $binary_remote_addr zone=client_ip_10rs:1m rate=10r/s;
    limit_req_zone $http_apikey zone=apikey_200rs:1m rate=200r/s;

    server {
    set $api_name -; # Start with an undefined API name, each API will update this value
    access_log /var/log/nginx/api_access.log api_main; # Each API may also log to a separate file

    listen 443 ssl;
    server_name api.example.com;

    # TLS config
    ssl_certificate /etc/ssl/certs/api.example.com.crt;
    ssl_certificate_key /etc/ssl/private/api.example.com.key;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 5m;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_protocols TLSv1.1 TLSv1.2;

    # API definitions, one per file
    include api_conf.d/*.conf;

    # Error responses
    error_page 404 = @400; # Invalid paths are treated as bad requests
    proxy_intercept_errors on; # Do not send backend errors to the client
    include api_json_errors.conf; # API client friendly JSON error responses
    default_type application/json; # If no content-type then assume JSON

    # Dummy location used to populate $request_body for JSON validation
    location = /_NULL {
    internal;
    return 204;
    }
    }

    js_include json_validator.js;
    js_set $validated json_validator;

    server {
    listen 127.0.0.1:10415; # This is the error response of json_validator()
    return 415; # Unsupported media type
    include api_json_errors.conf;
    }

    # Coalesce request method to READ|WRITE
    map $request_method $request_type {
    "GET" "READ";
    "HEAD" "READ";
    "OPTIONS" "READ";
    default "WRITE";
    }

    # vim: syntax=nginx
    52 changes: 52 additions & 0 deletions api_json_errors.conf
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,52 @@
    error_page 400 = @400;
    location @400 { return 400 '{"status":400,"message":"Bad request"}\n'; }

    error_page 401 = @401;
    location @401 { return 401 '{"status":401,"message":"Unauthorized"}\n'; }

    error_page 403 = @403;
    location @403 { return 403 '{"status":403,"message":"Forbidden"}\n'; }

    error_page 404 = @404;
    location @404 { return 404 '{"status":404,"message":"Resource not found"}\n'; }

    error_page 405 = @405;
    location @405 { return 405 '{"status":405,"message":"Method not allowed"}\n'; }

    error_page 408 = @408;
    location @408 { return 408 '{"status":408,"message":"Request timeout"}\n'; }

    error_page 413 = @413;
    location @413 { return 413 '{"status":413,"message":"Payload too large"}\n'; }

    error_page 414 = @414;
    location @414 { return 414 '{"status":414,"message":"Request URI too large"}\n'; }

    error_page 415 = @415;
    location @415 { return 415 '{"status":415,"message":"Unsupported media type"}\n'; }

    error_page 426 = @426;
    location @426 { return 426 '{"status":426,"message":"HTTP request was sent to HTTPS port"}\n'; }

    error_page 429 = @429;
    location @429 { return 429 '{"status":429,"message":"API rate limit exceeded"}\n'; }

    error_page 495 = @495;
    location @495 { return 495 '{"status":495,"message":"Client certificate authentication error"}\n'; }

    error_page 496 = @496;
    location @496 { return 496 '{"status":496,"message":"Client certificate not presented"}\n'; }

    error_page 497 = @497;
    location @497 { return 497 '{"status":497,"message":"HTTP request was sent to mutual TLS port"}\n'; }

    error_page 500 = @500;
    location @500 { return 500 '{"status":500,"message":"Server error"}\n'; }

    error_page 501 = @501;
    location @501 { return 501 '{"status":501,"message":"Not implemented"}\n'; }

    error_page 502 = @502;
    location @502 { return 502 '{"status":502,"message":"Bad gateway"}\n'; }

    # vim: syntax=nginx
    18 changes: 18 additions & 0 deletions api_keys.conf
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,18 @@
    map $http_apikey $api_client_name {
    default "";

    "7B5zIqmRGXmrJTFmKa99vcit" "client_one";
    "QzVV6y1EmQFbbxOfRCwyJs35" "client_two";
    "mGcjH8Fv6U9y3BVF9H3Ypb9T" "client_six";
    }

    # Infrastructure clients
    #
    map $api_client_name $is_infrastructure {
    default 0;

    "client_one" 1;
    "client_six" 1;
    }

    # vim: syntax=nginx
    11 changes: 11 additions & 0 deletions json_validator.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,11 @@
    function json_validator(req) {
    try {
    if ( req.variables.request_body.length > 0 ) {
    JSON.parse(req.variables.request_body);
    }
    return req.variables.upstream;
    } catch (e) {
    req.log('JSON.parse exception');
    return '127.0.0.1:10415'; // Address for error response
    }
    }
    26 changes: 26 additions & 0 deletions warehouse_api.conf
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,26 @@
    # API definition
    #
    location /api/warehouse/pricing {
    limit_except GET PATCH {}
    set $upstream pricing_service;
    rewrite ^ /_warehouse last;
    }
    location /api/warehouse/inventory {
    limit_except GET {}
    set $upstream inventory_service;
    rewrite ^ /_warehouse last;
    }

    # Policy section
    #
    location = /_warehouse {
    internal;
    set $api_name "Warehouse";

    limit_req zone=client_ip_10rs;
    limit_req_status 429;

    proxy_pass http://$upstream$request_uri;
    }

    # vim: syntax=nginx
    35 changes: 35 additions & 0 deletions warehouse_api_apikeys.conf
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,35 @@
    # API definition
    #
    location /api/warehouse/pricing {
    set $upstream pricing_service;
    rewrite ^ /_warehouse last;
    }
    location /api/warehouse/inventory {
    set $upstream inventory_service;
    rewrite ^ /_warehouse last;
    }
    location = /api/warehouse/inventory/audit {
    if ($is_infrastructure = 0) {
    return 403; # Forbidden (not infrastructure)
    }
    set $upstream inventory_service;
    rewrite ^ /_warehouse last;
    }

    # Policy section
    #
    location = /_warehouse {
    internal;
    set $api_name "Warehouse";

    if ($http_apikey = "") {
    return 401; # Unauthorized (please authenticate)
    }
    if ($api_client_name = "") {
    return 403; # Forbidden (invalid API key)
    }

    proxy_pass http://$upstream$request_uri;
    }

    # vim: syntax=nginx
    23 changes: 23 additions & 0 deletions warehouse_api_bodysize.conf
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,23 @@
    # API definition
    #
    location /api/warehouse/pricing {
    set $upstream pricing_service;
    rewrite ^ /_warehouse last;
    }
    location /api/warehouse/inventory {
    set $upstream inventory_service;
    rewrite ^ /_warehouse last;
    }

    # Policy section
    #
    location = /_warehouse {
    internal;
    set $api_name "Warehouse";

    client_max_body_size 16k;

    proxy_pass http://$upstream$request_uri;
    }

    # vim: syntax=nginx
    26 changes: 26 additions & 0 deletions warehouse_api_jsonbody.conf
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,26 @@
    # API definition
    #
    location /api/warehouse/pricing {
    set $upstream pricing_service;
    rewrite ^ /_warehouse last;
    }
    location /api/warehouse/inventory {
    set $upstream inventory_service;
    rewrite ^ /_warehouse last;
    }

    # Policy section
    #
    location = /_warehouse {
    internal;
    set $api_name "Warehouse";

    mirror /_NULL; # Create a copy of the request to capture request body
    client_body_in_single_buffer on; # Minimize memory copy operations on request body
    client_body_buffer_size 16k; # Largest body to keep in memory (before writing to file)
    client_max_body_size 16k;

    proxy_pass http://$validated$request_uri;
    }

    # vim: syntax=nginx
    37 changes: 37 additions & 0 deletions warehouse_api_methods.conf
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,37 @@
    # API definition
    #
    location /api/warehouse/pricing {
    limit_except GET PATCH DELETE {}
    set $upstream pricing_service;
    rewrite ^ /_warehouse_$request_type last;
    }
    location /api/warehouse/inventory {
    set $upstream inventory_service;
    rewrite ^ /_warehouse_$request_type last;
    }

    # Policy section
    #
    location = /_warehouse_READ {
    internal;
    set $api_name "Warehouse";

    auth_jwt $api_name;
    auth_jwt_key_file /etc/nginx/jwk.json;

    proxy_pass http://$upstream$request_uri;
    }
    location = /_warehouse_WRITE {
    internal;
    set $api_name "Warehouse";

    auth_jwt $api_name;
    auth_jwt_key_file /etc/nginx/jwk.json;
    if ($jwt_claim_admin != "true") { # Write operations must have "admin":true
    return 403; # Forbidden
    }

    proxy_pass http://$upstream$request_uri;
    }

    # vim: syntax=nginx