Advanced API security for Kubernetes containers running in AWS - NGINX App Protect per-service deployment through a CI/CD pipeline

Introduction

When the design objective for Kubernetes security is the separate management of WAF security policies, the solution is NGINX App Protect deployed per-service. This article describes such a deployment, with NGINX App Protect augmenting AWS API Gateway to provide advanced security to API workloads, deployed through a CI/CD pipeline. The advantage of NGINX App Protect deployed per-service in a Kubernetes environment is the separation of security policies between different services, allowing for better customisation of the policies and easier portability to different environments.

In this particular instance, I used a demo application, Arcadia Finance, that has a Web interface and also exposes an API allowing the users to make financial transactions. The API is described in an OpenAPI 3.0 file, allowing for the automated building of the positive security policy elements (allow list elements) whereas in the case of the web security policy, this configuration will be done manually.

The difference in configuration methods between the API and Web policies and the additional requirement for policy separation and independent portability between environments prompted the usage of two separate NGINX App Protect instance, each securing their respective service (Web and API).

The deployment used AWS EKS as Kubernetes environment where, beside the Arcadia Finance application components and NGINX App Protect instances, there is also a Fluentd deployment configured as a Syslog server for security logs sent by the NGINX App Protect instances. The logs are then being sent to AWS Elasticsearch and displayed via Kibana NGINX App Protect dashboards.

Access to EKS cluster is being provided by an NGINX Ingress Controller instance. The Web interface is being exposed externally through an AWS Application LoadBalancer, handling the SSL offloading while the API is exposed through a Network LoadBalancer. The API is published externally through AWS API Gateway, providing basic security, using a VPC link to connect to the Network LoadBalancer.

The configuration

The configuration (Arcadia Finance deployment, NGINX KIC, NGINX App Protect configuration, OpenAPI file) is being stored in AWS CodeComit and deployed through AWS CodePipeline and AWS CodeBuild.

The API Gateway configuration is being described in an OpenAPI file annotated for AWS API Gateway-specific elements:

{
  "openapi" : "3.0.1",
  "info" : {
    "title" : "API Arcadia Finance",
    "description" : "Arcadia OpenAPI",
    "version" : "1.0.0-oas3"
  },
  "servers" : [ {
    "url" : "https://api.cloud-app.uk"
  } ],
  "paths" : {
          "/api/rest/execute_money_transfer.php" : {
       "post" : {
         "requestBody" : {
           "content" : {
             "application/json" : {
               "schema" : {
                 "$ref" : "#/components/schemas/MODEL9e8bc4"
               }
             }
           },
           "required" : true
         },
         "responses" : {
           "200" : {
             "description" : "200 response",
             "content" : { }
           }
         },
         "x-amazon-apigateway-request-validator": "Validate body, query string parameters, and headers",
         "x-amazon-apigateway-gateway-responses": {
             "BAD_REQUEST_BODY": {
                 "responseTemplates": {
                     "application/json": "{\"message\": \"Bla Bla\"}"
                 }
             }
         },
         "x-amazon-apigateway-integration" : {
           "type" : "http_proxy",
           "uri" : "http://api.cloud-app.uk/api/rest/execute_money_transfer.php",
           "responses" : {
             "default" : {
               "statusCode" : "200"
             }
           },
           "passthroughBehavior" : "when_no_match",
           "connectionType" : "VPC_LINK",
           "connectionId" : "emda4d",
           "httpMethod" : "POST"
         }
       }
     },
    "/trading/transactions.php" : {
      "get" : {
        "responses" : {
          "200" : {
            "description" : "200 response",
            "content" : { }
          }
        },
        "x-amazon-apigateway-request-validator": "Validate body, query string parameters, and headers",
        "x-amazon-apigateway-gateway-responses": {
            "BAD_REQUEST_BODY": {
                "responseTemplates": {
                    "application/json": "{\"message\": \"$context.error.validationErrorString\"}"
                }
            }
        },    
        "x-amazon-apigateway-integration" : {
          "type" : "http_proxy",
          "uri" : "http://www.cloud-app.uk/trading/transactions.php",
          "responses" : {
            "default" : {
              "statusCode" : "200"
            }
          },
          "passthroughBehavior" : "when_no_match",
          "connectionType" : "VPC_LINK",
          "connectionId" : "emda4d",
          "httpMethod" : "GET"
        }
      }
    },
    "/trading/rest/sell_stocks.php" : {
      "post" : {
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/MODEL1ed7ad"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "description" : "200 response",
            "content" : { }
          }
        },
        "x-amazon-apigateway-request-validator": "Validate body, query string parameters, and headers",
        "x-amazon-apigateway-gateway-responses": {
            "BAD_REQUEST_BODY": {
                "responseTemplates": {
                    "application/json": "{\"message\": \"$context.error.validationErrorString\"}"
                }
            }
        },
        "x-amazon-apigateway-integration" : {
          "type" : "http_proxy",
          "uri" : "http://api.cloud-app.uk/trading/rest/sell_stocks.php",
          "responses" : {
            "default" : {
              "statusCode" : "200"
            }
          },
          "passthroughBehavior" : "when_no_match",
          "connectionType" : "VPC_LINK",
          "connectionId" : "emda4d",
          "httpMethod" : "POST"
        }
      }
    },
    "/trading/rest/buy_stocks.php" : {
      "post" : {
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/MODEL94f81c"
              }
            }
          },
          "required" : true
        },
        "responses" : {
          "200" : {
            "description" : "200 response",
            "content" : { }
          }
        },
        "x-amazon-apigateway-request-validator": "Validate body, query string parameters, and headers",
        "x-amazon-apigateway-gateway-responses": {
            "BAD_REQUEST_BODY": {
                "responseTemplates": {
                    "application/json": "{\"message\": \"$context.error.validationErrorString\"}"
                }
            }
        },
        "x-amazon-apigateway-integration" : {
          "type" : "http_proxy",
          "uri" : "http://api.cloud-app.uk/trading/rest/buy_stocks.php",
          "responses" : {
            "default" : {
              "statusCode" : "200"
            }
          },
          "passthroughBehavior" : "when_no_match",
          "connectionType" : "VPC_LINK",
          "connectionId" : "emda4d",
          "httpMethod" : "POST"
        }
      }
    }
  },
  "components" : {
    "schemas" : {
      "MODEL94f81c" : {
        "required" : [ "action", "company", "qty", "stock_price", "trans_value" ],
        "type" : "object",
        "properties" : {
          "trans_value" : {
            "minimum" : 0,
            "type" : "number"
          },
          "qty" : {
            "minimum" : 0,
            "type" : "integer",
            "format" : "int32"
          },
          "company" : {
            "type" : "string"
          },
          "action" : {
            "type" : "string",
            "enum" : [ "buy" ]
          },
          "stock_price" : {
            "minimum" : 0,
            "type" : "number"
          }
        },
        "additionalProperties" : false
      },
      "MODEL1ed7ad" : {
        "required" : [ "action", "company", "qty", "stock_price", "trans_value" ],
        "type" : "object",
        "properties" : {
          "trans_value" : {
            "minimum" : 0,
            "type" : "number"
          },
          "qty" : {
            "minimum" : 0,
            "type" : "integer",
            "format" : "int32"
          },
          "company" : {
            "type" : "string"
          },
          "action" : {
            "type" : "string",
            "enum" : [ "sell" ]
          },
          "stock_price" : {
            "minimum" : 0,
            "type" : "number"
          }
        },
        "additionalProperties" : false
      },
      "MODEL9e8bc4" : {
        "required" : [ "account", "amount", "currency", "friend" ],
        "type" : "object",
        "properties" : {
          "amount" : {
            "minimum" : 0,
            "type" : "number"
          },
          "account" : {
            "type" : "number"
          },
          "currency" : {
            "type" : "string"
          },
          "friend" : {
            "type" : "string"
          }
        },
        "additionalProperties" : false
      }
    }
  },
  "x-amazon-apigateway-policy" : {
    "Version" : "2012-10-17",
    "Statement" : [ {
      "Effect" : "Allow",
      "Principal" : "*",
      "Action" : "execute-api:Invoke",
      "Resource" : "arn:aws:execute-api:us-west-2:856265587682:7g8sbh9zs6/*"
    } ]
  },
  "x-amazon-apigateway-request-validators": {
    "Validate body, query string parameters, and headers": {
      "validateRequestParameters": true,
      "validateRequestBody": true
    }
  }
}


The Ingress objects controlled by NGINX KIC are responsible for steering the traffic to either the Web or API instances of NGINX App Protect:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
  name: arcadia-nginx-kic
  namespace: default
spec:
  rules:
  - host: "*.cloud-app.uk"
    http:
      paths:
      - backend:
          serviceName: api-nap
          servicePort: 80
        path: /api/rest/execute_money_transfer.php
      - backend:
          serviceName: api-nap
          servicePort: 80
        path: /trading/rest/buy_stocks.php
      - backend:
          serviceName: api-nap
          servicePort: 80
        path: /trading/rest/sell_stocks.php
      - backend:
          serviceName: web-nap
          servicePort: 80
        path: /trading/transactions.php
      - backend:
          serviceName: web-nap
          servicePort: 80
        path: /
      - backend:
          serviceName: web-nap
          servicePort: 80
        path: /files
      - backend:
          serviceName: web-nap
          servicePort: 80
        path: /api
      - backend:
          serviceName: web-nap
          servicePort: 80
        path: /app3

The NGINX App Protect configuration is also controlled by AWS CodePipeline, deployed as a ConfigMap and mounted as a volume on the NGINX instance:

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-conf-map-api
  namespace: default
data:
  nginx.conf: |+
    user nginx;

    worker_processes auto;
    load_module modules/ngx_http_app_protect_module.so;

    error_log /var/log/nginx/error.log debug;

    events {
        worker_connections 10240;
    }

    http {
        include /etc/nginx/mime.types;
        default_type application/octet-stream;
        sendfile on;
        keepalive_timeout 65;

        upstream main_DNS_name {
            server main;
        }
        upstream app2_DNS_name {
            server app2;
        }
        server {
            listen 80;
            server_name *.cloud-app.uk;
            proxy_http_version 1.1;

            app_protect_enable on;
            app_protect_policy_file "/etc/nginx/NAP_API_Policy.json";
            app_protect_security_log_enable on;
            app_protect_security_log "/etc/nginx/custom_log_format.json" syslog:server=fluentd.logging.svc.cluster.local:24224;

            location /trading {
                client_max_body_size 0;
                default_type text/html;
                # set your backend here
                proxy_pass http://main_DNS_name;
                proxy_set_header Host $host;
            }

            location /api {
                client_max_body_size 0;
                default_type text/html;
                # set your backend here
                proxy_pass http://app2_DNS_name;
                proxy_set_header Host $host;
            }
        }
}

 

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-nap
  labels:
    app: api-nap
spec:
  selector:
    matchLabels:
      app: api-nap
  replicas: 1
  template:
    metadata:
      labels:
        app: api-nap
    spec:
      containers:
      - name: api-nap
        image: 856265587682.dkr.ecr.us-west-2.amazonaws.com/per-service-nginx-app-protect:latest
        imagePullPolicy: IfNotPresent
        ports:
          - containerPort: 80
        volumeMounts:
        - name: nginx-conf-map-api-volume
          mountPath: "/etc/nginx/nginx.conf"
          subPath: "nginx.conf"
          readOnly: true
        - name: nap-api-policy-volume
          mountPath: "/etc/nginx/NAP_API_Policy.json"
          subPath: "NAP_API_Policy.json"
          readOnly: true
      volumes:
        - name: nginx-conf-map-api-volume
          configMap:
            name: nginx-conf-map-api
        - name: nap-api-policy-volume
          configMap:
            name: nap-api-policy

In case of API NGINX App Protect configuration, there is a reference to the OpenAPI file placed by the CI/CD pipeline in an S3 bucket:

apiVersion: v1
kind: ConfigMap
metadata:
  name: nap-api-policy
  namespace: default
data:
  NAP_API_Policy.json: |+
    {
        "policy": {
            "name": "policy_name",
            "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
            "applicationLanguage": "utf-8",
            "enforcementMode": "blocking",
            "signature-sets": [
                {
                    "name": "High Accuracy Signatures",
                    "block": true,
                    "alarm": true
                }
            ],
            "bot-defense": {
                "settings": {
                    "isEnabled": true
                },
                "mitigations": {
                    "classes": [
                        {
                            "name": "trusted-bot",
                            "action": "alarm"
                        },
                        {
                            "name": "untrusted-bot",
                            "action": "block"
                        },
                        {
                            "name": "malicious-bot",
                            "action": "block"
                        }
                    ]
                }
            },
            "open-api-files": [
                {
                    "link": "https://per-service-nginx-app-protect.s3.us-west-2.amazonaws.com/arcadia-openapi3-aws.json"
                }            
            ],
           "blocking-settings": {
                "violations": [
                    {
                        "name": "VIOL_JSON_FORMAT",
                        "alarm": true,
                        "block": true
                    },
                    {
                        "name": "VIOL_PARAMETER_VALUE_METACHAR",
                        "alarm": false,
                        "block": false
                    },
                    {
                        "name": "VIOL_HTTP_PROTOCOL",
                        "alarm": true,
                        "block": true
                    },
                    {
                        "name": "VIOL_EVASION",
                        "alarm": true,
                        "block": true
                    },
                    {
                        "name": "VIOL_FILETYPE",
                        "alarm": true,
                        "block": true
                    },
                    {
                        "name": "VIOL_METHOD",
                        "alarm": true,
                        "block": true
                    },
                    {
                        "block": true,
                        "description": "Disallowed file upload content detected in body",
                        "name": "VIOL_FILE_UPLOAD_IN_BODY"
                    },
                    {
                        "block": true,
                        "description": "Mandatory request body is missing",
                        "name": "VIOL_MANDATORY_REQUEST_BODY"
                    },
                    {
                        "block": true,
                        "description": "Illegal parameter location",
                        "name": "VIOL_PARAMETER_LOCATION"
                    },
                    {
                        "block": true,
                        "description": "Mandatory parameter is missing",
                        "name": "VIOL_MANDATORY_PARAMETER"
                    },
                    {
                        "block": true,
                        "description": "JSON data does not comply with JSON schema",
                        "name": "VIOL_JSON_SCHEMA"
                    },
                    {
                        "block": true,
                        "description": "Illegal parameter array value",
                        "name": "VIOL_PARAMETER_ARRAY_VALUE"
                    },
                    {
                        "block": true,
                        "description": "Illegal Base64 value",
                        "name": "VIOL_PARAMETER_VALUE_BASE64"
                    },
                    {
                        "block": true,
                        "description": "Disallowed file upload content detected",
                        "name": "VIOL_FILE_UPLOAD"
                    },
                    {
                        "block": true,
                        "description": "Illegal request content type",
                        "name": "VIOL_URL_CONTENT_TYPE"
                    },
                    {
                        "block": true,
                        "description": "Illegal static parameter value",
                        "name": "VIOL_PARAMETER_STATIC_VALUE"
                    },
                    {
                        "block": true,
                        "description": "Illegal parameter value length",
                        "name": "VIOL_PARAMETER_VALUE_LENGTH"
                    },
                    {
                        "block": true,
                        "description": "Illegal parameter data type",
                        "name": "VIOL_PARAMETER_DATA_TYPE"
                    },
                    {
                        "block": true,
                        "description": "Illegal parameter numeric value",
                        "name": "VIOL_PARAMETER_NUMERIC_VALUE"
                    },
                    {
                        "block": true,
                        "description": "Parameter value does not comply with regular expression",
                        "name": "VIOL_PARAMETER_VALUE_REGEXP"
                    },
                    {
                        "block": true,
                        "description": "Illegal URL",
                        "name": "VIOL_URL"
                    },
                    {
                        "block": true,
                        "description": "Illegal parameter",
                        "name": "VIOL_PARAMETER"
                    },
                    {
                        "block": true,
                        "description": "Illegal empty parameter value",
                        "name": "VIOL_PARAMETER_EMPTY_VALUE"
                    },
                    {
                        "block": true,
                        "description": "Illegal repeated parameter name",
                        "name": "VIOL_PARAMETER_REPEATED"
                    }
                ],
                "http-protocols": [
                    {
                        "description": "Header name with no header value",
                        "enabled": true
                    },
                    {
                        "description": "Chunked request with Content-Length header",
                        "enabled": true
                    },
                    {
                        "description": "Check maximum number of parameters",
                        "enabled": true,
                        "maxParams": 5
                    },
                    {
                        "description": "Check maximum number of headers",
                        "enabled": true,
                        "maxHeaders": 30
                    },
                    {
                        "description": "Body in GET or HEAD requests",
                        "enabled": true
                    },
                    {
                        "description": "Bad multipart/form-data request parsing",
                        "enabled": true
                    },
                    {
                        "description": "Bad multipart parameters parsing",
                        "enabled": true
                    },
                    {
                        "description": "Unescaped space in URL",
                        "enabled": true
                    }
                ],
                "evasions": [
                    {
                        "description": "Bad unescape",
                        "enabled": true
                    },
                    {
                        "description": "Directory traversals",
                        "enabled": true
                    },
                    {
                        "description": "Bare byte decoding",
                        "enabled": true
                    },
                    {
                        "description": "Apache whitespace",
                        "enabled": true
                    },
                    {
                        "description": "Multiple decoding",
                        "enabled": true,
                        "maxDecodingPasses": 2
                    },
                    {
                        "description": "IIS Unicode codepoints",
                        "enabled": true
                    },
                    {
                        "description": "%u decoding",
                        "enabled": true
                    }
                ]
            },
            "methodReference": {
                "link": "https://per-service-nginx-app-protect.s3.us-west-2.amazonaws.com/methods.txt"
            },
            "filetypeReference": {
                "link": "https://per-service-nginx-app-protect.s3.us-west-2.amazonaws.com/filetypes.txt"
            }
        }
    }

In this case, the same OpenAPI file is pushed to both AWS API Gateway and, through the S3 bucket, to the NGINX App Protect API instance.

NGINX App Protect augmenting the security provided by AWS API Gateway

The NGINX App Protect API instance enhances the security posture of API Gateway by providing negative security (attack signature matching) and advanced security like bot detection. To demonstrate this functionality, a SQLi attack is simulated against the API.

This valid API call sent by Postman is successfully completed:

A similar call that contains an attack pattern (SQL injection) is being blocked by the NGINX App Protect instance:

To demonstrate the bot detection capability, the same valid call sent before is now sent from Curl (as opposed to Postman used earlier), now matching an untrusted bot signature and being blocked:

curl -vvvk https://api.cloud-app.uk/api/rest/execute_money_transfer.php -d '{"account": 2075894, "amount": 1, "currency": "GBP", "friend": "Vincent"}' -H "Content-Type: application/json" -X POST
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying 143.204.170.103...
* TCP_NODELAY set
* Connected to api.cloud-app.uk (143.204.170.103) port 443 (#0)
* WARNING: disabling hostname validation also disables SNI.
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate: *.cloudfront.net
* Server certificate: DigiCert Global CA G2
* Server certificate: DigiCert Global Root G2
> POST /api/rest/execute_money_transfer.php HTTP/1.1
> Host: api.cloud-app.uk
> User-Agent: curl/7.54.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 73
>
* upload completely sent off: 73 out of 73 bytes
< HTTP/1.1 403 Forbidden
< Content-Type: application/json; charset=utf-8
< Content-Length: 37
< Connection: keep-alive
< Date: Sat, 28 Nov 2020 20:59:01 GMT
< x-amzn-RequestId: 213ca523-173b-42a9-ab41-e3420602bef9
< x-amzn-Remapped-Content-Length: 37
< x-amzn-Remapped-Connection: keep-alive
< x-amz-apigw-id: WvIDaFu0PHcFZOg=
< Cache-Control: no-cache
< x-amzn-Remapped-Server: nginx/1.19.3
< Pragma: no-cache
< x-amzn-Remapped-Date: Sat, 28 Nov 2020 20:59:01 GMT
< X-Cache: Error from cloudfront
< Via: 1.1 9a0d5427f47351631cdee4d5e38248d8.cloudfront.net (CloudFront)
< X-Amz-Cf-Pop: LHR50-C1
< X-Amz-Cf-Id: _VYxM43hCyrzj5hJNitbxLkzjww7iygpoWXT7sege-5eySEaKmcRxQ==
<
{"supportID": "4099392564272510395"}
* Connection #0 to host api.cloud-app.uk left intact

This can be checked in the NGINX App Protect security logs displayed in Kibana NGINX App Protect dashboards, running in AWS ElasticSearch:

The bot defense behavior can be controlled from the policy file under the CodeCommit repository. Changing the action from "block" to "alarm" for "untrusted bot" and commiting the change will trigger the pipeline to redeploy the NGINX App Protect policy:

apiVersion: v1
kind: ConfigMap
metadata:
  name: nap-api-policy
  namespace: default
data:
  NAP_API_Policy.json: |+
    {
        "policy": {
            "name": "policy_name",
            "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" },
            "applicationLanguage": "utf-8",
            "enforcementMode": "blocking",
            "signature-sets": [
                {
                    "name": "High Accuracy Signatures",
                    "block": true,
                    "alarm": true
                }
            ],
            "bot-defense": {
                "settings": {
                    "isEnabled": true
                },
                "mitigations": {
                    "classes": [
                        {
                            "name": "trusted-bot",
                            "action": "alarm"
                        },
                        {
                            "name": "untrusted-bot",
                            "action": "block"
                        },
                        {
                            "name": "malicious-bot",
                            "action": "block"
                        }
                    ]
                }
            },
...............................................................................................................

The same Curl call is now being allowed:

curl -vvvk https://api.cloud-app.uk/api/rest/execute_money_transfer.php -d '{"account": 2075894, "amount": 1, "currency": "GBP", "friend": "Vincent"}' -H "Content-Type: application/json" -X POST
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying 143.204.192.29...
* TCP_NODELAY set
* Connected to api.cloud-app.uk (143.204.192.29) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/cert.pem
  CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=*.cloud-app.uk
*  start date: Nov 18 00:00:00 2020 GMT
*  expire date: Dec 17 23:59:59 2021 GMT
*  issuer: C=US; O=Amazon; OU=Server CA 1B; CN=Amazon
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x7fc877008200)
> POST /api/rest/execute_money_transfer.php HTTP/2
> Host: api.cloud-app.uk
> User-Agent: curl/7.64.1
> Accept: */*
> Content-Type: application/json
> Content-Length: 75
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
* We are completely uploaded and fine
< HTTP/2 200
< content-type: text/html; charset=UTF-8
< content-length: 155
< date: Mon, 30 Nov 2020 11:02:19 GMT
< x-amzn-requestid: 9bdb2379-06c4-4970-a528-cd8de9cb75b3
< x-amzn-remapped-content-length: 155
< x-amzn-remapped-connection: keep-alive
< x-amz-apigw-id: W0WhMH_TvHcFndQ=
< x-amzn-remapped-server: nginx/1.19.3
< vary: Accept-Encoding
< x-amzn-remapped-date: Mon, 30 Nov 2020 11:02:19 GMT
< x-cache: Miss from cloudfront
< via: 1.1 bb501579906725a97059c817430425cf.cloudfront.net (CloudFront)
< x-amz-cf-pop: LHR3-C1
< x-amz-cf-id: xo4zfKVqUeejkHzLPArADi1rxRxTJkg61YgfhruAR4KjdpMSnYymkQ==
<
* Connection #0 to host api.cloud-app.uk left intact
{"name":"Vincent", "status":"success","amount":"1", "currency":"GBP", "transid":"753910682", "msg":"The money transfer has been successfully completed "}* Closing connection 0

The new bot defense behavior can be checked in the NGINX App Protect Kibana dashboard:

Conclusion

To recap, this article has demoed the per-service model of deployment for NGINX App Protect in Kubernetes environment. The main advantage of this deployment model is the independent management of security policies and the portability of each security policy.

NGINX App Protect elevates the security level provided by the API Gateway by providing negative security and advanced security features like bot detection.

The configuration is being controlled by a CI/CD pipeline, in this case AWS CodePipeline, and the same OpenAPI file used to configure the AWS API Gateway is also ingested by the NGINX App Protect API instance.

Lastly the security logs sent by NGINX App Protect through Fluentd to AWS ElasticSearch are being displayed in Kibana dashboards.

Published Jan 15, 2021
Version 1.0
No CommentsBe the first to comment
"}},"componentScriptGroups({\"componentId\":\"custom.widget.Beta_MetaNav\"})":{"__typename":"ComponentScriptGroups","scriptGroups":{"__typename":"ComponentScriptGroupsDefinition","afterInteractive":{"__typename":"PageScriptGroupDefinition","group":"AFTER_INTERACTIVE","scriptIds":[]},"lazyOnLoad":{"__typename":"PageScriptGroupDefinition","group":"LAZY_ON_LOAD","scriptIds":[]}},"componentScripts":[]},"component({\"componentId\":\"custom.widget.Beta_Footer\"})":{"__typename":"Component","render({\"context\":{\"component\":{\"entities\":[],\"props\":{}},\"page\":{\"entities\":[\"board:TechnicalArticles\",\"message:289036\"],\"name\":\"TkbMessagePage\",\"props\":{},\"url\":\"https://community.f5.com/kb/technicalarticles/advanced-api-security-for-kubernetes-containers-running-in-aws---nginx-app-prote/289036\"}}})":{"__typename":"ComponentRenderResult","html":"
 
 
 
 
 

\"F5 ©2024 F5, Inc. All rights reserved.
Trademarks Policies Privacy California Privacy Do Not Sell My Personal Information
"}},"componentScriptGroups({\"componentId\":\"custom.widget.Beta_Footer\"})":{"__typename":"ComponentScriptGroups","scriptGroups":{"__typename":"ComponentScriptGroupsDefinition","afterInteractive":{"__typename":"PageScriptGroupDefinition","group":"AFTER_INTERACTIVE","scriptIds":[]},"lazyOnLoad":{"__typename":"PageScriptGroupDefinition","group":"LAZY_ON_LOAD","scriptIds":[]}},"componentScripts":[]},"component({\"componentId\":\"custom.widget.Tag_Manager_Helper\"})":{"__typename":"Component","render({\"context\":{\"component\":{\"entities\":[],\"props\":{}},\"page\":{\"entities\":[\"board:TechnicalArticles\",\"message:289036\"],\"name\":\"TkbMessagePage\",\"props\":{},\"url\":\"https://community.f5.com/kb/technicalarticles/advanced-api-security-for-kubernetes-containers-running-in-aws---nginx-app-prote/289036\"}}})":{"__typename":"ComponentRenderResult","html":" "}},"componentScriptGroups({\"componentId\":\"custom.widget.Tag_Manager_Helper\"})":{"__typename":"ComponentScriptGroups","scriptGroups":{"__typename":"ComponentScriptGroupsDefinition","afterInteractive":{"__typename":"PageScriptGroupDefinition","group":"AFTER_INTERACTIVE","scriptIds":[]},"lazyOnLoad":{"__typename":"PageScriptGroupDefinition","group":"LAZY_ON_LOAD","scriptIds":[]}},"componentScripts":[]},"component({\"componentId\":\"custom.widget.Consent_Blackbar\"})":{"__typename":"Component","render({\"context\":{\"component\":{\"entities\":[],\"props\":{}},\"page\":{\"entities\":[\"board:TechnicalArticles\",\"message:289036\"],\"name\":\"TkbMessagePage\",\"props\":{},\"url\":\"https://community.f5.com/kb/technicalarticles/advanced-api-security-for-kubernetes-containers-running-in-aws---nginx-app-prote/289036\"}}})":{"__typename":"ComponentRenderResult","html":"
"}},"componentScriptGroups({\"componentId\":\"custom.widget.Consent_Blackbar\"})":{"__typename":"ComponentScriptGroups","scriptGroups":{"__typename":"ComponentScriptGroupsDefinition","afterInteractive":{"__typename":"PageScriptGroupDefinition","group":"AFTER_INTERACTIVE","scriptIds":[]},"lazyOnLoad":{"__typename":"PageScriptGroupDefinition","group":"LAZY_ON_LOAD","scriptIds":[]}},"componentScripts":[]},"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/common/QueryHandler\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/common/QueryHandler-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"components/community/NavbarDropdownToggle\"]})":[{"__ref":"CachedAsset:text:en_US-components/community/NavbarDropdownToggle-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageView/MessageViewStandard\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageView/MessageViewStandard-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/ThreadedReplyList\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/ThreadedReplyList-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageReplyCallToAction\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageReplyCallToAction-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageSubject\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageSubject-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageBody\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageBody-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageCustomFields\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageCustomFields-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageRevision\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageRevision-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageReplyButton\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageReplyButton-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageAuthorBio\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageAuthorBio-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"components/guides/GuideBottomNavigation\"]})":[{"__ref":"CachedAsset:text:en_US-components/guides/GuideBottomNavigation-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"components/customComponent/CustomComponent\"]})":[{"__ref":"CachedAsset:text:en_US-components/customComponent/CustomComponent-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"components/users/UserLink\"]})":[{"__ref":"CachedAsset:text:en_US-components/users/UserLink-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/users/UserRank\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/users/UserRank-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"components/users/UserRegistrationDate\"]})":[{"__ref":"CachedAsset:text:en_US-components/users/UserRegistrationDate-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"components/tags/TagView/TagViewChip\"]})":[{"__ref":"CachedAsset:text:en_US-components/tags/TagView/TagViewChip-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/users/UserAvatar\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/users/UserAvatar-1740415735000"}],"cachedText({\"lastModified\":\"1740415735000\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/ranks/UserRankLabel\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/ranks/UserRankLabel-1740415735000"}]},"CachedAsset:pages-1741994701844":{"__typename":"CachedAsset","id":"pages-1741994701844","value":[{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"HowDoI.GetInvolved.MvpProgram","type":"COMMUNITY","urlPath":"/c/how-do-i/get-involved/mvp-program","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"BlogViewAllPostsPage","type":"BLOG","urlPath":"/category/:categoryId/blog/:boardId/all-posts/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"CasePortalPage","type":"CASE_PORTAL","urlPath":"/caseportal","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"CreateGroupHubPage","type":"GROUP_HUB","urlPath":"/groups/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"CaseViewPage","type":"CASE_DETAILS","urlPath":"/case/:caseId/:caseNumber","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"InboxPage","type":"COMMUNITY","urlPath":"/inbox","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"HowDoI.GetInvolved.AdvocacyProgram","type":"COMMUNITY","urlPath":"/c/how-do-i/get-involved/advocacy-program","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"HowDoI.GetHelp.NonCustomer","type":"COMMUNITY","urlPath":"/c/how-do-i/get-help/non-customer","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"HelpFAQPage","type":"COMMUNITY","urlPath":"/help","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"HowDoI.GetHelp.F5Customer","type":"COMMUNITY","urlPath":"/c/how-do-i/get-help/f5-customer","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"IdeaMessagePage","type":"IDEA_POST","urlPath":"/idea/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"IdeaViewAllIdeasPage","type":"IDEA","urlPath":"/category/:categoryId/ideas/:boardId/all-ideas/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"LoginPage","type":"USER","urlPath":"/signin","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"BlogPostPage","type":"BLOG","urlPath":"/category/:categoryId/blogs/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"HowDoI.GetInvolved","type":"COMMUNITY","urlPath":"/c/how-do-i/get-involved","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"HowDoI.Learn","type":"COMMUNITY","urlPath":"/c/how-do-i/learn","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1739501733000,"localOverride":null,"page":{"id":"Test","type":"CUSTOM","urlPath":"/custom-test-2","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"ThemeEditorPage","type":"COMMUNITY","urlPath":"/designer/themes","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"TkbViewAllArticlesPage","type":"TKB","urlPath":"/category/:categoryId/kb/:boardId/all-articles/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"OccasionEditPage","type":"EVENT","urlPath":"/event/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"OAuthAuthorizationAllowPage","type":"USER","urlPath":"/auth/authorize/allow","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"PageEditorPage","type":"COMMUNITY","urlPath":"/designer/pages","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"PostPage","type":"COMMUNITY","urlPath":"/category/:categoryId/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"ForumBoardPage","type":"FORUM","urlPath":"/category/:categoryId/discussions/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"TkbBoardPage","type":"TKB","urlPath":"/category/:categoryId/kb/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"EventPostPage","type":"EVENT","urlPath":"/category/:categoryId/events/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"UserBadgesPage","type":"COMMUNITY","urlPath":"/users/:login/:userId/badges","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"GroupHubMembershipAction","type":"GROUP_HUB","urlPath":"/membership/join/:nodeId/:membershipType","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"MaintenancePage","type":"COMMUNITY","urlPath":"/maintenance","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"IdeaReplyPage","type":"IDEA_REPLY","urlPath":"/idea/:boardId/:messageSubject/:messageId/comments/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"UserSettingsPage","type":"USER","urlPath":"/mysettings/:userSettingsTab","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"GroupHubsPage","type":"GROUP_HUB","urlPath":"/groups","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"ForumPostPage","type":"FORUM","urlPath":"/category/:categoryId/discussions/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"OccasionRsvpActionPage","type":"OCCASION","urlPath":"/event/:boardId/:messageSubject/:messageId/rsvp/:responseType","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"VerifyUserEmailPage","type":"USER","urlPath":"/verifyemail/:userId/:verifyEmailToken","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"AllOccasionsPage","type":"OCCASION","urlPath":"/category/:categoryId/events/:boardId/all-events/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"EventBoardPage","type":"EVENT","urlPath":"/category/:categoryId/events/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"TkbReplyPage","type":"TKB_REPLY","urlPath":"/kb/:boardId/:messageSubject/:messageId/comments/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"IdeaBoardPage","type":"IDEA","urlPath":"/category/:categoryId/ideas/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"CommunityGuideLinesPage","type":"COMMUNITY","urlPath":"/communityguidelines","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"CaseCreatePage","type":"SALESFORCE_CASE_CREATION","urlPath":"/caseportal/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"TkbEditPage","type":"TKB","urlPath":"/kb/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"ForgotPasswordPage","type":"USER","urlPath":"/forgotpassword","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"IdeaEditPage","type":"IDEA","urlPath":"/idea/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"TagPage","type":"COMMUNITY","urlPath":"/tag/:tagName","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"BlogBoardPage","type":"BLOG","urlPath":"/category/:categoryId/blog/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"OccasionMessagePage","type":"OCCASION_TOPIC","urlPath":"/event/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"ManageContentPage","type":"COMMUNITY","urlPath":"/managecontent","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"ClosedMembershipNodeNonMembersPage","type":"GROUP_HUB","urlPath":"/closedgroup/:groupHubId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"HowDoI.GetHelp.Community","type":"COMMUNITY","urlPath":"/c/how-do-i/get-help/community","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"CommunityPage","type":"COMMUNITY","urlPath":"/","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"HowDoI.GetInvolved.ContributeCode","type":"COMMUNITY","urlPath":"/c/how-do-i/get-involved/contribute-code","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"ForumMessagePage","type":"FORUM_TOPIC","urlPath":"/discussions/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"IdeaPostPage","type":"IDEA","urlPath":"/category/:categoryId/ideas/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"BlogMessagePage","type":"BLOG_ARTICLE","urlPath":"/blog/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"RegistrationPage","type":"USER","urlPath":"/register","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"EditGroupHubPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"ForumEditPage","type":"FORUM","urlPath":"/discussions/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"ResetPasswordPage","type":"USER","urlPath":"/resetpassword/:userId/:resetPasswordToken","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"TkbMessagePage","type":"TKB_ARTICLE","urlPath":"/kb/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"HowDoI.Learn.AboutIrules","type":"COMMUNITY","urlPath":"/c/how-do-i/learn/about-irules","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"BlogEditPage","type":"BLOG","urlPath":"/blog/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"HowDoI.GetHelp.F5Support","type":"COMMUNITY","urlPath":"/c/how-do-i/get-help/f5-support","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"ManageUsersPage","type":"USER","urlPath":"/users/manage/:tab?/:manageUsersTab?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"ForumReplyPage","type":"FORUM_REPLY","urlPath":"/discussions/:boardId/:messageSubject/:messageId/replies/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"PrivacyPolicyPage","type":"COMMUNITY","urlPath":"/privacypolicy","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"NotificationPage","type":"COMMUNITY","urlPath":"/notifications","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"UserPage","type":"USER","urlPath":"/users/:login/:userId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"HealthCheckPage","type":"COMMUNITY","urlPath":"/health","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"OccasionReplyPage","type":"OCCASION_REPLY","urlPath":"/event/:boardId/:messageSubject/:messageId/comments/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"ManageMembersPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId/manage/:tab?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"SearchResultsPage","type":"COMMUNITY","urlPath":"/search","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"BlogReplyPage","type":"BLOG_REPLY","urlPath":"/blog/:boardId/:messageSubject/:messageId/replies/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"GroupHubPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"TermsOfServicePage","type":"COMMUNITY","urlPath":"/termsofservice","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"HowDoI.GetHelp","type":"COMMUNITY","urlPath":"/c/how-do-i/get-help","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"HowDoI.GetHelp.SecurityIncident","type":"COMMUNITY","urlPath":"/c/how-do-i/get-help/security-incident","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"CategoryPage","type":"CATEGORY","urlPath":"/category/:categoryId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"ForumViewAllTopicsPage","type":"FORUM","urlPath":"/category/:categoryId/discussions/:boardId/all-topics/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"TkbPostPage","type":"TKB","urlPath":"/category/:categoryId/kbs/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"GroupHubPostPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1741994701844,"localOverride":null,"page":{"id":"HowDoI","type":"COMMUNITY","urlPath":"/c/how-do-i","__typename":"PageDescriptor"},"__typename":"PageResource"}],"localOverride":false},"CachedAsset:text:en_US-components/context/AppContext/AppContextProvider-0":{"__typename":"CachedAsset","id":"text:en_US-components/context/AppContext/AppContextProvider-0","value":{"noCommunity":"Cannot find community","noUser":"Cannot find current user","noNode":"Cannot find node with id {nodeId}","noMessage":"Cannot find message with id {messageId}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/Loading/LoadingDot-0":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/Loading/LoadingDot-0","value":{"title":"Loading..."},"localOverride":false},"User:user:-1":{"__typename":"User","id":"user:-1","uid":-1,"login":"Former Member","email":"","avatar":null,"rank":null,"kudosWeight":1,"registrationData":{"__typename":"RegistrationData","status":"ANONYMOUS","registrationTime":null,"confirmEmailStatus":false,"registrationAccessLevel":"VIEW","ssoRegistrationFields":[]},"ssoId":null,"profileSettings":{"__typename":"ProfileSettings","dateDisplayStyle":{"__typename":"InheritableStringSettingWithPossibleValues","key":"layout.friendly_dates_enabled","value":"false","localValue":"true","possibleValues":["true","false"]},"dateDisplayFormat":{"__typename":"InheritableStringSetting","key":"layout.format_pattern_date","value":"dd-MMM-yyyy","localValue":"MM-dd-yyyy"},"language":{"__typename":"InheritableStringSettingWithPossibleValues","key":"profile.language","value":"en-US","localValue":null,"possibleValues":["en-US"]}},"deleted":false},"Theme:customTheme1":{"__typename":"Theme","id":"customTheme1"},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bi0zNC0xM2k0MzE3N0Q2NjFBRDg5NDAy\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bi0zNC0xM2k0MzE3N0Q2NjFBRDg5NDAy","mimeType":"image/png"},"Category:category:Articles":{"__typename":"Category","id":"category:Articles","entityType":"CATEGORY","displayId":"Articles","nodeType":"category","depth":1,"title":"Articles","shortTitle":"Articles","parent":{"__ref":"Category:category:top"},"categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:top":{"__typename":"Category","id":"category:top","displayId":"top","nodeType":"category","depth":0,"title":"Top","entityType":"CATEGORY","shortTitle":"Top"},"Tkb:board:TechnicalArticles":{"__typename":"Tkb","id":"board:TechnicalArticles","entityType":"TKB","displayId":"TechnicalArticles","nodeType":"board","depth":2,"conversationStyle":"TKB","title":"Technical Articles","description":"F5 SMEs share good practice.","avatar":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bi0zNC0xM2k0MzE3N0Q2NjFBRDg5NDAy\"}"},"profileSettings":{"__typename":"ProfileSettings","language":null},"parent":{"__ref":"Category:category:Articles"},"ancestors":{"__typename":"CoreNodeConnection","edges":[{"__typename":"CoreNodeEdge","node":{"__ref":"Community:community:zihoc95639"}},{"__typename":"CoreNodeEdge","node":{"__ref":"Category:category:Articles"}}]},"userContext":{"__typename":"NodeUserContext","canAddAttachments":false,"canUpdateNode":false,"canPostMessages":false,"isSubscribed":false},"boardPolicies":{"__typename":"BoardPolicies","canPublishArticleOnCreate":{"__typename":"PolicyResult","failureReason":{"__typename":"FailureReason","message":"error.lithium.policies.forums.policy_can_publish_on_create_workflow_action.accessDenied","key":"error.lithium.policies.forums.policy_can_publish_on_create_workflow_action.accessDenied","args":[]}},"canReadNode":{"__typename":"PolicyResult","failureReason":null}},"shortTitle":"Technical Articles","isManualSortOrderAvailable":false,"tkbPolicies":{"__typename":"TkbPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"repliesProperties":{"__typename":"RepliesProperties","sortOrder":"PUBLISH_TIME","repliesFormat":"threaded"},"tagProperties":{"__typename":"TagNodeProperties","tagsEnabled":{"__typename":"PolicyResult","failureReason":null}},"requireTags":true,"tagType":"FREEFORM_AND_PRESET"},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/cmstMjgtQ3U0RXo2\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/cmstMjgtQ3U0RXo2","height":0,"width":0,"mimeType":"image/svg+xml"},"Rank:rank:28":{"__typename":"Rank","id":"rank:28","position":5,"name":"Employee","color":"C20025","icon":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/cmstMjgtQ3U0RXo2\"}"},"rankStyle":"OUTLINE"},"User:user:305638":{"__typename":"User","id":"user:305638","uid":305638,"login":"Valentin_Tobi","deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://community.f5.com/t5/s/zihoc95639/images/dS0zMDU2MzgtMjE5NThpMzEwNzRGNTRCM0ZCREU4Rg"},"rank":{"__ref":"Rank:rank:28"},"email":"","messagesCount":25,"biography":null,"topicsCount":24,"kudosReceivedCount":70,"kudosGivenCount":0,"kudosWeight":1,"registrationData":{"__typename":"RegistrationData","status":null,"registrationTime":"2019-09-02T03:28:28.000-07:00","confirmEmailStatus":null},"followersCount":null,"solutionsCount":0},"TkbTopicMessage:message:289036":{"__typename":"TkbTopicMessage","uid":289036,"subject":"Advanced API security for Kubernetes containers running in AWS - NGINX App Protect per-service deployment through a CI/CD pipeline","id":"message:289036","revisionNum":1,"repliesCount":0,"author":{"__ref":"User:user:305638"},"depth":0,"hasGivenKudo":false,"helpful":null,"board":{"__ref":"Tkb:board:TechnicalArticles"},"conversation":{"__ref":"Conversation:conversation:289036"},"messagePolicies":{"__typename":"MessagePolicies","canPublishArticleOnEdit":{"__typename":"PolicyResult","failureReason":{"__typename":"FailureReason","message":"error.lithium.policies.forums.policy_can_publish_on_edit_workflow_action.accessDenied","key":"error.lithium.policies.forums.policy_can_publish_on_edit_workflow_action.accessDenied","args":[]}},"canModerateSpamMessage":{"__typename":"PolicyResult","failureReason":{"__typename":"FailureReason","message":"error.lithium.policies.feature.moderation_spam.action.moderate_entity.allowed.accessDenied","key":"error.lithium.policies.feature.moderation_spam.action.moderate_entity.allowed.accessDenied","args":[]}}},"contentWorkflow":{"__typename":"ContentWorkflow","state":"PUBLISH","scheduledPublishTime":null,"scheduledTimezone":null,"userContext":{"__typename":"MessageWorkflowContext","canSubmitForReview":null,"canEdit":false,"canRecall":null,"canSubmitForPublication":null,"canReturnToAuthor":null,"canPublish":null,"canReturnToReview":null,"canSchedule":false},"shortScheduledTimezone":null},"readOnly":false,"editFrozen":false,"moderationData":{"__ref":"ModerationData:moderation_data:289036"},"teaser":"","body":"

Introduction

\n\n

When the design objective for Kubernetes security is the separate management of WAF security policies, the solution is NGINX App Protect deployed per-service. This article describes such a deployment, with NGINX App Protect augmenting AWS API Gateway to provide advanced security to API workloads, deployed through a CI/CD pipeline. The advantage of NGINX App Protect deployed per-service in a Kubernetes environment is the separation of security policies between different services, allowing for better customisation of the policies and easier portability to different environments.

\n\n

In this particular instance, I used a demo application, Arcadia Finance, that has a Web interface and also exposes an API allowing the users to make financial transactions. The API is described in an OpenAPI 3.0 file, allowing for the automated building of the positive security policy elements (allow list elements) whereas in the case of the web security policy, this configuration will be done manually.

\n\n

The difference in configuration methods between the API and Web policies and the additional requirement for policy separation and independent portability between environments prompted the usage of two separate NGINX App Protect instance, each securing their respective service (Web and API).

\n\n

The deployment used AWS EKS as Kubernetes environment where, beside the Arcadia Finance application components and NGINX App Protect instances, there is also a Fluentd deployment configured as a Syslog server for security logs sent by the NGINX App Protect instances. The logs are then being sent to AWS Elasticsearch and displayed via Kibana NGINX App Protect dashboards.

\n\n

Access to EKS cluster is being provided by an NGINX Ingress Controller instance. The Web interface is being exposed externally through an AWS Application LoadBalancer, handling the SSL offloading while the API is exposed through a Network LoadBalancer. The API is published externally through AWS API Gateway, providing basic security, using a VPC link to connect to the Network LoadBalancer.

\n\n

\n\n

The configuration

\n\n

The configuration (Arcadia Finance deployment, NGINX KIC, NGINX App Protect configuration, OpenAPI file) is being stored in AWS CodeComit and deployed through AWS CodePipeline and AWS CodeBuild.

\n\n

The API Gateway configuration is being described in an OpenAPI file annotated for AWS API Gateway-specific elements:

\n\n
\n{\n  \"openapi\" : \"3.0.1\",\n  \"info\" : {\n    \"title\" : \"API Arcadia Finance\",\n    \"description\" : \"Arcadia OpenAPI\",\n    \"version\" : \"1.0.0-oas3\"\n  },\n  \"servers\" : [ {\n    \"url\" : \"https://api.cloud-app.uk\"\n  } ],\n  \"paths\" : {\n          \"/api/rest/execute_money_transfer.php\" : {\n       \"post\" : {\n         \"requestBody\" : {\n           \"content\" : {\n             \"application/json\" : {\n               \"schema\" : {\n                 \"$ref\" : \"#/components/schemas/MODEL9e8bc4\"\n               }\n             }\n           },\n           \"required\" : true\n         },\n         \"responses\" : {\n           \"200\" : {\n             \"description\" : \"200 response\",\n             \"content\" : { }\n           }\n         },\n         \"x-amazon-apigateway-request-validator\": \"Validate body, query string parameters, and headers\",\n         \"x-amazon-apigateway-gateway-responses\": {\n             \"BAD_REQUEST_BODY\": {\n                 \"responseTemplates\": {\n                     \"application/json\": \"{\\\"message\\\": \\\"Bla Bla\\\"}\"\n                 }\n             }\n         },\n         \"x-amazon-apigateway-integration\" : {\n           \"type\" : \"http_proxy\",\n           \"uri\" : \"http://api.cloud-app.uk/api/rest/execute_money_transfer.php\",\n           \"responses\" : {\n             \"default\" : {\n               \"statusCode\" : \"200\"\n             }\n           },\n           \"passthroughBehavior\" : \"when_no_match\",\n           \"connectionType\" : \"VPC_LINK\",\n           \"connectionId\" : \"emda4d\",\n           \"httpMethod\" : \"POST\"\n         }\n       }\n     },\n    \"/trading/transactions.php\" : {\n      \"get\" : {\n        \"responses\" : {\n          \"200\" : {\n            \"description\" : \"200 response\",\n            \"content\" : { }\n          }\n        },\n        \"x-amazon-apigateway-request-validator\": \"Validate body, query string parameters, and headers\",\n        \"x-amazon-apigateway-gateway-responses\": {\n            \"BAD_REQUEST_BODY\": {\n                \"responseTemplates\": {\n                    \"application/json\": \"{\\\"message\\\": \\\"$context.error.validationErrorString\\\"}\"\n                }\n            }\n        },    \n        \"x-amazon-apigateway-integration\" : {\n          \"type\" : \"http_proxy\",\n          \"uri\" : \"http://www.cloud-app.uk/trading/transactions.php\",\n          \"responses\" : {\n            \"default\" : {\n              \"statusCode\" : \"200\"\n            }\n          },\n          \"passthroughBehavior\" : \"when_no_match\",\n          \"connectionType\" : \"VPC_LINK\",\n          \"connectionId\" : \"emda4d\",\n          \"httpMethod\" : \"GET\"\n        }\n      }\n    },\n    \"/trading/rest/sell_stocks.php\" : {\n      \"post\" : {\n        \"requestBody\" : {\n          \"content\" : {\n            \"application/json\" : {\n              \"schema\" : {\n                \"$ref\" : \"#/components/schemas/MODEL1ed7ad\"\n              }\n            }\n          },\n          \"required\" : true\n        },\n        \"responses\" : {\n          \"200\" : {\n            \"description\" : \"200 response\",\n            \"content\" : { }\n          }\n        },\n        \"x-amazon-apigateway-request-validator\": \"Validate body, query string parameters, and headers\",\n        \"x-amazon-apigateway-gateway-responses\": {\n            \"BAD_REQUEST_BODY\": {\n                \"responseTemplates\": {\n                    \"application/json\": \"{\\\"message\\\": \\\"$context.error.validationErrorString\\\"}\"\n                }\n            }\n        },\n        \"x-amazon-apigateway-integration\" : {\n          \"type\" : \"http_proxy\",\n          \"uri\" : \"http://api.cloud-app.uk/trading/rest/sell_stocks.php\",\n          \"responses\" : {\n            \"default\" : {\n              \"statusCode\" : \"200\"\n            }\n          },\n          \"passthroughBehavior\" : \"when_no_match\",\n          \"connectionType\" : \"VPC_LINK\",\n          \"connectionId\" : \"emda4d\",\n          \"httpMethod\" : \"POST\"\n        }\n      }\n    },\n    \"/trading/rest/buy_stocks.php\" : {\n      \"post\" : {\n        \"requestBody\" : {\n          \"content\" : {\n            \"application/json\" : {\n              \"schema\" : {\n                \"$ref\" : \"#/components/schemas/MODEL94f81c\"\n              }\n            }\n          },\n          \"required\" : true\n        },\n        \"responses\" : {\n          \"200\" : {\n            \"description\" : \"200 response\",\n            \"content\" : { }\n          }\n        },\n        \"x-amazon-apigateway-request-validator\": \"Validate body, query string parameters, and headers\",\n        \"x-amazon-apigateway-gateway-responses\": {\n            \"BAD_REQUEST_BODY\": {\n                \"responseTemplates\": {\n                    \"application/json\": \"{\\\"message\\\": \\\"$context.error.validationErrorString\\\"}\"\n                }\n            }\n        },\n        \"x-amazon-apigateway-integration\" : {\n          \"type\" : \"http_proxy\",\n          \"uri\" : \"http://api.cloud-app.uk/trading/rest/buy_stocks.php\",\n          \"responses\" : {\n            \"default\" : {\n              \"statusCode\" : \"200\"\n            }\n          },\n          \"passthroughBehavior\" : \"when_no_match\",\n          \"connectionType\" : \"VPC_LINK\",\n          \"connectionId\" : \"emda4d\",\n          \"httpMethod\" : \"POST\"\n        }\n      }\n    }\n  },\n  \"components\" : {\n    \"schemas\" : {\n      \"MODEL94f81c\" : {\n        \"required\" : [ \"action\", \"company\", \"qty\", \"stock_price\", \"trans_value\" ],\n        \"type\" : \"object\",\n        \"properties\" : {\n          \"trans_value\" : {\n            \"minimum\" : 0,\n            \"type\" : \"number\"\n          },\n          \"qty\" : {\n            \"minimum\" : 0,\n            \"type\" : \"integer\",\n            \"format\" : \"int32\"\n          },\n          \"company\" : {\n            \"type\" : \"string\"\n          },\n          \"action\" : {\n            \"type\" : \"string\",\n            \"enum\" : [ \"buy\" ]\n          },\n          \"stock_price\" : {\n            \"minimum\" : 0,\n            \"type\" : \"number\"\n          }\n        },\n        \"additionalProperties\" : false\n      },\n      \"MODEL1ed7ad\" : {\n        \"required\" : [ \"action\", \"company\", \"qty\", \"stock_price\", \"trans_value\" ],\n        \"type\" : \"object\",\n        \"properties\" : {\n          \"trans_value\" : {\n            \"minimum\" : 0,\n            \"type\" : \"number\"\n          },\n          \"qty\" : {\n            \"minimum\" : 0,\n            \"type\" : \"integer\",\n            \"format\" : \"int32\"\n          },\n          \"company\" : {\n            \"type\" : \"string\"\n          },\n          \"action\" : {\n            \"type\" : \"string\",\n            \"enum\" : [ \"sell\" ]\n          },\n          \"stock_price\" : {\n            \"minimum\" : 0,\n            \"type\" : \"number\"\n          }\n        },\n        \"additionalProperties\" : false\n      },\n      \"MODEL9e8bc4\" : {\n        \"required\" : [ \"account\", \"amount\", \"currency\", \"friend\" ],\n        \"type\" : \"object\",\n        \"properties\" : {\n          \"amount\" : {\n            \"minimum\" : 0,\n            \"type\" : \"number\"\n          },\n          \"account\" : {\n            \"type\" : \"number\"\n          },\n          \"currency\" : {\n            \"type\" : \"string\"\n          },\n          \"friend\" : {\n            \"type\" : \"string\"\n          }\n        },\n        \"additionalProperties\" : false\n      }\n    }\n  },\n  \"x-amazon-apigateway-policy\" : {\n    \"Version\" : \"2012-10-17\",\n    \"Statement\" : [ {\n      \"Effect\" : \"Allow\",\n      \"Principal\" : \"*\",\n      \"Action\" : \"execute-api:Invoke\",\n      \"Resource\" : \"arn:aws:execute-api:us-west-2:856265587682:7g8sbh9zs6/*\"\n    } ]\n  },\n  \"x-amazon-apigateway-request-validators\": {\n    \"Validate body, query string parameters, and headers\": {\n      \"validateRequestParameters\": true,\n      \"validateRequestBody\": true\n    }\n  }\n}\n\n\n
\n\n

The Ingress objects controlled by NGINX KIC are responsible for steering the traffic to either the Web or API instances of NGINX App Protect:

\n\n
\napiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n  annotations:\n    kubernetes.io/ingress.class: nginx\n  name: arcadia-nginx-kic\n  namespace: default\nspec:\n  rules:\n  - host: \"*.cloud-app.uk\"\n    http:\n      paths:\n      - backend:\n          serviceName: api-nap\n          servicePort: 80\n        path: /api/rest/execute_money_transfer.php\n      - backend:\n          serviceName: api-nap\n          servicePort: 80\n        path: /trading/rest/buy_stocks.php\n      - backend:\n          serviceName: api-nap\n          servicePort: 80\n        path: /trading/rest/sell_stocks.php\n      - backend:\n          serviceName: web-nap\n          servicePort: 80\n        path: /trading/transactions.php\n      - backend:\n          serviceName: web-nap\n          servicePort: 80\n        path: /\n      - backend:\n          serviceName: web-nap\n          servicePort: 80\n        path: /files\n      - backend:\n          serviceName: web-nap\n          servicePort: 80\n        path: /api\n      - backend:\n          serviceName: web-nap\n          servicePort: 80\n        path: /app3\n\n
\n\n

The NGINX App Protect configuration is also controlled by AWS CodePipeline, deployed as a ConfigMap and mounted as a volume on the NGINX instance:

\n\n
\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: nginx-conf-map-api\n  namespace: default\ndata:\n  nginx.conf: |+\n    user nginx;\n\n    worker_processes auto;\n    load_module modules/ngx_http_app_protect_module.so;\n\n    error_log /var/log/nginx/error.log debug;\n\n    events {\n        worker_connections 10240;\n    }\n\n    http {\n        include /etc/nginx/mime.types;\n        default_type application/octet-stream;\n        sendfile on;\n        keepalive_timeout 65;\n\n        upstream main_DNS_name {\n            server main;\n        }\n        upstream app2_DNS_name {\n            server app2;\n        }\n        server {\n            listen 80;\n            server_name *.cloud-app.uk;\n            proxy_http_version 1.1;\n\n            app_protect_enable on;\n            app_protect_policy_file \"/etc/nginx/NAP_API_Policy.json\";\n            app_protect_security_log_enable on;\n            app_protect_security_log \"/etc/nginx/custom_log_format.json\" syslog:server=fluentd.logging.svc.cluster.local:24224;\n\n            location /trading {\n                client_max_body_size 0;\n                default_type text/html;\n                # set your backend here\n                proxy_pass http://main_DNS_name;\n                proxy_set_header Host $host;\n            }\n\n            location /api {\n                client_max_body_size 0;\n                default_type text/html;\n                # set your backend here\n                proxy_pass http://app2_DNS_name;\n                proxy_set_header Host $host;\n            }\n        }\n}\n
\n\n

 

\n\n
\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: api-nap\n  labels:\n    app: api-nap\nspec:\n  selector:\n    matchLabels:\n      app: api-nap\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        app: api-nap\n    spec:\n      containers:\n      - name: api-nap\n        image: 856265587682.dkr.ecr.us-west-2.amazonaws.com/per-service-nginx-app-protect:latest\n        imagePullPolicy: IfNotPresent\n        ports:\n          - containerPort: 80\n        volumeMounts:\n        - name: nginx-conf-map-api-volume\n          mountPath: \"/etc/nginx/nginx.conf\"\n          subPath: \"nginx.conf\"\n          readOnly: true\n        - name: nap-api-policy-volume\n          mountPath: \"/etc/nginx/NAP_API_Policy.json\"\n          subPath: \"NAP_API_Policy.json\"\n          readOnly: true\n      volumes:\n        - name: nginx-conf-map-api-volume\n          configMap:\n            name: nginx-conf-map-api\n        - name: nap-api-policy-volume\n          configMap:\n            name: nap-api-policy\n\n
\n\n

In case of API NGINX App Protect configuration, there is a reference to the OpenAPI file placed by the CI/CD pipeline in an S3 bucket:

\n\n
\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: nap-api-policy\n  namespace: default\ndata:\n  NAP_API_Policy.json: |+\n    {\n        \"policy\": {\n            \"name\": \"policy_name\",\n            \"template\": { \"name\": \"POLICY_TEMPLATE_NGINX_BASE\" },\n            \"applicationLanguage\": \"utf-8\",\n            \"enforcementMode\": \"blocking\",\n            \"signature-sets\": [\n                {\n                    \"name\": \"High Accuracy Signatures\",\n                    \"block\": true,\n                    \"alarm\": true\n                }\n            ],\n            \"bot-defense\": {\n                \"settings\": {\n                    \"isEnabled\": true\n                },\n                \"mitigations\": {\n                    \"classes\": [\n                        {\n                            \"name\": \"trusted-bot\",\n                            \"action\": \"alarm\"\n                        },\n                        {\n                            \"name\": \"untrusted-bot\",\n                            \"action\": \"block\"\n                        },\n                        {\n                            \"name\": \"malicious-bot\",\n                            \"action\": \"block\"\n                        }\n                    ]\n                }\n            },\n            \"open-api-files\": [\n                {\n                    \"link\": \"https://per-service-nginx-app-protect.s3.us-west-2.amazonaws.com/arcadia-openapi3-aws.json\"\n                }            \n            ],\n           \"blocking-settings\": {\n                \"violations\": [\n                    {\n                        \"name\": \"VIOL_JSON_FORMAT\",\n                        \"alarm\": true,\n                        \"block\": true\n                    },\n                    {\n                        \"name\": \"VIOL_PARAMETER_VALUE_METACHAR\",\n                        \"alarm\": false,\n                        \"block\": false\n                    },\n                    {\n                        \"name\": \"VIOL_HTTP_PROTOCOL\",\n                        \"alarm\": true,\n                        \"block\": true\n                    },\n                    {\n                        \"name\": \"VIOL_EVASION\",\n                        \"alarm\": true,\n                        \"block\": true\n                    },\n                    {\n                        \"name\": \"VIOL_FILETYPE\",\n                        \"alarm\": true,\n                        \"block\": true\n                    },\n                    {\n                        \"name\": \"VIOL_METHOD\",\n                        \"alarm\": true,\n                        \"block\": true\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Disallowed file upload content detected in body\",\n                        \"name\": \"VIOL_FILE_UPLOAD_IN_BODY\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Mandatory request body is missing\",\n                        \"name\": \"VIOL_MANDATORY_REQUEST_BODY\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Illegal parameter location\",\n                        \"name\": \"VIOL_PARAMETER_LOCATION\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Mandatory parameter is missing\",\n                        \"name\": \"VIOL_MANDATORY_PARAMETER\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"JSON data does not comply with JSON schema\",\n                        \"name\": \"VIOL_JSON_SCHEMA\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Illegal parameter array value\",\n                        \"name\": \"VIOL_PARAMETER_ARRAY_VALUE\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Illegal Base64 value\",\n                        \"name\": \"VIOL_PARAMETER_VALUE_BASE64\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Disallowed file upload content detected\",\n                        \"name\": \"VIOL_FILE_UPLOAD\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Illegal request content type\",\n                        \"name\": \"VIOL_URL_CONTENT_TYPE\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Illegal static parameter value\",\n                        \"name\": \"VIOL_PARAMETER_STATIC_VALUE\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Illegal parameter value length\",\n                        \"name\": \"VIOL_PARAMETER_VALUE_LENGTH\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Illegal parameter data type\",\n                        \"name\": \"VIOL_PARAMETER_DATA_TYPE\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Illegal parameter numeric value\",\n                        \"name\": \"VIOL_PARAMETER_NUMERIC_VALUE\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Parameter value does not comply with regular expression\",\n                        \"name\": \"VIOL_PARAMETER_VALUE_REGEXP\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Illegal URL\",\n                        \"name\": \"VIOL_URL\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Illegal parameter\",\n                        \"name\": \"VIOL_PARAMETER\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Illegal empty parameter value\",\n                        \"name\": \"VIOL_PARAMETER_EMPTY_VALUE\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Illegal repeated parameter name\",\n                        \"name\": \"VIOL_PARAMETER_REPEATED\"\n                    }\n                ],\n                \"http-protocols\": [\n                    {\n                        \"description\": \"Header name with no header value\",\n                        \"enabled\": true\n                    },\n                    {\n                        \"description\": \"Chunked request with Content-Length header\",\n                        \"enabled\": true\n                    },\n                    {\n                        \"description\": \"Check maximum number of parameters\",\n                        \"enabled\": true,\n                        \"maxParams\": 5\n                    },\n                    {\n                        \"description\": \"Check maximum number of headers\",\n                        \"enabled\": true,\n                        \"maxHeaders\": 30\n                    },\n                    {\n                        \"description\": \"Body in GET or HEAD requests\",\n                        \"enabled\": true\n                    },\n                    {\n                        \"description\": \"Bad multipart/form-data request parsing\",\n                        \"enabled\": true\n                    },\n                    {\n                        \"description\": \"Bad multipart parameters parsing\",\n                        \"enabled\": true\n                    },\n                    {\n                        \"description\": \"Unescaped space in URL\",\n                        \"enabled\": true\n                    }\n                ],\n                \"evasions\": [\n                    {\n                        \"description\": \"Bad unescape\",\n                        \"enabled\": true\n                    },\n                    {\n                        \"description\": \"Directory traversals\",\n                        \"enabled\": true\n                    },\n                    {\n                        \"description\": \"Bare byte decoding\",\n                        \"enabled\": true\n                    },\n                    {\n                        \"description\": \"Apache whitespace\",\n                        \"enabled\": true\n                    },\n                    {\n                        \"description\": \"Multiple decoding\",\n                        \"enabled\": true,\n                        \"maxDecodingPasses\": 2\n                    },\n                    {\n                        \"description\": \"IIS Unicode codepoints\",\n                        \"enabled\": true\n                    },\n                    {\n                        \"description\": \"%u decoding\",\n                        \"enabled\": true\n                    }\n                ]\n            },\n            \"methodReference\": {\n                \"link\": \"https://per-service-nginx-app-protect.s3.us-west-2.amazonaws.com/methods.txt\"\n            },\n            \"filetypeReference\": {\n                \"link\": \"https://per-service-nginx-app-protect.s3.us-west-2.amazonaws.com/filetypes.txt\"\n            }\n        }\n    }\n\n
\n\n

In this case, the same OpenAPI file is pushed to both AWS API Gateway and, through the S3 bucket, to the NGINX App Protect API instance.

\n\n

NGINX App Protect augmenting the security provided by AWS API Gateway

\n\n

The NGINX App Protect API instance enhances the security posture of API Gateway by providing negative security (attack signature matching) and advanced security like bot detection. To demonstrate this functionality, a SQLi attack is simulated against the API.

\n\n

This valid API call sent by Postman is successfully completed:

\n\n

\n\n

A similar call that contains an attack pattern (SQL injection) is being blocked by the NGINX App Protect instance:

\n\n

\n\n

To demonstrate the bot detection capability, the same valid call sent before is now sent from Curl (as opposed to Postman used earlier), now matching an untrusted bot signature and being blocked:

\n\n
\ncurl -vvvk https://api.cloud-app.uk/api/rest/execute_money_transfer.php -d '{\"account\": 2075894, \"amount\": 1, \"currency\": \"GBP\", \"friend\": \"Vincent\"}' -H \"Content-Type: application/json\" -X POST\nNote: Unnecessary use of -X or --request, POST is already inferred.\n*   Trying 143.204.170.103...\n* TCP_NODELAY set\n* Connected to api.cloud-app.uk (143.204.170.103) port 443 (#0)\n* WARNING: disabling hostname validation also disables SNI.\n* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256\n* Server certificate: *.cloudfront.net\n* Server certificate: DigiCert Global CA G2\n* Server certificate: DigiCert Global Root G2\n> POST /api/rest/execute_money_transfer.php HTTP/1.1\n> Host: api.cloud-app.uk\n> User-Agent: curl/7.54.0\n> Accept: */*\n> Content-Type: application/json\n> Content-Length: 73\n>\n* upload completely sent off: 73 out of 73 bytes\n< HTTP/1.1 403 Forbidden\n< Content-Type: application/json; charset=utf-8\n< Content-Length: 37\n< Connection: keep-alive\n< Date: Sat, 28 Nov 2020 20:59:01 GMT\n< x-amzn-RequestId: 213ca523-173b-42a9-ab41-e3420602bef9\n< x-amzn-Remapped-Content-Length: 37\n< x-amzn-Remapped-Connection: keep-alive\n< x-amz-apigw-id: WvIDaFu0PHcFZOg=\n< Cache-Control: no-cache\n< x-amzn-Remapped-Server: nginx/1.19.3\n< Pragma: no-cache\n< x-amzn-Remapped-Date: Sat, 28 Nov 2020 20:59:01 GMT\n< X-Cache: Error from cloudfront\n< Via: 1.1 9a0d5427f47351631cdee4d5e38248d8.cloudfront.net (CloudFront)\n< X-Amz-Cf-Pop: LHR50-C1\n< X-Amz-Cf-Id: _VYxM43hCyrzj5hJNitbxLkzjww7iygpoWXT7sege-5eySEaKmcRxQ==\n<\n{\"supportID\": \"4099392564272510395\"}\n* Connection #0 to host api.cloud-app.uk left intact\n\n
\n\n

This can be checked in the NGINX App Protect security logs displayed in Kibana NGINX App Protect dashboards, running in AWS ElasticSearch:

\n\n

\n\n

The bot defense behavior can be controlled from the policy file under the CodeCommit repository. Changing the action from \"block\" to \"alarm\" for \"untrusted bot\" and commiting the change will trigger the pipeline to redeploy the NGINX App Protect policy:

\n\n
\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: nap-api-policy\n  namespace: default\ndata:\n  NAP_API_Policy.json: |+\n    {\n        \"policy\": {\n            \"name\": \"policy_name\",\n            \"template\": { \"name\": \"POLICY_TEMPLATE_NGINX_BASE\" },\n            \"applicationLanguage\": \"utf-8\",\n            \"enforcementMode\": \"blocking\",\n            \"signature-sets\": [\n                {\n                    \"name\": \"High Accuracy Signatures\",\n                    \"block\": true,\n                    \"alarm\": true\n                }\n            ],\n            \"bot-defense\": {\n                \"settings\": {\n                    \"isEnabled\": true\n                },\n                \"mitigations\": {\n                    \"classes\": [\n                        {\n                            \"name\": \"trusted-bot\",\n                            \"action\": \"alarm\"\n                        },\n                        {\n                            \"name\": \"untrusted-bot\",\n                            \"action\": \"block\"\n                        },\n                        {\n                            \"name\": \"malicious-bot\",\n                            \"action\": \"block\"\n                        }\n                    ]\n                }\n            },\n...............................................................................................................\n\n
\n\n

The same Curl call is now being allowed:

\n\n
\ncurl -vvvk https://api.cloud-app.uk/api/rest/execute_money_transfer.php -d '{\"account\": 2075894, \"amount\": 1, \"currency\": \"GBP\", \"friend\": \"Vincent\"}' -H \"Content-Type: application/json\" -X POST\nNote: Unnecessary use of -X or --request, POST is already inferred.\n*   Trying 143.204.192.29...\n* TCP_NODELAY set\n* Connected to api.cloud-app.uk (143.204.192.29) port 443 (#0)\n* ALPN, offering h2\n* ALPN, offering http/1.1\n* successfully set certificate verify locations:\n*   CAfile: /etc/ssl/cert.pem\n  CApath: none\n* TLSv1.2 (OUT), TLS handshake, Client hello (1):\n* TLSv1.2 (IN), TLS handshake, Server hello (2):\n* TLSv1.2 (IN), TLS handshake, Certificate (11):\n* TLSv1.2 (IN), TLS handshake, Server key exchange (12):\n* TLSv1.2 (IN), TLS handshake, Server finished (14):\n* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):\n* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):\n* TLSv1.2 (OUT), TLS handshake, Finished (20):\n* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):\n* TLSv1.2 (IN), TLS handshake, Finished (20):\n* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256\n* ALPN, server accepted to use h2\n* Server certificate:\n*  subject: CN=*.cloud-app.uk\n*  start date: Nov 18 00:00:00 2020 GMT\n*  expire date: Dec 17 23:59:59 2021 GMT\n*  issuer: C=US; O=Amazon; OU=Server CA 1B; CN=Amazon\n*  SSL certificate verify ok.\n* Using HTTP2, server supports multi-use\n* Connection state changed (HTTP/2 confirmed)\n* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0\n* Using Stream ID: 1 (easy handle 0x7fc877008200)\n> POST /api/rest/execute_money_transfer.php HTTP/2\n> Host: api.cloud-app.uk\n> User-Agent: curl/7.64.1\n> Accept: */*\n> Content-Type: application/json\n> Content-Length: 75\n>\n* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!\n* We are completely uploaded and fine\n< HTTP/2 200\n< content-type: text/html; charset=UTF-8\n< content-length: 155\n< date: Mon, 30 Nov 2020 11:02:19 GMT\n< x-amzn-requestid: 9bdb2379-06c4-4970-a528-cd8de9cb75b3\n< x-amzn-remapped-content-length: 155\n< x-amzn-remapped-connection: keep-alive\n< x-amz-apigw-id: W0WhMH_TvHcFndQ=\n< x-amzn-remapped-server: nginx/1.19.3\n< vary: Accept-Encoding\n< x-amzn-remapped-date: Mon, 30 Nov 2020 11:02:19 GMT\n< x-cache: Miss from cloudfront\n< via: 1.1 bb501579906725a97059c817430425cf.cloudfront.net (CloudFront)\n< x-amz-cf-pop: LHR3-C1\n< x-amz-cf-id: xo4zfKVqUeejkHzLPArADi1rxRxTJkg61YgfhruAR4KjdpMSnYymkQ==\n<\n* Connection #0 to host api.cloud-app.uk left intact\n{\"name\":\"Vincent\", \"status\":\"success\",\"amount\":\"1\", \"currency\":\"GBP\", \"transid\":\"753910682\", \"msg\":\"The money transfer has been successfully completed \"}* Closing connection 0\n\n
\n\n

The new bot defense behavior can be checked in the NGINX App Protect Kibana dashboard:

\n\n

\n\n

Conclusion

\n\n

To recap, this article has demoed the per-service model of deployment for NGINX App Protect in Kubernetes environment. The main advantage of this deployment model is the independent management of security policies and the portability of each security policy.

\n\n

NGINX App Protect elevates the security level provided by the API Gateway by providing negative security and advanced security features like bot detection.

\n\n

The configuration is being controlled by a CI/CD pipeline, in this case AWS CodePipeline, and the same OpenAPI file used to configure the AWS API Gateway is also ingested by the NGINX App Protect API instance.

\n\n

Lastly the security logs sent by NGINX App Protect through Fluentd to AWS ElasticSearch are being displayed in Kibana dashboards.

","body@stringLength":"75959","rawBody":"

Introduction

\n\n

When the design objective for Kubernetes security is the separate management of WAF security policies, the solution is NGINX App Protect deployed per-service. This article describes such a deployment, with NGINX App Protect augmenting AWS API Gateway to provide advanced security to API workloads, deployed through a CI/CD pipeline. The advantage of NGINX App Protect deployed per-service in a Kubernetes environment is the separation of security policies between different services, allowing for better customisation of the policies and easier portability to different environments.

\n\n

In this particular instance, I used a demo application, Arcadia Finance, that has a Web interface and also exposes an API allowing the users to make financial transactions. The API is described in an OpenAPI 3.0 file, allowing for the automated building of the positive security policy elements (allow list elements) whereas in the case of the web security policy, this configuration will be done manually.

\n\n

The difference in configuration methods between the API and Web policies and the additional requirement for policy separation and independent portability between environments prompted the usage of two separate NGINX App Protect instance, each securing their respective service (Web and API).

\n\n

The deployment used AWS EKS as Kubernetes environment where, beside the Arcadia Finance application components and NGINX App Protect instances, there is also a Fluentd deployment configured as a Syslog server for security logs sent by the NGINX App Protect instances. The logs are then being sent to AWS Elasticsearch and displayed via Kibana NGINX App Protect dashboards.

\n\n

Access to EKS cluster is being provided by an NGINX Ingress Controller instance. The Web interface is being exposed externally through an AWS Application LoadBalancer, handling the SSL offloading while the API is exposed through a Network LoadBalancer. The API is published externally through AWS API Gateway, providing basic security, using a VPC link to connect to the Network LoadBalancer.

\n\n

\n\n

The configuration

\n\n

The configuration (Arcadia Finance deployment, NGINX KIC, NGINX App Protect configuration, OpenAPI file) is being stored in AWS CodeComit and deployed through AWS CodePipeline and AWS CodeBuild.

\n\n

The API Gateway configuration is being described in an OpenAPI file annotated for AWS API Gateway-specific elements:

\n\n
\n{\n  \"openapi\" : \"3.0.1\",\n  \"info\" : {\n    \"title\" : \"API Arcadia Finance\",\n    \"description\" : \"Arcadia OpenAPI\",\n    \"version\" : \"1.0.0-oas3\"\n  },\n  \"servers\" : [ {\n    \"url\" : \"https://api.cloud-app.uk\"\n  } ],\n  \"paths\" : {\n          \"/api/rest/execute_money_transfer.php\" : {\n       \"post\" : {\n         \"requestBody\" : {\n           \"content\" : {\n             \"application/json\" : {\n               \"schema\" : {\n                 \"$ref\" : \"#/components/schemas/MODEL9e8bc4\"\n               }\n             }\n           },\n           \"required\" : true\n         },\n         \"responses\" : {\n           \"200\" : {\n             \"description\" : \"200 response\",\n             \"content\" : { }\n           }\n         },\n         \"x-amazon-apigateway-request-validator\": \"Validate body, query string parameters, and headers\",\n         \"x-amazon-apigateway-gateway-responses\": {\n             \"BAD_REQUEST_BODY\": {\n                 \"responseTemplates\": {\n                     \"application/json\": \"{\\\"message\\\": \\\"Bla Bla\\\"}\"\n                 }\n             }\n         },\n         \"x-amazon-apigateway-integration\" : {\n           \"type\" : \"http_proxy\",\n           \"uri\" : \"http://api.cloud-app.uk/api/rest/execute_money_transfer.php\",\n           \"responses\" : {\n             \"default\" : {\n               \"statusCode\" : \"200\"\n             }\n           },\n           \"passthroughBehavior\" : \"when_no_match\",\n           \"connectionType\" : \"VPC_LINK\",\n           \"connectionId\" : \"emda4d\",\n           \"httpMethod\" : \"POST\"\n         }\n       }\n     },\n    \"/trading/transactions.php\" : {\n      \"get\" : {\n        \"responses\" : {\n          \"200\" : {\n            \"description\" : \"200 response\",\n            \"content\" : { }\n          }\n        },\n        \"x-amazon-apigateway-request-validator\": \"Validate body, query string parameters, and headers\",\n        \"x-amazon-apigateway-gateway-responses\": {\n            \"BAD_REQUEST_BODY\": {\n                \"responseTemplates\": {\n                    \"application/json\": \"{\\\"message\\\": \\\"$context.error.validationErrorString\\\"}\"\n                }\n            }\n        },    \n        \"x-amazon-apigateway-integration\" : {\n          \"type\" : \"http_proxy\",\n          \"uri\" : \"http://www.cloud-app.uk/trading/transactions.php\",\n          \"responses\" : {\n            \"default\" : {\n              \"statusCode\" : \"200\"\n            }\n          },\n          \"passthroughBehavior\" : \"when_no_match\",\n          \"connectionType\" : \"VPC_LINK\",\n          \"connectionId\" : \"emda4d\",\n          \"httpMethod\" : \"GET\"\n        }\n      }\n    },\n    \"/trading/rest/sell_stocks.php\" : {\n      \"post\" : {\n        \"requestBody\" : {\n          \"content\" : {\n            \"application/json\" : {\n              \"schema\" : {\n                \"$ref\" : \"#/components/schemas/MODEL1ed7ad\"\n              }\n            }\n          },\n          \"required\" : true\n        },\n        \"responses\" : {\n          \"200\" : {\n            \"description\" : \"200 response\",\n            \"content\" : { }\n          }\n        },\n        \"x-amazon-apigateway-request-validator\": \"Validate body, query string parameters, and headers\",\n        \"x-amazon-apigateway-gateway-responses\": {\n            \"BAD_REQUEST_BODY\": {\n                \"responseTemplates\": {\n                    \"application/json\": \"{\\\"message\\\": \\\"$context.error.validationErrorString\\\"}\"\n                }\n            }\n        },\n        \"x-amazon-apigateway-integration\" : {\n          \"type\" : \"http_proxy\",\n          \"uri\" : \"http://api.cloud-app.uk/trading/rest/sell_stocks.php\",\n          \"responses\" : {\n            \"default\" : {\n              \"statusCode\" : \"200\"\n            }\n          },\n          \"passthroughBehavior\" : \"when_no_match\",\n          \"connectionType\" : \"VPC_LINK\",\n          \"connectionId\" : \"emda4d\",\n          \"httpMethod\" : \"POST\"\n        }\n      }\n    },\n    \"/trading/rest/buy_stocks.php\" : {\n      \"post\" : {\n        \"requestBody\" : {\n          \"content\" : {\n            \"application/json\" : {\n              \"schema\" : {\n                \"$ref\" : \"#/components/schemas/MODEL94f81c\"\n              }\n            }\n          },\n          \"required\" : true\n        },\n        \"responses\" : {\n          \"200\" : {\n            \"description\" : \"200 response\",\n            \"content\" : { }\n          }\n        },\n        \"x-amazon-apigateway-request-validator\": \"Validate body, query string parameters, and headers\",\n        \"x-amazon-apigateway-gateway-responses\": {\n            \"BAD_REQUEST_BODY\": {\n                \"responseTemplates\": {\n                    \"application/json\": \"{\\\"message\\\": \\\"$context.error.validationErrorString\\\"}\"\n                }\n            }\n        },\n        \"x-amazon-apigateway-integration\" : {\n          \"type\" : \"http_proxy\",\n          \"uri\" : \"http://api.cloud-app.uk/trading/rest/buy_stocks.php\",\n          \"responses\" : {\n            \"default\" : {\n              \"statusCode\" : \"200\"\n            }\n          },\n          \"passthroughBehavior\" : \"when_no_match\",\n          \"connectionType\" : \"VPC_LINK\",\n          \"connectionId\" : \"emda4d\",\n          \"httpMethod\" : \"POST\"\n        }\n      }\n    }\n  },\n  \"components\" : {\n    \"schemas\" : {\n      \"MODEL94f81c\" : {\n        \"required\" : [ \"action\", \"company\", \"qty\", \"stock_price\", \"trans_value\" ],\n        \"type\" : \"object\",\n        \"properties\" : {\n          \"trans_value\" : {\n            \"minimum\" : 0,\n            \"type\" : \"number\"\n          },\n          \"qty\" : {\n            \"minimum\" : 0,\n            \"type\" : \"integer\",\n            \"format\" : \"int32\"\n          },\n          \"company\" : {\n            \"type\" : \"string\"\n          },\n          \"action\" : {\n            \"type\" : \"string\",\n            \"enum\" : [ \"buy\" ]\n          },\n          \"stock_price\" : {\n            \"minimum\" : 0,\n            \"type\" : \"number\"\n          }\n        },\n        \"additionalProperties\" : false\n      },\n      \"MODEL1ed7ad\" : {\n        \"required\" : [ \"action\", \"company\", \"qty\", \"stock_price\", \"trans_value\" ],\n        \"type\" : \"object\",\n        \"properties\" : {\n          \"trans_value\" : {\n            \"minimum\" : 0,\n            \"type\" : \"number\"\n          },\n          \"qty\" : {\n            \"minimum\" : 0,\n            \"type\" : \"integer\",\n            \"format\" : \"int32\"\n          },\n          \"company\" : {\n            \"type\" : \"string\"\n          },\n          \"action\" : {\n            \"type\" : \"string\",\n            \"enum\" : [ \"sell\" ]\n          },\n          \"stock_price\" : {\n            \"minimum\" : 0,\n            \"type\" : \"number\"\n          }\n        },\n        \"additionalProperties\" : false\n      },\n      \"MODEL9e8bc4\" : {\n        \"required\" : [ \"account\", \"amount\", \"currency\", \"friend\" ],\n        \"type\" : \"object\",\n        \"properties\" : {\n          \"amount\" : {\n            \"minimum\" : 0,\n            \"type\" : \"number\"\n          },\n          \"account\" : {\n            \"type\" : \"number\"\n          },\n          \"currency\" : {\n            \"type\" : \"string\"\n          },\n          \"friend\" : {\n            \"type\" : \"string\"\n          }\n        },\n        \"additionalProperties\" : false\n      }\n    }\n  },\n  \"x-amazon-apigateway-policy\" : {\n    \"Version\" : \"2012-10-17\",\n    \"Statement\" : [ {\n      \"Effect\" : \"Allow\",\n      \"Principal\" : \"*\",\n      \"Action\" : \"execute-api:Invoke\",\n      \"Resource\" : \"arn:aws:execute-api:us-west-2:856265587682:7g8sbh9zs6/*\"\n    } ]\n  },\n  \"x-amazon-apigateway-request-validators\": {\n    \"Validate body, query string parameters, and headers\": {\n      \"validateRequestParameters\": true,\n      \"validateRequestBody\": true\n    }\n  }\n}\n\n\n
\n\n

The Ingress objects controlled by NGINX KIC are responsible for steering the traffic to either the Web or API instances of NGINX App Protect:

\n\n
\napiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n  annotations:\n    kubernetes.io/ingress.class: nginx\n  name: arcadia-nginx-kic\n  namespace: default\nspec:\n  rules:\n  - host: \"*.cloud-app.uk\"\n    http:\n      paths:\n      - backend:\n          serviceName: api-nap\n          servicePort: 80\n        path: /api/rest/execute_money_transfer.php\n      - backend:\n          serviceName: api-nap\n          servicePort: 80\n        path: /trading/rest/buy_stocks.php\n      - backend:\n          serviceName: api-nap\n          servicePort: 80\n        path: /trading/rest/sell_stocks.php\n      - backend:\n          serviceName: web-nap\n          servicePort: 80\n        path: /trading/transactions.php\n      - backend:\n          serviceName: web-nap\n          servicePort: 80\n        path: /\n      - backend:\n          serviceName: web-nap\n          servicePort: 80\n        path: /files\n      - backend:\n          serviceName: web-nap\n          servicePort: 80\n        path: /api\n      - backend:\n          serviceName: web-nap\n          servicePort: 80\n        path: /app3\n\n
\n\n

The NGINX App Protect configuration is also controlled by AWS CodePipeline, deployed as a ConfigMap and mounted as a volume on the NGINX instance:

\n\n
\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: nginx-conf-map-api\n  namespace: default\ndata:\n  nginx.conf: |+\n    user nginx;\n\n    worker_processes auto;\n    load_module modules/ngx_http_app_protect_module.so;\n\n    error_log /var/log/nginx/error.log debug;\n\n    events {\n        worker_connections 10240;\n    }\n\n    http {\n        include /etc/nginx/mime.types;\n        default_type application/octet-stream;\n        sendfile on;\n        keepalive_timeout 65;\n\n        upstream main_DNS_name {\n            server main;\n        }\n        upstream app2_DNS_name {\n            server app2;\n        }\n        server {\n            listen 80;\n            server_name *.cloud-app.uk;\n            proxy_http_version 1.1;\n\n            app_protect_enable on;\n            app_protect_policy_file \"/etc/nginx/NAP_API_Policy.json\";\n            app_protect_security_log_enable on;\n            app_protect_security_log \"/etc/nginx/custom_log_format.json\" syslog:server=fluentd.logging.svc.cluster.local:24224;\n\n            location /trading {\n                client_max_body_size 0;\n                default_type text/html;\n                # set your backend here\n                proxy_pass http://main_DNS_name;\n                proxy_set_header Host $host;\n            }\n\n            location /api {\n                client_max_body_size 0;\n                default_type text/html;\n                # set your backend here\n                proxy_pass http://app2_DNS_name;\n                proxy_set_header Host $host;\n            }\n        }\n}\n
\n\n

 

\n\n
\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: api-nap\n  labels:\n    app: api-nap\nspec:\n  selector:\n    matchLabels:\n      app: api-nap\n  replicas: 1\n  template:\n    metadata:\n      labels:\n        app: api-nap\n    spec:\n      containers:\n      - name: api-nap\n        image: 856265587682.dkr.ecr.us-west-2.amazonaws.com/per-service-nginx-app-protect:latest\n        imagePullPolicy: IfNotPresent\n        ports:\n          - containerPort: 80\n        volumeMounts:\n        - name: nginx-conf-map-api-volume\n          mountPath: \"/etc/nginx/nginx.conf\"\n          subPath: \"nginx.conf\"\n          readOnly: true\n        - name: nap-api-policy-volume\n          mountPath: \"/etc/nginx/NAP_API_Policy.json\"\n          subPath: \"NAP_API_Policy.json\"\n          readOnly: true\n      volumes:\n        - name: nginx-conf-map-api-volume\n          configMap:\n            name: nginx-conf-map-api\n        - name: nap-api-policy-volume\n          configMap:\n            name: nap-api-policy\n\n
\n\n

In case of API NGINX App Protect configuration, there is a reference to the OpenAPI file placed by the CI/CD pipeline in an S3 bucket:

\n\n
\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: nap-api-policy\n  namespace: default\ndata:\n  NAP_API_Policy.json: |+\n    {\n        \"policy\": {\n            \"name\": \"policy_name\",\n            \"template\": { \"name\": \"POLICY_TEMPLATE_NGINX_BASE\" },\n            \"applicationLanguage\": \"utf-8\",\n            \"enforcementMode\": \"blocking\",\n            \"signature-sets\": [\n                {\n                    \"name\": \"High Accuracy Signatures\",\n                    \"block\": true,\n                    \"alarm\": true\n                }\n            ],\n            \"bot-defense\": {\n                \"settings\": {\n                    \"isEnabled\": true\n                },\n                \"mitigations\": {\n                    \"classes\": [\n                        {\n                            \"name\": \"trusted-bot\",\n                            \"action\": \"alarm\"\n                        },\n                        {\n                            \"name\": \"untrusted-bot\",\n                            \"action\": \"block\"\n                        },\n                        {\n                            \"name\": \"malicious-bot\",\n                            \"action\": \"block\"\n                        }\n                    ]\n                }\n            },\n            \"open-api-files\": [\n                {\n                    \"link\": \"https://per-service-nginx-app-protect.s3.us-west-2.amazonaws.com/arcadia-openapi3-aws.json\"\n                }            \n            ],\n           \"blocking-settings\": {\n                \"violations\": [\n                    {\n                        \"name\": \"VIOL_JSON_FORMAT\",\n                        \"alarm\": true,\n                        \"block\": true\n                    },\n                    {\n                        \"name\": \"VIOL_PARAMETER_VALUE_METACHAR\",\n                        \"alarm\": false,\n                        \"block\": false\n                    },\n                    {\n                        \"name\": \"VIOL_HTTP_PROTOCOL\",\n                        \"alarm\": true,\n                        \"block\": true\n                    },\n                    {\n                        \"name\": \"VIOL_EVASION\",\n                        \"alarm\": true,\n                        \"block\": true\n                    },\n                    {\n                        \"name\": \"VIOL_FILETYPE\",\n                        \"alarm\": true,\n                        \"block\": true\n                    },\n                    {\n                        \"name\": \"VIOL_METHOD\",\n                        \"alarm\": true,\n                        \"block\": true\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Disallowed file upload content detected in body\",\n                        \"name\": \"VIOL_FILE_UPLOAD_IN_BODY\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Mandatory request body is missing\",\n                        \"name\": \"VIOL_MANDATORY_REQUEST_BODY\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Illegal parameter location\",\n                        \"name\": \"VIOL_PARAMETER_LOCATION\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Mandatory parameter is missing\",\n                        \"name\": \"VIOL_MANDATORY_PARAMETER\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"JSON data does not comply with JSON schema\",\n                        \"name\": \"VIOL_JSON_SCHEMA\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Illegal parameter array value\",\n                        \"name\": \"VIOL_PARAMETER_ARRAY_VALUE\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Illegal Base64 value\",\n                        \"name\": \"VIOL_PARAMETER_VALUE_BASE64\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Disallowed file upload content detected\",\n                        \"name\": \"VIOL_FILE_UPLOAD\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Illegal request content type\",\n                        \"name\": \"VIOL_URL_CONTENT_TYPE\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Illegal static parameter value\",\n                        \"name\": \"VIOL_PARAMETER_STATIC_VALUE\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Illegal parameter value length\",\n                        \"name\": \"VIOL_PARAMETER_VALUE_LENGTH\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Illegal parameter data type\",\n                        \"name\": \"VIOL_PARAMETER_DATA_TYPE\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Illegal parameter numeric value\",\n                        \"name\": \"VIOL_PARAMETER_NUMERIC_VALUE\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Parameter value does not comply with regular expression\",\n                        \"name\": \"VIOL_PARAMETER_VALUE_REGEXP\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Illegal URL\",\n                        \"name\": \"VIOL_URL\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Illegal parameter\",\n                        \"name\": \"VIOL_PARAMETER\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Illegal empty parameter value\",\n                        \"name\": \"VIOL_PARAMETER_EMPTY_VALUE\"\n                    },\n                    {\n                        \"block\": true,\n                        \"description\": \"Illegal repeated parameter name\",\n                        \"name\": \"VIOL_PARAMETER_REPEATED\"\n                    }\n                ],\n                \"http-protocols\": [\n                    {\n                        \"description\": \"Header name with no header value\",\n                        \"enabled\": true\n                    },\n                    {\n                        \"description\": \"Chunked request with Content-Length header\",\n                        \"enabled\": true\n                    },\n                    {\n                        \"description\": \"Check maximum number of parameters\",\n                        \"enabled\": true,\n                        \"maxParams\": 5\n                    },\n                    {\n                        \"description\": \"Check maximum number of headers\",\n                        \"enabled\": true,\n                        \"maxHeaders\": 30\n                    },\n                    {\n                        \"description\": \"Body in GET or HEAD requests\",\n                        \"enabled\": true\n                    },\n                    {\n                        \"description\": \"Bad multipart/form-data request parsing\",\n                        \"enabled\": true\n                    },\n                    {\n                        \"description\": \"Bad multipart parameters parsing\",\n                        \"enabled\": true\n                    },\n                    {\n                        \"description\": \"Unescaped space in URL\",\n                        \"enabled\": true\n                    }\n                ],\n                \"evasions\": [\n                    {\n                        \"description\": \"Bad unescape\",\n                        \"enabled\": true\n                    },\n                    {\n                        \"description\": \"Directory traversals\",\n                        \"enabled\": true\n                    },\n                    {\n                        \"description\": \"Bare byte decoding\",\n                        \"enabled\": true\n                    },\n                    {\n                        \"description\": \"Apache whitespace\",\n                        \"enabled\": true\n                    },\n                    {\n                        \"description\": \"Multiple decoding\",\n                        \"enabled\": true,\n                        \"maxDecodingPasses\": 2\n                    },\n                    {\n                        \"description\": \"IIS Unicode codepoints\",\n                        \"enabled\": true\n                    },\n                    {\n                        \"description\": \"%u decoding\",\n                        \"enabled\": true\n                    }\n                ]\n            },\n            \"methodReference\": {\n                \"link\": \"https://per-service-nginx-app-protect.s3.us-west-2.amazonaws.com/methods.txt\"\n            },\n            \"filetypeReference\": {\n                \"link\": \"https://per-service-nginx-app-protect.s3.us-west-2.amazonaws.com/filetypes.txt\"\n            }\n        }\n    }\n\n
\n\n

In this case, the same OpenAPI file is pushed to both AWS API Gateway and, through the S3 bucket, to the NGINX App Protect API instance.

\n\n

NGINX App Protect augmenting the security provided by AWS API Gateway

\n\n

The NGINX App Protect API instance enhances the security posture of API Gateway by providing negative security (attack signature matching) and advanced security like bot detection. To demonstrate this functionality, a SQLi attack is simulated against the API.

\n\n

This valid API call sent by Postman is successfully completed:

\n\n

\n\n

A similar call that contains an attack pattern (SQL injection) is being blocked by the NGINX App Protect instance:

\n\n

\n\n

To demonstrate the bot detection capability, the same valid call sent before is now sent from Curl (as opposed to Postman used earlier), now matching an untrusted bot signature and being blocked:

\n\n
\ncurl -vvvk https://api.cloud-app.uk/api/rest/execute_money_transfer.php -d '{\"account\": 2075894, \"amount\": 1, \"currency\": \"GBP\", \"friend\": \"Vincent\"}' -H \"Content-Type: application/json\" -X POST\nNote: Unnecessary use of -X or --request, POST is already inferred.\n*   Trying 143.204.170.103...\n* TCP_NODELAY set\n* Connected to api.cloud-app.uk (143.204.170.103) port 443 (#0)\n* WARNING: disabling hostname validation also disables SNI.\n* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256\n* Server certificate: *.cloudfront.net\n* Server certificate: DigiCert Global CA G2\n* Server certificate: DigiCert Global Root G2\n> POST /api/rest/execute_money_transfer.php HTTP/1.1\n> Host: api.cloud-app.uk\n> User-Agent: curl/7.54.0\n> Accept: */*\n> Content-Type: application/json\n> Content-Length: 73\n>\n* upload completely sent off: 73 out of 73 bytes\n< HTTP/1.1 403 Forbidden\n< Content-Type: application/json; charset=utf-8\n< Content-Length: 37\n< Connection: keep-alive\n< Date: Sat, 28 Nov 2020 20:59:01 GMT\n< x-amzn-RequestId: 213ca523-173b-42a9-ab41-e3420602bef9\n< x-amzn-Remapped-Content-Length: 37\n< x-amzn-Remapped-Connection: keep-alive\n< x-amz-apigw-id: WvIDaFu0PHcFZOg=\n< Cache-Control: no-cache\n< x-amzn-Remapped-Server: nginx/1.19.3\n< Pragma: no-cache\n< x-amzn-Remapped-Date: Sat, 28 Nov 2020 20:59:01 GMT\n< X-Cache: Error from cloudfront\n< Via: 1.1 9a0d5427f47351631cdee4d5e38248d8.cloudfront.net (CloudFront)\n< X-Amz-Cf-Pop: LHR50-C1\n< X-Amz-Cf-Id: _VYxM43hCyrzj5hJNitbxLkzjww7iygpoWXT7sege-5eySEaKmcRxQ==\n<\n{\"supportID\": \"4099392564272510395\"}\n* Connection #0 to host api.cloud-app.uk left intact\n\n
\n\n

This can be checked in the NGINX App Protect security logs displayed in Kibana NGINX App Protect dashboards, running in AWS ElasticSearch:

\n\n

\n\n

The bot defense behavior can be controlled from the policy file under the CodeCommit repository. Changing the action from \"block\" to \"alarm\" for \"untrusted bot\" and commiting the change will trigger the pipeline to redeploy the NGINX App Protect policy:

\n\n
\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: nap-api-policy\n  namespace: default\ndata:\n  NAP_API_Policy.json: |+\n    {\n        \"policy\": {\n            \"name\": \"policy_name\",\n            \"template\": { \"name\": \"POLICY_TEMPLATE_NGINX_BASE\" },\n            \"applicationLanguage\": \"utf-8\",\n            \"enforcementMode\": \"blocking\",\n            \"signature-sets\": [\n                {\n                    \"name\": \"High Accuracy Signatures\",\n                    \"block\": true,\n                    \"alarm\": true\n                }\n            ],\n            \"bot-defense\": {\n                \"settings\": {\n                    \"isEnabled\": true\n                },\n                \"mitigations\": {\n                    \"classes\": [\n                        {\n                            \"name\": \"trusted-bot\",\n                            \"action\": \"alarm\"\n                        },\n                        {\n                            \"name\": \"untrusted-bot\",\n                            \"action\": \"block\"\n                        },\n                        {\n                            \"name\": \"malicious-bot\",\n                            \"action\": \"block\"\n                        }\n                    ]\n                }\n            },\n...............................................................................................................\n\n
\n\n

The same Curl call is now being allowed:

\n\n
\ncurl -vvvk https://api.cloud-app.uk/api/rest/execute_money_transfer.php -d '{\"account\": 2075894, \"amount\": 1, \"currency\": \"GBP\", \"friend\": \"Vincent\"}' -H \"Content-Type: application/json\" -X POST\nNote: Unnecessary use of -X or --request, POST is already inferred.\n*   Trying 143.204.192.29...\n* TCP_NODELAY set\n* Connected to api.cloud-app.uk (143.204.192.29) port 443 (#0)\n* ALPN, offering h2\n* ALPN, offering http/1.1\n* successfully set certificate verify locations:\n*   CAfile: /etc/ssl/cert.pem\n  CApath: none\n* TLSv1.2 (OUT), TLS handshake, Client hello (1):\n* TLSv1.2 (IN), TLS handshake, Server hello (2):\n* TLSv1.2 (IN), TLS handshake, Certificate (11):\n* TLSv1.2 (IN), TLS handshake, Server key exchange (12):\n* TLSv1.2 (IN), TLS handshake, Server finished (14):\n* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):\n* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):\n* TLSv1.2 (OUT), TLS handshake, Finished (20):\n* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):\n* TLSv1.2 (IN), TLS handshake, Finished (20):\n* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256\n* ALPN, server accepted to use h2\n* Server certificate:\n*  subject: CN=*.cloud-app.uk\n*  start date: Nov 18 00:00:00 2020 GMT\n*  expire date: Dec 17 23:59:59 2021 GMT\n*  issuer: C=US; O=Amazon; OU=Server CA 1B; CN=Amazon\n*  SSL certificate verify ok.\n* Using HTTP2, server supports multi-use\n* Connection state changed (HTTP/2 confirmed)\n* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0\n* Using Stream ID: 1 (easy handle 0x7fc877008200)\n> POST /api/rest/execute_money_transfer.php HTTP/2\n> Host: api.cloud-app.uk\n> User-Agent: curl/7.64.1\n> Accept: */*\n> Content-Type: application/json\n> Content-Length: 75\n>\n* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!\n* We are completely uploaded and fine\n< HTTP/2 200\n< content-type: text/html; charset=UTF-8\n< content-length: 155\n< date: Mon, 30 Nov 2020 11:02:19 GMT\n< x-amzn-requestid: 9bdb2379-06c4-4970-a528-cd8de9cb75b3\n< x-amzn-remapped-content-length: 155\n< x-amzn-remapped-connection: keep-alive\n< x-amz-apigw-id: W0WhMH_TvHcFndQ=\n< x-amzn-remapped-server: nginx/1.19.3\n< vary: Accept-Encoding\n< x-amzn-remapped-date: Mon, 30 Nov 2020 11:02:19 GMT\n< x-cache: Miss from cloudfront\n< via: 1.1 bb501579906725a97059c817430425cf.cloudfront.net (CloudFront)\n< x-amz-cf-pop: LHR3-C1\n< x-amz-cf-id: xo4zfKVqUeejkHzLPArADi1rxRxTJkg61YgfhruAR4KjdpMSnYymkQ==\n<\n* Connection #0 to host api.cloud-app.uk left intact\n{\"name\":\"Vincent\", \"status\":\"success\",\"amount\":\"1\", \"currency\":\"GBP\", \"transid\":\"753910682\", \"msg\":\"The money transfer has been successfully completed \"}* Closing connection 0\n\n
\n\n

The new bot defense behavior can be checked in the NGINX App Protect Kibana dashboard:

\n\n

\n\n

Conclusion

\n\n

To recap, this article has demoed the per-service model of deployment for NGINX App Protect in Kubernetes environment. The main advantage of this deployment model is the independent management of security policies and the portability of each security policy.

\n\n

NGINX App Protect elevates the security level provided by the API Gateway by providing negative security and advanced security features like bot detection.

\n\n

The configuration is being controlled by a CI/CD pipeline, in this case AWS CodePipeline, and the same OpenAPI file used to configure the AWS API Gateway is also ingested by the NGINX App Protect API instance.

\n\n

Lastly the security logs sent by NGINX App Protect through Fluentd to AWS ElasticSearch are being displayed in Kibana dashboards.

","kudosSumWeight":1,"postTime":"2021-01-14T17:05:10.000-08:00","images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjUuMnwyLjF8b3wyNXxfTlZffDE","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkwMzYtODA2N2kxQzA1QTY3NDBCQTYxQzdE?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMnwyLjF8b3wyNXxfTlZffDI","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkwMzYtMTI1NTlpRUIxNUY5MEJERDE4NjhFMw?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMnwyLjF8b3wyNXxfTlZffDM","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkwMzYtMzMwNWlGMTE2NzRGMDY2RTUzMzgy?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMnwyLjF8b3wyNXxfTlZffDQ","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkwMzYtMTA2MzhpNjBCMTNBMDAyMkE1OTQ1Mw?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjUuMnwyLjF8b3wyNXxfTlZffDU","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkwMzYtMTQwNTNpOTFCNkFBNTIyQjk2REQ3Qw?revision=1\"}"}}],"totalCount":5,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"attachments":{"__typename":"AttachmentConnection","pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null},"edges":[]},"tags":{"__typename":"TagConnection","pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null},"edges":[{"__typename":"TagEdge","cursor":"MjUuMnwyLjF8b3wxMHxfTlZffDE","node":{"__typename":"Tag","id":"tag:api gateway","text":"api gateway","time":"2022-01-24T02:30:10.878-08:00","lastActivityTime":null,"messagesCount":null,"followersCount":null}},{"__typename":"TagEdge","cursor":"MjUuMnwyLjF8b3wxMHxfTlZffDI","node":{"__typename":"Tag","id":"tag:AWS","text":"AWS","time":"2022-01-24T02:29:54.659-08:00","lastActivityTime":null,"messagesCount":null,"followersCount":null}},{"__typename":"TagEdge","cursor":"MjUuMnwyLjF8b3wxMHxfTlZffDM","node":{"__typename":"Tag","id":"tag:CICD","text":"CICD","time":"2022-01-24T02:33:38.911-08:00","lastActivityTime":null,"messagesCount":null,"followersCount":null}},{"__typename":"TagEdge","cursor":"MjUuMnwyLjF8b3wxMHxfTlZffDQ","node":{"__typename":"Tag","id":"tag:cloud","text":"cloud","time":"2016-05-10T00:36:43.000-07:00","lastActivityTime":null,"messagesCount":null,"followersCount":null}},{"__typename":"TagEdge","cursor":"MjUuMnwyLjF8b3wxMHxfTlZffDU","node":{"__typename":"Tag","id":"tag:NGINX WAF","text":"NGINX WAF","time":"2022-01-24T02:31:33.979-08:00","lastActivityTime":null,"messagesCount":null,"followersCount":null}},{"__typename":"TagEdge","cursor":"MjUuMnwyLjF8b3wxMHxfTlZffDY","node":{"__typename":"Tag","id":"tag:security","text":"security","time":"2009-07-03T08:19:36.000-07:00","lastActivityTime":null,"messagesCount":null,"followersCount":null}},{"__typename":"TagEdge","cursor":"MjUuMnwyLjF8b3wxMHxfTlZffDc","node":{"__typename":"Tag","id":"tag:series-api-security","text":"series-api-security","time":"2022-02-07T14:23:11.339-08:00","lastActivityTime":null,"messagesCount":null,"followersCount":null}}]},"timeToRead":15,"rawTeaser":"","introduction":"","currentRevision":{"__ref":"Revision:revision:289036_1"},"latestVersion":{"__typename":"FriendlyVersion","major":"1","minor":"0"},"metrics":{"__typename":"MessageMetrics","views":2114},"visibilityScope":"PUBLIC","canonicalUrl":null,"seoTitle":null,"seoDescription":null,"placeholder":false,"originalMessageForPlaceholder":null,"contributors":{"__typename":"UserConnection","edges":[]},"nonCoAuthorContributors":{"__typename":"UserConnection","edges":[]},"coAuthors":{"__typename":"UserConnection","edges":[{"__typename":"UserEdge","node":{"__ref":"User:user:305638"}}]},"tkbMessagePolicies":{"__typename":"TkbMessagePolicies","canDoAuthoringActionsOnTkb":{"__typename":"PolicyResult","failureReason":{"__typename":"FailureReason","message":"error.lithium.policies.tkb.policy_can_do_authoring_action.accessDenied","key":"error.lithium.policies.tkb.policy_can_do_authoring_action.accessDenied","args":[]}}},"archivalData":null,"replies":{"__typename":"MessageConnection","edges":[],"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"customFields":[],"revisions({\"constraints\":{\"isPublished\":{\"eq\":true}},\"first\":1})":{"__typename":"RevisionConnection","totalCount":1}},"Conversation:conversation:289036":{"__typename":"Conversation","id":"conversation:289036","solved":false,"topic":{"__ref":"TkbTopicMessage:message:289036"},"lastPostingActivityTime":"2021-01-14T17:05:10.000-08:00","lastPostTime":"2021-01-14T17:05:10.000-08:00","unreadReplyCount":0,"isSubscribed":false},"ModerationData:moderation_data:289036":{"__typename":"ModerationData","id":"moderation_data:289036","status":"APPROVED","rejectReason":null,"isReportedAbuse":false,"rejectUser":null,"rejectTime":null,"rejectActorType":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkwMzYtODA2N2kxQzA1QTY3NDBCQTYxQzdE?revision=1\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkwMzYtODA2N2kxQzA1QTY3NDBCQTYxQzdE?revision=1","title":"0EM1T000002KG7B.png","associationType":"BODY","width":2104,"height":1184,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkwMzYtMTI1NTlpRUIxNUY5MEJERDE4NjhFMw?revision=1\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkwMzYtMTI1NTlpRUIxNUY5MEJERDE4NjhFMw?revision=1","title":"0151T000003q3KwQAI.png","associationType":"BODY","width":1000,"height":601,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkwMzYtMzMwNWlGMTE2NzRGMDY2RTUzMzgy?revision=1\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkwMzYtMzMwNWlGMTE2NzRGMDY2RTUzMzgy?revision=1","title":"0151T000003q3L6QAI.png","associationType":"BODY","width":1000,"height":602,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkwMzYtMTA2MzhpNjBCMTNBMDAyMkE1OTQ1Mw?revision=1\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkwMzYtMTA2MzhpNjBCMTNBMDAyMkE1OTQ1Mw?revision=1","title":"0151T000003q3LzQAI.png","associationType":"BODY","width":3240,"height":644,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkwMzYtMTQwNTNpOTFCNkFBNTIyQjk2REQ3Qw?revision=1\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODkwMzYtMTQwNTNpOTFCNkFBNTIyQjk2REQ3Qw?revision=1","title":"0151T000003q4aOQAQ.png","associationType":"BODY","width":3200,"height":824,"altText":null},"Revision:revision:289036_1":{"__typename":"Revision","id":"revision:289036_1","lastEditTime":"2021-01-14T17:05:10.000-08:00"},"CachedAsset:theme:customTheme1-1741994701376":{"__typename":"CachedAsset","id":"theme:customTheme1-1741994701376","value":{"id":"customTheme1","animation":{"fast":"150ms","normal":"250ms","slow":"500ms","slowest":"750ms","function":"cubic-bezier(0.07, 0.91, 0.51, 1)","__typename":"AnimationThemeSettings"},"avatar":{"borderRadius":"50%","collections":["custom"],"__typename":"AvatarThemeSettings"},"basics":{"browserIcon":{"imageAssetName":"JimmyPackets-512-1702592938213.png","imageLastModified":"1702592945815","__typename":"ThemeAsset"},"customerLogo":{"imageAssetName":"f5_logo_fix-1704824537976.svg","imageLastModified":"1704824540697","__typename":"ThemeAsset"},"maximumWidthOfPageContent":"1600px","oneColumnNarrowWidth":"800px","gridGutterWidthMd":"30px","gridGutterWidthXs":"10px","pageWidthStyle":"WIDTH_OF_PAGE_CONTENT","__typename":"BasicsThemeSettings"},"buttons":{"borderRadiusSm":"5px","borderRadius":"5px","borderRadiusLg":"5px","paddingY":"5px","paddingYLg":"7px","paddingYHero":"var(--lia-bs-btn-padding-y-lg)","paddingX":"12px","paddingXLg":"14px","paddingXHero":"42px","fontStyle":"NORMAL","fontWeight":"400","textTransform":"NONE","disabledOpacity":0.5,"primaryTextColor":"var(--lia-bs-white)","primaryTextHoverColor":"var(--lia-bs-white)","primaryTextActiveColor":"var(--lia-bs-white)","primaryBgColor":"var(--lia-bs-primary)","primaryBgHoverColor":"hsl(var(--lia-bs-primary-h), var(--lia-bs-primary-s), calc(var(--lia-bs-primary-l) * 0.85))","primaryBgActiveColor":"hsl(var(--lia-bs-primary-h), var(--lia-bs-primary-s), calc(var(--lia-bs-primary-l) * 0.7))","primaryBorder":"1px solid transparent","primaryBorderHover":"1px solid transparent","primaryBorderActive":"1px solid transparent","primaryBorderFocus":"1px solid var(--lia-bs-white)","primaryBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","secondaryTextColor":"var(--lia-bs-gray-900)","secondaryTextHoverColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.95))","secondaryTextActiveColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.9))","secondaryBgColor":"var(--lia-bs-gray-400)","secondaryBgHoverColor":"hsl(var(--lia-bs-gray-400-h), var(--lia-bs-gray-400-s), calc(var(--lia-bs-gray-400-l) * 0.96))","secondaryBgActiveColor":"hsl(var(--lia-bs-gray-400-h), var(--lia-bs-gray-400-s), calc(var(--lia-bs-gray-400-l) * 0.92))","secondaryBorder":"1px solid transparent","secondaryBorderHover":"1px solid transparent","secondaryBorderActive":"1px solid transparent","secondaryBorderFocus":"1px solid transparent","secondaryBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","tertiaryTextColor":"var(--lia-bs-gray-900)","tertiaryTextHoverColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.95))","tertiaryTextActiveColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.9))","tertiaryBgColor":"transparent","tertiaryBgHoverColor":"transparent","tertiaryBgActiveColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.04)","tertiaryBorder":"1px solid transparent","tertiaryBorderHover":"1px solid hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","tertiaryBorderActive":"1px solid transparent","tertiaryBorderFocus":"1px solid transparent","tertiaryBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","destructiveTextColor":"var(--lia-bs-danger)","destructiveTextHoverColor":"hsl(var(--lia-bs-danger-h), var(--lia-bs-danger-s), calc(var(--lia-bs-danger-l) * 0.95))","destructiveTextActiveColor":"hsl(var(--lia-bs-danger-h), var(--lia-bs-danger-s), calc(var(--lia-bs-danger-l) * 0.9))","destructiveBgColor":"var(--lia-bs-gray-300)","destructiveBgHoverColor":"hsl(var(--lia-bs-gray-300-h), var(--lia-bs-gray-300-s), calc(var(--lia-bs-gray-300-l) * 0.96))","destructiveBgActiveColor":"hsl(var(--lia-bs-gray-300-h), var(--lia-bs-gray-300-s), calc(var(--lia-bs-gray-300-l) * 0.92))","destructiveBorder":"1px solid transparent","destructiveBorderHover":"1px solid transparent","destructiveBorderActive":"1px solid transparent","destructiveBorderFocus":"1px solid transparent","destructiveBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","__typename":"ButtonsThemeSettings"},"border":{"color":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","mainContent":"NONE","sideContent":"NONE","radiusSm":"3px","radius":"5px","radiusLg":"9px","radius50":"100vw","__typename":"BorderThemeSettings"},"boxShadow":{"xs":"0 0 0 1px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.08), 0 3px 0 -1px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.08)","sm":"0 2px 4px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.06)","md":"0 5px 15px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.15)","lg":"0 10px 30px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.15)","__typename":"BoxShadowThemeSettings"},"cards":{"bgColor":"var(--lia-panel-bg-color)","borderRadius":"var(--lia-panel-border-radius)","boxShadow":"var(--lia-box-shadow-xs)","__typename":"CardsThemeSettings"},"chip":{"maxWidth":"300px","height":"30px","__typename":"ChipThemeSettings"},"coreTypes":{"defaultMessageLinkColor":"var(--lia-bs-primary)","defaultMessageLinkDecoration":"none","defaultMessageLinkFontStyle":"NORMAL","defaultMessageLinkFontWeight":"400","defaultMessageFontStyle":"NORMAL","defaultMessageFontWeight":"400","forumColor":"#0C5C8D","forumFontFamily":"var(--lia-bs-font-family-base)","forumFontWeight":"var(--lia-default-message-font-weight)","forumLineHeight":"var(--lia-bs-line-height-base)","forumFontStyle":"var(--lia-default-message-font-style)","forumMessageLinkColor":"var(--lia-default-message-link-color)","forumMessageLinkDecoration":"var(--lia-default-message-link-decoration)","forumMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","forumMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","forumSolvedColor":"#62C026","blogColor":"#730015","blogFontFamily":"var(--lia-bs-font-family-base)","blogFontWeight":"var(--lia-default-message-font-weight)","blogLineHeight":"1.75","blogFontStyle":"var(--lia-default-message-font-style)","blogMessageLinkColor":"var(--lia-default-message-link-color)","blogMessageLinkDecoration":"var(--lia-default-message-link-decoration)","blogMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","blogMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","tkbColor":"#C20025","tkbFontFamily":"var(--lia-bs-font-family-base)","tkbFontWeight":"var(--lia-default-message-font-weight)","tkbLineHeight":"1.75","tkbFontStyle":"var(--lia-default-message-font-style)","tkbMessageLinkColor":"var(--lia-default-message-link-color)","tkbMessageLinkDecoration":"var(--lia-default-message-link-decoration)","tkbMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","tkbMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","qandaColor":"#4099E2","qandaFontFamily":"var(--lia-bs-font-family-base)","qandaFontWeight":"var(--lia-default-message-font-weight)","qandaLineHeight":"var(--lia-bs-line-height-base)","qandaFontStyle":"var(--lia-default-message-link-font-style)","qandaMessageLinkColor":"var(--lia-default-message-link-color)","qandaMessageLinkDecoration":"var(--lia-default-message-link-decoration)","qandaMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","qandaMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","qandaSolvedColor":"#3FA023","ideaColor":"#F3704B","ideaFontFamily":"var(--lia-bs-font-family-base)","ideaFontWeight":"var(--lia-default-message-font-weight)","ideaLineHeight":"var(--lia-bs-line-height-base)","ideaFontStyle":"var(--lia-default-message-font-style)","ideaMessageLinkColor":"var(--lia-default-message-link-color)","ideaMessageLinkDecoration":"var(--lia-default-message-link-decoration)","ideaMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","ideaMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","contestColor":"#FCC845","contestFontFamily":"var(--lia-bs-font-family-base)","contestFontWeight":"var(--lia-default-message-font-weight)","contestLineHeight":"var(--lia-bs-line-height-base)","contestFontStyle":"var(--lia-default-message-link-font-style)","contestMessageLinkColor":"var(--lia-default-message-link-color)","contestMessageLinkDecoration":"var(--lia-default-message-link-decoration)","contestMessageLinkFontStyle":"ITALIC","contestMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","occasionColor":"#EE4B5B","occasionFontFamily":"var(--lia-bs-font-family-base)","occasionFontWeight":"var(--lia-default-message-font-weight)","occasionLineHeight":"var(--lia-bs-line-height-base)","occasionFontStyle":"var(--lia-default-message-font-style)","occasionMessageLinkColor":"var(--lia-default-message-link-color)","occasionMessageLinkDecoration":"var(--lia-default-message-link-decoration)","occasionMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","occasionMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","grouphubColor":"#491B62","categoryColor":"#949494","communityColor":"#FFFFFF","productColor":"#949494","__typename":"CoreTypesThemeSettings"},"colors":{"black":"#000000","white":"#FFFFFF","gray100":"#F7F7F7","gray200":"#F7F7F7","gray300":"#E8E8E8","gray400":"#D9D9D9","gray500":"#CCCCCC","gray600":"#949494","gray700":"#707070","gray800":"#545454","gray900":"#333333","dark":"#545454","light":"#F7F7F7","primary":"#0C5C8D","secondary":"#333333","bodyText":"#222222","bodyBg":"#F5F5F5","info":"#1D9CD3","success":"#62C026","warning":"#FFD651","danger":"#C20025","alertSystem":"#FF6600","textMuted":"#707070","highlight":"#FFFCAD","outline":"var(--lia-bs-primary)","custom":["#C20025","#081B85","#009639","#B3C6D7","#7CC0EB","#F29A36"],"__typename":"ColorsThemeSettings"},"divider":{"size":"3px","marginLeft":"4px","marginRight":"4px","borderRadius":"50%","bgColor":"var(--lia-bs-gray-600)","bgColorActive":"var(--lia-bs-gray-600)","__typename":"DividerThemeSettings"},"dropdown":{"fontSize":"var(--lia-bs-font-size-sm)","borderColor":"var(--lia-bs-border-color)","borderRadius":"var(--lia-bs-border-radius-sm)","dividerBg":"var(--lia-bs-gray-300)","itemPaddingY":"5px","itemPaddingX":"20px","headerColor":"var(--lia-bs-gray-700)","__typename":"DropdownThemeSettings"},"email":{"link":{"color":"#0069D4","hoverColor":"#0061c2","decoration":"none","hoverDecoration":"underline","__typename":"EmailLinkSettings"},"border":{"color":"#e4e4e4","__typename":"EmailBorderSettings"},"buttons":{"borderRadiusLg":"5px","paddingXLg":"16px","paddingYLg":"7px","fontWeight":"700","primaryTextColor":"#ffffff","primaryTextHoverColor":"#ffffff","primaryBgColor":"#0069D4","primaryBgHoverColor":"#005cb8","primaryBorder":"1px solid transparent","primaryBorderHover":"1px solid transparent","__typename":"EmailButtonsSettings"},"panel":{"borderRadius":"5px","borderColor":"#e4e4e4","__typename":"EmailPanelSettings"},"__typename":"EmailThemeSettings"},"emoji":{"skinToneDefault":"#ffcd43","skinToneLight":"#fae3c5","skinToneMediumLight":"#e2cfa5","skinToneMedium":"#daa478","skinToneMediumDark":"#a78058","skinToneDark":"#5e4d43","__typename":"EmojiThemeSettings"},"heading":{"color":"var(--lia-bs-body-color)","fontFamily":"Inter","fontStyle":"NORMAL","fontWeight":"600","h1FontSize":"30px","h2FontSize":"25px","h3FontSize":"20px","h4FontSize":"18px","h5FontSize":"16px","h6FontSize":"16px","lineHeight":"1.2","subHeaderFontSize":"11px","subHeaderFontWeight":"500","h1LetterSpacing":"normal","h2LetterSpacing":"normal","h3LetterSpacing":"normal","h4LetterSpacing":"normal","h5LetterSpacing":"normal","h6LetterSpacing":"normal","subHeaderLetterSpacing":"2px","h1FontWeight":"var(--lia-bs-headings-font-weight)","h2FontWeight":"var(--lia-bs-headings-font-weight)","h3FontWeight":"var(--lia-bs-headings-font-weight)","h4FontWeight":"var(--lia-bs-headings-font-weight)","h5FontWeight":"var(--lia-bs-headings-font-weight)","h6FontWeight":"var(--lia-bs-headings-font-weight)","__typename":"HeadingThemeSettings"},"icons":{"size10":"10px","size12":"12px","size14":"14px","size16":"16px","size20":"20px","size24":"24px","size30":"30px","size40":"40px","size50":"50px","size60":"60px","size80":"80px","size120":"120px","size160":"160px","__typename":"IconsThemeSettings"},"imagePreview":{"bgColor":"var(--lia-bs-gray-900)","titleColor":"var(--lia-bs-white)","controlColor":"var(--lia-bs-white)","controlBgColor":"var(--lia-bs-gray-800)","__typename":"ImagePreviewThemeSettings"},"input":{"borderColor":"var(--lia-bs-gray-600)","disabledColor":"var(--lia-bs-gray-600)","focusBorderColor":"var(--lia-bs-primary)","labelMarginBottom":"10px","btnFontSize":"var(--lia-bs-font-size-sm)","focusBoxShadow":"0 0 0 3px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","checkLabelMarginBottom":"2px","checkboxBorderRadius":"3px","borderRadiusSm":"var(--lia-bs-border-radius-sm)","borderRadius":"var(--lia-bs-border-radius)","borderRadiusLg":"var(--lia-bs-border-radius-lg)","formTextMarginTop":"4px","textAreaBorderRadius":"var(--lia-bs-border-radius)","activeFillColor":"var(--lia-bs-primary)","__typename":"InputThemeSettings"},"loading":{"dotDarkColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.2)","dotLightColor":"hsla(var(--lia-bs-white-h), var(--lia-bs-white-s), var(--lia-bs-white-l), 0.5)","barDarkColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.06)","barLightColor":"hsla(var(--lia-bs-white-h), var(--lia-bs-white-s), var(--lia-bs-white-l), 0.4)","__typename":"LoadingThemeSettings"},"link":{"color":"var(--lia-bs-primary)","hoverColor":"hsl(var(--lia-bs-primary-h), var(--lia-bs-primary-s), calc(var(--lia-bs-primary-l) - 10%))","decoration":"none","hoverDecoration":"underline","__typename":"LinkThemeSettings"},"listGroup":{"itemPaddingY":"15px","itemPaddingX":"15px","borderColor":"var(--lia-bs-gray-300)","__typename":"ListGroupThemeSettings"},"modal":{"contentTextColor":"var(--lia-bs-body-color)","contentBg":"var(--lia-bs-white)","backgroundBg":"var(--lia-bs-black)","smSize":"440px","mdSize":"760px","lgSize":"1080px","backdropOpacity":0.3,"contentBoxShadowXs":"var(--lia-bs-box-shadow-sm)","contentBoxShadow":"var(--lia-bs-box-shadow)","headerFontWeight":"700","__typename":"ModalThemeSettings"},"navbar":{"position":"FIXED","background":{"attachment":null,"clip":null,"color":"var(--lia-bs-white)","imageAssetName":null,"imageLastModified":"0","origin":null,"position":"CENTER_CENTER","repeat":"NO_REPEAT","size":"COVER","__typename":"BackgroundProps"},"backgroundOpacity":0.8,"paddingTop":"15px","paddingBottom":"15px","borderBottom":"1px solid var(--lia-bs-border-color)","boxShadow":"var(--lia-bs-box-shadow-sm)","brandMarginRight":"30px","brandMarginRightSm":"10px","brandLogoHeight":"30px","linkGap":"10px","linkJustifyContent":"flex-start","linkPaddingY":"5px","linkPaddingX":"10px","linkDropdownPaddingY":"9px","linkDropdownPaddingX":"var(--lia-nav-link-px)","linkColor":"var(--lia-bs-body-color)","linkHoverColor":"var(--lia-bs-primary)","linkFontSize":"var(--lia-bs-font-size-sm)","linkFontStyle":"NORMAL","linkFontWeight":"400","linkTextTransform":"NONE","linkLetterSpacing":"normal","linkBorderRadius":"var(--lia-bs-border-radius-sm)","linkBgColor":"transparent","linkBgHoverColor":"transparent","linkBorder":"none","linkBorderHover":"none","linkBoxShadow":"none","linkBoxShadowHover":"none","linkTextBorderBottom":"none","linkTextBorderBottomHover":"none","dropdownPaddingTop":"10px","dropdownPaddingBottom":"15px","dropdownPaddingX":"10px","dropdownMenuOffset":"2px","dropdownDividerMarginTop":"10px","dropdownDividerMarginBottom":"10px","dropdownBorderColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","controllerBgHoverColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.1)","controllerIconColor":"var(--lia-bs-body-color)","controllerIconHoverColor":"var(--lia-bs-body-color)","controllerTextColor":"var(--lia-nav-controller-icon-color)","controllerTextHoverColor":"var(--lia-nav-controller-icon-hover-color)","controllerHighlightColor":"hsla(30, 100%, 50%)","controllerHighlightTextColor":"var(--lia-yiq-light)","controllerBorderRadius":"var(--lia-border-radius-50)","hamburgerColor":"var(--lia-nav-controller-icon-color)","hamburgerHoverColor":"var(--lia-nav-controller-icon-color)","hamburgerBgColor":"transparent","hamburgerBgHoverColor":"transparent","hamburgerBorder":"none","hamburgerBorderHover":"none","collapseMenuMarginLeft":"20px","collapseMenuDividerBg":"var(--lia-nav-link-color)","collapseMenuDividerOpacity":0.16,"__typename":"NavbarThemeSettings"},"pager":{"textColor":"var(--lia-bs-link-color)","textFontWeight":"var(--lia-font-weight-md)","textFontSize":"var(--lia-bs-font-size-sm)","__typename":"PagerThemeSettings"},"panel":{"bgColor":"var(--lia-bs-white)","borderRadius":"var(--lia-bs-border-radius)","borderColor":"var(--lia-bs-border-color)","boxShadow":"none","__typename":"PanelThemeSettings"},"popover":{"arrowHeight":"8px","arrowWidth":"16px","maxWidth":"300px","minWidth":"100px","headerBg":"var(--lia-bs-white)","borderColor":"var(--lia-bs-border-color)","borderRadius":"var(--lia-bs-border-radius)","boxShadow":"0 0.5rem 1rem hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.15)","__typename":"PopoverThemeSettings"},"prism":{"color":"#000000","bgColor":"#f5f2f0","fontFamily":"var(--font-family-monospace)","fontSize":"var(--lia-bs-font-size-base)","fontWeightBold":"var(--lia-bs-font-weight-bold)","fontStyleItalic":"italic","tabSize":2,"highlightColor":"#b3d4fc","commentColor":"#62707e","punctuationColor":"#6f6f6f","namespaceOpacity":"0.7","propColor":"#990055","selectorColor":"#517a00","operatorColor":"#906736","operatorBgColor":"hsla(0, 0%, 100%, 0.5)","keywordColor":"#0076a9","functionColor":"#d3284b","variableColor":"#c14700","__typename":"PrismThemeSettings"},"rte":{"bgColor":"var(--lia-bs-white)","borderRadius":"var(--lia-panel-border-radius)","boxShadow":" var(--lia-panel-box-shadow)","customColor1":"#bfedd2","customColor2":"#fbeeb8","customColor3":"#f8cac6","customColor4":"#eccafa","customColor5":"#c2e0f4","customColor6":"#2dc26b","customColor7":"#f1c40f","customColor8":"#e03e2d","customColor9":"#b96ad9","customColor10":"#3598db","customColor11":"#169179","customColor12":"#e67e23","customColor13":"#ba372a","customColor14":"#843fa1","customColor15":"#236fa1","customColor16":"#ecf0f1","customColor17":"#ced4d9","customColor18":"#95a5a6","customColor19":"#7e8c8d","customColor20":"#34495e","customColor21":"#000000","customColor22":"#ffffff","defaultMessageHeaderMarginTop":"14px","defaultMessageHeaderMarginBottom":"10px","defaultMessageItemMarginTop":"0","defaultMessageItemMarginBottom":"10px","diffAddedColor":"hsla(170, 53%, 51%, 0.4)","diffChangedColor":"hsla(43, 97%, 63%, 0.4)","diffNoneColor":"hsla(0, 0%, 80%, 0.4)","diffRemovedColor":"hsla(9, 74%, 47%, 0.4)","specialMessageHeaderMarginTop":"14px","specialMessageHeaderMarginBottom":"10px","specialMessageItemMarginTop":"0","specialMessageItemMarginBottom":"10px","__typename":"RteThemeSettings"},"tags":{"bgColor":"var(--lia-bs-gray-200)","bgHoverColor":"var(--lia-bs-gray-400)","borderRadius":"var(--lia-bs-border-radius-sm)","color":"var(--lia-bs-body-color)","hoverColor":"var(--lia-bs-body-color)","fontWeight":"var(--lia-font-weight-md)","fontSize":"var(--lia-font-size-xxs)","textTransform":"UPPERCASE","letterSpacing":"0.5px","__typename":"TagsThemeSettings"},"toasts":{"borderRadius":"var(--lia-bs-border-radius)","paddingX":"12px","__typename":"ToastsThemeSettings"},"typography":{"fontFamilyBase":"Atkinson Hyperlegible","fontStyleBase":"NORMAL","fontWeightBase":"400","fontWeightLight":"300","fontWeightNormal":"400","fontWeightMd":"500","fontWeightBold":"700","letterSpacingSm":"normal","letterSpacingXs":"normal","lineHeightBase":"1.3","fontSizeBase":"15px","fontSizeXxs":"11px","fontSizeXs":"12px","fontSizeSm":"13px","fontSizeLg":"20px","fontSizeXl":"24px","smallFontSize":"14px","customFonts":[],"__typename":"TypographyThemeSettings"},"unstyledListItem":{"marginBottomSm":"5px","marginBottomMd":"10px","marginBottomLg":"15px","marginBottomXl":"20px","marginBottomXxl":"25px","__typename":"UnstyledListItemThemeSettings"},"yiq":{"light":"#ffffff","dark":"#000000","__typename":"YiqThemeSettings"},"colorLightness":{"primaryDark":0.36,"primaryLight":0.74,"primaryLighter":0.89,"primaryLightest":0.95,"infoDark":0.39,"infoLight":0.72,"infoLighter":0.85,"infoLightest":0.93,"successDark":0.24,"successLight":0.62,"successLighter":0.8,"successLightest":0.91,"warningDark":0.39,"warningLight":0.68,"warningLighter":0.84,"warningLightest":0.93,"dangerDark":0.41,"dangerLight":0.72,"dangerLighter":0.89,"dangerLightest":0.95,"__typename":"ColorLightnessThemeSettings"},"localOverride":false,"__typename":"Theme"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/Loading/LoadingDot-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/Loading/LoadingDot-1740415735000","value":{"title":"Loading..."},"localOverride":false},"CachedAsset:quilt:f5.prod:pages/kbs/TkbMessagePage:board:TechnicalArticles-1741994699732":{"__typename":"CachedAsset","id":"quilt:f5.prod:pages/kbs/TkbMessagePage:board:TechnicalArticles-1741994699732","value":{"id":"TkbMessagePage","container":{"id":"Common","headerProps":{"backgroundImageProps":null,"backgroundColor":null,"addComponents":null,"removeComponents":["community.widget.bannerWidget"],"componentOrder":null,"__typename":"QuiltContainerSectionProps"},"headerComponentProps":{"community.widget.breadcrumbWidget":{"disableLastCrumbForDesktop":false}},"footerProps":null,"footerComponentProps":null,"items":[{"id":"message-list","layout":"MAIN_SIDE","bgColor":"transparent","showTitle":true,"showDescription":true,"textPosition":"CENTER","textColor":"var(--lia-bs-body-color)","sectionEditLevel":null,"bgImage":null,"disableSpacing":null,"edgeToEdgeDisplay":null,"fullHeight":null,"showBorder":null,"__typename":"MainSideQuiltSection","columnMap":{"main":[{"id":"tkbs.widget.tkbArticleWidget","className":"lia-tkb-container","props":{"contributorListType":"panel","showHelpfulness":false,"showTimestamp":true,"showGuideNavigationSection":true,"showVersion":true,"lazyLoad":false,"editLevel":"CONFIGURE"},"__typename":"QuiltComponent"}],"side":[{"id":"featuredWidgets.widget.featuredContentWidget","className":null,"props":{"instanceId":"featuredWidgets.widget.featuredContentWidget-1702666556326","layoutProps":{"layout":"card","layoutOptions":{"useRepliesCount":false,"useAuthorRank":false,"useTimeToRead":true,"useKudosCount":false,"useViewCount":true,"usePreviewMedia":true,"useBody":false,"useCenteredCardContent":false,"useTags":true,"useTimestamp":false,"useBoardLink":true,"useAuthorLink":false,"useSolvedBadge":true}},"titleSrOnly":false,"showPager":true,"pageSize":3,"lazyLoad":true},"__typename":"QuiltComponent"},{"id":"messages.widget.relatedContentWidget","className":null,"props":{"hideIfEmpty":true,"enablePagination":true,"useTitle":true,"listVariant":{"type":"listGroup"},"pageSize":3,"style":"list","pagerVariant":{"type":"loadMore"},"viewVariant":{"type":"inline","props":{"useRepliesCount":true,"useMedia":true,"useAuthorRank":false,"useNode":true,"useTimeToRead":true,"useSpoilerFreeBody":true,"useKudosCount":true,"useNodeLink":true,"useViewCount":true,"usePreviewMedia":false,"useBody":false,"timeStampType":"postTime","useTags":true,"clampSubjectLines":2,"useBoardIcon":false,"useMessageTimeLink":true,"clampBodyLines":3,"useTextBody":true,"useSolvedBadge":true,"useAvatar":true,"useAuthorLogin":true,"useUnreadCount":true}},"lazyLoad":true,"panelType":"divider"},"__typename":"QuiltComponent"}],"__typename":"MainSideSectionColumns"}}],"__typename":"QuiltContainer"},"__typename":"Quilt","localOverride":false},"localOverride":false},"CachedAsset:text:en_US-components/common/EmailVerification-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/common/EmailVerification-1740415735000","value":{"email.verification.title":"Email Verification Required","email.verification.message.update.email":"To participate in the community, you must first verify your email address. The verification email was sent to {email}. To change your email, visit My Settings.","email.verification.message.resend.email":"To participate in the community, you must first verify your email address. The verification email was sent to {email}. Resend email."},"localOverride":false},"CachedAsset:text:en_US-pages/kbs/TkbMessagePage-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-pages/kbs/TkbMessagePage-1740415735000","value":{"title":"{contextMessageSubject} | {communityTitle}","errorMissing":"This article cannot be found","name":"TKB Message Page","section.message-list.title":"","archivedMessageTitle":"This Content Has Been Archived","section.erPqcf.title":"","section.erPqcf.description":"","section.message-list.description":""},"localOverride":false},"CachedAsset:quiltWrapper:f5.prod:Common:1741994620406":{"__typename":"CachedAsset","id":"quiltWrapper:f5.prod:Common:1741994620406","value":{"id":"Common","header":{"backgroundImageProps":{"assetName":"header.jpg","backgroundSize":"COVER","backgroundRepeat":"NO_REPEAT","backgroundPosition":"LEFT_CENTER","lastModified":"1702932449000","__typename":"BackgroundImageProps"},"backgroundColor":"transparent","items":[{"id":"custom.widget.Beta_MetaNav","props":{"widgetVisibility":"signedInOrAnonymous","useTitle":true,"useBackground":false,"title":"","lazyLoad":false},"__typename":"QuiltComponent"},{"id":"community.widget.navbarWidget","props":{"showUserName":false,"showRegisterLink":true,"style":{"boxShadow":"var(--lia-bs-box-shadow-sm)","linkFontWeight":"700","controllerHighlightColor":"hsla(30, 100%, 50%)","dropdownDividerMarginBottom":"10px","hamburgerBorderHover":"none","linkFontSize":"15px","linkBoxShadowHover":"none","backgroundOpacity":0.4,"controllerBorderRadius":"var(--lia-border-radius-50)","hamburgerBgColor":"transparent","linkTextBorderBottom":"none","hamburgerColor":"var(--lia-nav-controller-icon-color)","brandLogoHeight":"48px","linkLetterSpacing":"normal","linkBgHoverColor":"transparent","collapseMenuDividerOpacity":0.16,"paddingBottom":"10px","dropdownPaddingBottom":"15px","dropdownMenuOffset":"2px","hamburgerBgHoverColor":"transparent","borderBottom":"0","hamburgerBorder":"none","dropdownPaddingX":"10px","brandMarginRightSm":"10px","linkBoxShadow":"none","linkJustifyContent":"center","linkColor":"var(--lia-bs-primary)","collapseMenuDividerBg":"var(--lia-nav-link-color)","dropdownPaddingTop":"10px","controllerHighlightTextColor":"var(--lia-yiq-dark)","background":{"imageAssetName":"","color":"var(--lia-bs-white)","size":"COVER","repeat":"NO_REPEAT","position":"CENTER_CENTER","imageLastModified":""},"linkBorderRadius":"var(--lia-bs-border-radius-sm)","linkHoverColor":"var(--lia-bs-primary)","position":"FIXED","linkBorder":"none","linkTextBorderBottomHover":"2px solid #0C5C8D","brandMarginRight":"30px","hamburgerHoverColor":"var(--lia-nav-controller-icon-color)","linkBorderHover":"none","collapseMenuMarginLeft":"20px","linkFontStyle":"NORMAL","linkPaddingX":"10px","paddingTop":"10px","linkPaddingY":"5px","linkTextTransform":"NONE","dropdownBorderColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","controllerBgHoverColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.1)","linkDropdownPaddingX":"var(--lia-nav-link-px)","linkBgColor":"transparent","linkDropdownPaddingY":"9px","controllerIconColor":"#0C5C8D","dropdownDividerMarginTop":"10px","linkGap":"10px","controllerIconHoverColor":"#0C5C8D"},"links":{"sideLinks":[],"mainLinks":[{"children":[{"linkType":"INTERNAL","id":"migrated-link-1","params":{"boardId":"TechnicalForum","categoryId":"Forums"},"routeName":"ForumBoardPage"},{"linkType":"INTERNAL","id":"migrated-link-2","params":{"boardId":"WaterCooler","categoryId":"Forums"},"routeName":"ForumBoardPage"}],"linkType":"INTERNAL","id":"migrated-link-0","params":{"categoryId":"Forums"},"routeName":"CategoryPage"},{"children":[{"linkType":"INTERNAL","id":"migrated-link-4","params":{"boardId":"codeshare","categoryId":"CrowdSRC"},"routeName":"TkbBoardPage"},{"linkType":"INTERNAL","id":"migrated-link-5","params":{"boardId":"communityarticles","categoryId":"CrowdSRC"},"routeName":"TkbBoardPage"}],"linkType":"INTERNAL","id":"migrated-link-3","params":{"categoryId":"CrowdSRC"},"routeName":"CategoryPage"},{"children":[{"linkType":"INTERNAL","id":"migrated-link-7","params":{"boardId":"TechnicalArticles","categoryId":"Articles"},"routeName":"TkbBoardPage"},{"linkType":"INTERNAL","id":"article-series","params":{"boardId":"article-series","categoryId":"Articles"},"routeName":"TkbBoardPage"},{"linkType":"INTERNAL","id":"security-insights","params":{"boardId":"security-insights","categoryId":"Articles"},"routeName":"TkbBoardPage"},{"linkType":"INTERNAL","id":"migrated-link-8","params":{"boardId":"DevCentralNews","categoryId":"Articles"},"routeName":"TkbBoardPage"}],"linkType":"INTERNAL","id":"migrated-link-6","params":{"categoryId":"Articles"},"routeName":"CategoryPage"},{"children":[{"linkType":"INTERNAL","id":"migrated-link-10","params":{"categoryId":"CommunityGroups"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"migrated-link-11","params":{"categoryId":"F5-Groups"},"routeName":"CategoryPage"}],"linkType":"INTERNAL","id":"migrated-link-9","params":{"categoryId":"GroupsCategory"},"routeName":"CategoryPage"},{"children":[],"linkType":"INTERNAL","id":"migrated-link-12","params":{"boardId":"Events","categoryId":"top"},"routeName":"EventBoardPage"},{"children":[],"linkType":"INTERNAL","id":"migrated-link-13","params":{"boardId":"Suggestions","categoryId":"top"},"routeName":"IdeaBoardPage"},{"children":[],"linkType":"EXTERNAL","id":"Common-external-link","url":"https://community.f5.com/c/how-do-i","target":"SELF"}]},"className":"QuiltComponent_lia-component-edit-mode__lQ9Z6","showSearchIcon":false},"__typename":"QuiltComponent"},{"id":"community.widget.bannerWidget","props":{"backgroundColor":"transparent","visualEffects":{"showBottomBorder":false},"backgroundImageProps":{"backgroundSize":"COVER","backgroundPosition":"CENTER_CENTER","backgroundRepeat":"NO_REPEAT"},"fontColor":"#222222"},"__typename":"QuiltComponent"},{"id":"community.widget.breadcrumbWidget","props":{"backgroundColor":"var(--lia-bs-primary)","linkHighlightColor":"#FFFFFF","visualEffects":{"showBottomBorder":false},"backgroundOpacity":60,"linkTextColor":"#FFFFFF"},"__typename":"QuiltComponent"}],"__typename":"QuiltWrapperSection"},"footer":{"backgroundImageProps":{"assetName":null,"backgroundSize":"COVER","backgroundRepeat":"NO_REPEAT","backgroundPosition":"CENTER_CENTER","lastModified":null,"__typename":"BackgroundImageProps"},"backgroundColor":"var(--lia-bs-body-color)","items":[{"id":"custom.widget.Beta_Footer","props":{"widgetVisibility":"signedInOrAnonymous","useTitle":true,"useBackground":false,"title":"","lazyLoad":false},"__typename":"QuiltComponent"},{"id":"custom.widget.Tag_Manager_Helper","props":{"widgetVisibility":"signedInOrAnonymous","useTitle":true,"useBackground":false,"title":"","lazyLoad":false},"__typename":"QuiltComponent"},{"id":"custom.widget.Consent_Blackbar","props":{"widgetVisibility":"signedInOrAnonymous","useTitle":true,"useBackground":false,"title":"","lazyLoad":false},"__typename":"QuiltComponent"}],"__typename":"QuiltWrapperSection"},"__typename":"QuiltWrapper","localOverride":false},"localOverride":false},"CachedAsset:text:en_US-components/common/ActionFeedback-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/common/ActionFeedback-1740415735000","value":{"joinedGroupHub.title":"Welcome","joinedGroupHub.message":"You are now a member of this group and are subscribed to updates.","groupHubInviteNotFound.title":"Invitation Not Found","groupHubInviteNotFound.message":"Sorry, we could not find your invitation to the group. The owner may have canceled the invite.","groupHubNotFound.title":"Group Not Found","groupHubNotFound.message":"The grouphub you tried to join does not exist. It may have been deleted.","existingGroupHubMember.title":"Already Joined","existingGroupHubMember.message":"You are already a member of this group.","accountLocked.title":"Account Locked","accountLocked.message":"Your account has been locked due to multiple failed attempts. Try again in {lockoutTime} minutes.","editedGroupHub.title":"Changes Saved","editedGroupHub.message":"Your group has been updated.","leftGroupHub.title":"Goodbye","leftGroupHub.message":"You are no longer a member of this group and will not receive future updates.","deletedGroupHub.title":"Deleted","deletedGroupHub.message":"The group has been deleted.","groupHubCreated.title":"Group Created","groupHubCreated.message":"{groupHubName} is ready to use","accountClosed.title":"Account Closed","accountClosed.message":"The account has been closed and you will now be redirected to the homepage","resetTokenExpired.title":"Reset Password Link has Expired","resetTokenExpired.message":"Try resetting your password again","invalidUrl.title":"Invalid URL","invalidUrl.message":"The URL you're using is not recognized. Verify your URL and try again.","accountClosedForUser.title":"Account Closed","accountClosedForUser.message":"{userName}'s account is closed","inviteTokenInvalid.title":"Invitation Invalid","inviteTokenInvalid.message":"Your invitation to the community has been canceled or expired.","inviteTokenError.title":"Invitation Verification Failed","inviteTokenError.message":"The url you are utilizing is not recognized. Verify your URL and try again","pageNotFound.title":"Access Denied","pageNotFound.message":"You do not have access to this area of the community or it doesn't exist","eventAttending.title":"Responded as Attending","eventAttending.message":"You'll be notified when there's new activity and reminded as the event approaches","eventInterested.title":"Responded as Interested","eventInterested.message":"You'll be notified when there's new activity and reminded as the event approaches","eventNotFound.title":"Event Not Found","eventNotFound.message":"The event you tried to respond to does not exist.","redirectToRelatedPage.title":"Showing Related Content","redirectToRelatedPageForBaseUsers.title":"Showing Related Content","redirectToRelatedPageForBaseUsers.message":"The content you are trying to access is archived","redirectToRelatedPage.message":"The content you are trying to access is archived","relatedUrl.archivalLink.flyoutMessage":"The content you are trying to access is archived View Archived Content"},"localOverride":false},"CachedAsset:component:custom.widget.Beta_MetaNav-en-1741994721278":{"__typename":"CachedAsset","id":"component:custom.widget.Beta_MetaNav-en-1741994721278","value":{"component":{"id":"custom.widget.Beta_MetaNav","template":{"id":"Beta_MetaNav","markupLanguage":"HANDLEBARS","style":null,"texts":null,"defaults":{"config":{"applicablePages":[],"description":"MetaNav menu at the top of every page.","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"components":[{"id":"custom.widget.Beta_MetaNav","form":null,"config":null,"props":[],"__typename":"Component"}],"grouping":"CUSTOM","__typename":"ComponentTemplate"},"properties":{"config":{"applicablePages":[],"description":"MetaNav menu at the top of every page.","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"form":null,"__typename":"Component","localOverride":false},"globalCss":null,"form":null},"localOverride":false},"CachedAsset:component:custom.widget.Beta_Footer-en-1741994721278":{"__typename":"CachedAsset","id":"component:custom.widget.Beta_Footer-en-1741994721278","value":{"component":{"id":"custom.widget.Beta_Footer","template":{"id":"Beta_Footer","markupLanguage":"HANDLEBARS","style":null,"texts":null,"defaults":{"config":{"applicablePages":[],"description":"DevCentral´s custom footer.","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"components":[{"id":"custom.widget.Beta_Footer","form":null,"config":null,"props":[],"__typename":"Component"}],"grouping":"CUSTOM","__typename":"ComponentTemplate"},"properties":{"config":{"applicablePages":[],"description":"DevCentral´s custom footer.","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"form":null,"__typename":"Component","localOverride":false},"globalCss":null,"form":null},"localOverride":false},"CachedAsset:component:custom.widget.Tag_Manager_Helper-en-1741994721278":{"__typename":"CachedAsset","id":"component:custom.widget.Tag_Manager_Helper-en-1741994721278","value":{"component":{"id":"custom.widget.Tag_Manager_Helper","template":{"id":"Tag_Manager_Helper","markupLanguage":"HANDLEBARS","style":null,"texts":null,"defaults":{"config":{"applicablePages":[],"description":"Helper widget to inject Tag Manager scripts into head element","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"components":[{"id":"custom.widget.Tag_Manager_Helper","form":null,"config":null,"props":[],"__typename":"Component"}],"grouping":"CUSTOM","__typename":"ComponentTemplate"},"properties":{"config":{"applicablePages":[],"description":"Helper widget to inject Tag Manager scripts into head element","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"form":null,"__typename":"Component","localOverride":false},"globalCss":null,"form":null},"localOverride":false},"CachedAsset:component:custom.widget.Consent_Blackbar-en-1741994721278":{"__typename":"CachedAsset","id":"component:custom.widget.Consent_Blackbar-en-1741994721278","value":{"component":{"id":"custom.widget.Consent_Blackbar","template":{"id":"Consent_Blackbar","markupLanguage":"HTML","style":null,"texts":null,"defaults":{"config":{"applicablePages":[],"description":"","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"components":[{"id":"custom.widget.Consent_Blackbar","form":null,"config":null,"props":[],"__typename":"Component"}],"grouping":"TEXTHTML","__typename":"ComponentTemplate"},"properties":{"config":{"applicablePages":[],"description":"","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"form":null,"__typename":"Component","localOverride":false},"globalCss":null,"form":null},"localOverride":false},"CachedAsset:text:en_US-components/community/Breadcrumb-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/community/Breadcrumb-1740415735000","value":{"navLabel":"Breadcrumbs","dropdown":"Additional parent page navigation"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageBanner-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageBanner-1740415735000","value":{"messageMarkedAsSpam":"This post has been marked as spam","messageMarkedAsSpam@board:TKB":"This article has been marked as spam","messageMarkedAsSpam@board:BLOG":"This post has been marked as spam","messageMarkedAsSpam@board:FORUM":"This discussion has been marked as spam","messageMarkedAsSpam@board:OCCASION":"This event has been marked as spam","messageMarkedAsSpam@board:IDEA":"This idea has been marked as spam","manageSpam":"Manage Spam","messageMarkedAsAbuse":"This post has been marked as abuse","messageMarkedAsAbuse@board:TKB":"This article has been marked as abuse","messageMarkedAsAbuse@board:BLOG":"This post has been marked as abuse","messageMarkedAsAbuse@board:FORUM":"This discussion has been marked as abuse","messageMarkedAsAbuse@board:OCCASION":"This event has been marked as abuse","messageMarkedAsAbuse@board:IDEA":"This idea has been marked as abuse","preModCommentAuthorText":"This comment will be published as soon as it is approved","preModCommentModeratorText":"This comment is awaiting moderation","messageMarkedAsOther":"This post has been rejected due to other reasons","messageMarkedAsOther@board:TKB":"This article has been rejected due to other reasons","messageMarkedAsOther@board:BLOG":"This post has been rejected due to other reasons","messageMarkedAsOther@board:FORUM":"This discussion has been rejected due to other reasons","messageMarkedAsOther@board:OCCASION":"This event has been rejected due to other reasons","messageMarkedAsOther@board:IDEA":"This idea has been rejected due to other reasons","messageArchived":"This post was archived on {date}","relatedUrl":"View Related Content","relatedContentText":"Showing related content","archivedContentLink":"View Archived Content"},"localOverride":false},"CachedAsset:text:en_US-components/tkbs/TkbArticleWidget-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/tkbs/TkbArticleWidget-1740415735000","value":{},"localOverride":false},"Category:category:Forums":{"__typename":"Category","id":"category:Forums","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Forum:board:TechnicalForum":{"__typename":"Forum","id":"board:TechnicalForum","forumPolicies":{"__typename":"ForumPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Forum:board:WaterCooler":{"__typename":"Forum","id":"board:WaterCooler","forumPolicies":{"__typename":"ForumPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Tkb:board:DevCentralNews":{"__typename":"Tkb","id":"board:DevCentralNews","tkbPolicies":{"__typename":"TkbPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:GroupsCategory":{"__typename":"Category","id":"category:GroupsCategory","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:F5-Groups":{"__typename":"Category","id":"category:F5-Groups","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:CommunityGroups":{"__typename":"Category","id":"category:CommunityGroups","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Occasion:board:Events":{"__typename":"Occasion","id":"board:Events","boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"occasionPolicies":{"__typename":"OccasionPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Idea:board:Suggestions":{"__typename":"Idea","id":"board:Suggestions","boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"ideaPolicies":{"__typename":"IdeaPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:CrowdSRC":{"__typename":"Category","id":"category:CrowdSRC","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Tkb:board:codeshare":{"__typename":"Tkb","id":"board:codeshare","tkbPolicies":{"__typename":"TkbPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Tkb:board:communityarticles":{"__typename":"Tkb","id":"board:communityarticles","tkbPolicies":{"__typename":"TkbPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Tkb:board:security-insights":{"__typename":"Tkb","id":"board:security-insights","tkbPolicies":{"__typename":"TkbPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Tkb:board:article-series":{"__typename":"Tkb","id":"board:article-series","tkbPolicies":{"__typename":"TkbPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"TkbTopicMessage:message:279431":{"__typename":"TkbTopicMessage","id":"message:279431","uid":279431,"subject":"9. SYN Cookie Troubleshooting: Logs","board":{"__ref":"Tkb:board:TechnicalArticles"}},"Guide:guide:6":{"__typename":"Guide","id":"guide:6","lastArticle":{"__ref":"TkbTopicMessage:message:279431"}},"TkbTopicMessage:message:285055":{"__typename":"TkbTopicMessage","id":"message:285055","uid":285055,"subject":"F5 Certifications Mega Meta Series: How to take the stress out of the F5 exams","board":{"__ref":"Tkb:board:TechnicalArticles"}},"Guide:guide:8":{"__typename":"Guide","id":"guide:8","firstArticle":{"__ref":"TkbTopicMessage:message:285055"}},"Guide:guide:7":{"__typename":"Guide","id":"guide:7","title":"API Security","node":{"__ref":"Tkb:board:article-series"},"previousGuide":{"__ref":"Guide:guide:6"},"nextGuide":{"__ref":"Guide:guide:8"}},"TkbTopicMessage:message:289041":{"__typename":"TkbTopicMessage","id":"message:289041","uid":289041,"subject":"Declarative Advanced WAF policy lifecycle in a CI/CD pipeline","board":{"__ref":"Tkb:board:TechnicalArticles"}},"TkbTopicMessage:message:290907":{"__typename":"TkbTopicMessage","id":"message:290907","uid":290907,"subject":"Protecting APIs with NGINX App Protect","board":{"__ref":"Tkb:board:TechnicalArticles"}},"CachedAsset:text:en_US-components/community/Navbar-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/community/Navbar-1740415735000","value":{"community":"Community Home","inbox":"Inbox","manageContent":"Manage Content","tos":"Terms of Service","forgotPassword":"Forgot Password","themeEditor":"Theme Editor","edit":"Edit Navigation Bar","skipContent":"Skip to content","migrated-link-9":"Groups","migrated-link-7":"Technical Articles","migrated-link-8":"DevCentral News","migrated-link-1":"Technical Forum","migrated-link-10":"Community Groups","migrated-link-2":"Water Cooler","migrated-link-11":"F5 Groups","Common-external-link":"How Do I...?","migrated-link-0":"Forums","article-series":"Article Series","migrated-link-5":"Community Articles","migrated-link-6":"Articles","security-insights":"Security Insights","migrated-link-3":"CrowdSRC","migrated-link-4":"CodeShare","migrated-link-12":"Events","migrated-link-13":"Suggestions"},"localOverride":false},"CachedAsset:text:en_US-components/community/NavbarHamburgerDropdown-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/community/NavbarHamburgerDropdown-1740415735000","value":{"hamburgerLabel":"Side Menu"},"localOverride":false},"CachedAsset:text:en_US-components/community/BrandLogo-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/community/BrandLogo-1740415735000","value":{"logoAlt":"Khoros","themeLogoAlt":"Brand Logo"},"localOverride":false},"CachedAsset:text:en_US-components/community/NavbarTextLinks-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/community/NavbarTextLinks-1740415735000","value":{"more":"More"},"localOverride":false},"CachedAsset:text:en_US-components/authentication/AuthenticationLink-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/authentication/AuthenticationLink-1740415735000","value":{"title.login":"Sign In","title.registration":"Register","title.forgotPassword":"Forgot Password","title.multiAuthLogin":"Sign In"},"localOverride":false},"CachedAsset:text:en_US-components/nodes/NodeLink-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/nodes/NodeLink-1740415735000","value":{"place":"Place {name}"},"localOverride":false},"QueryVariables:TopicReplyList:message:289036:1":{"__typename":"QueryVariables","id":"TopicReplyList:message:289036:1","value":{"id":"message:289036","first":10,"sorts":{"postTime":{"direction":"ASC"}},"repliesFirst":3,"repliesFirstDepthThree":1,"repliesSorts":{"postTime":{"direction":"ASC"}},"useAvatar":true,"useAuthorLogin":true,"useAuthorRank":true,"useBody":true,"useKudosCount":true,"useTimeToRead":false,"useMedia":false,"useReadOnlyIcon":false,"useRepliesCount":true,"useSearchSnippet":false,"useAcceptedSolutionButton":false,"useSolvedBadge":false,"useAttachments":false,"attachmentsFirst":5,"useTags":true,"useNodeAncestors":false,"useUserHoverCard":false,"useNodeHoverCard":false,"useModerationStatus":true,"usePreviewSubjectModal":false,"useMessageStatus":true}},"ROOT_MUTATION":{"__typename":"Mutation"},"CachedAsset:text:en_US-shared/client/components/common/QueryHandler-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/QueryHandler-1740415735000","value":{"title":"Query Handler"},"localOverride":false},"CachedAsset:text:en_US-components/community/NavbarDropdownToggle-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/community/NavbarDropdownToggle-1740415735000","value":{"ariaLabelClosed":"Press the down arrow to open the menu"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageView/MessageViewStandard-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageView/MessageViewStandard-1740415735000","value":{"anonymous":"Anonymous","author":"{messageAuthorLogin}","authorBy":"{messageAuthorLogin}","board":"{messageBoardTitle}","replyToUser":" to {parentAuthor}","showMoreReplies":"Show More","replyText":"Reply","repliesText":"Replies","markedAsSolved":"Marked as Solved","movedMessagePlaceholder.BLOG":"{count, plural, =0 {This comment has been} other {These comments have been} }","movedMessagePlaceholder.TKB":"{count, plural, =0 {This comment has been} other {These comments have been} }","movedMessagePlaceholder.FORUM":"{count, plural, =0 {This reply has been} other {These replies have been} }","movedMessagePlaceholder.IDEA":"{count, plural, =0 {This comment has been} other {These comments have been} }","movedMessagePlaceholder.OCCASION":"{count, plural, =0 {This comment has been} other {These comments have been} }","movedMessagePlaceholderUrlText":"moved.","messageStatus":"Status: ","statusChanged":"Status changed: {previousStatus} to {currentStatus}","statusAdded":"Status added: {status}","statusRemoved":"Status removed: {status}","labelExpand":"expand replies","labelCollapse":"collapse replies","unhelpfulReason.reason1":"Content is outdated","unhelpfulReason.reason2":"Article is missing information","unhelpfulReason.reason3":"Content is for a different Product","unhelpfulReason.reason4":"Doesn't match what I was searching for"},"localOverride":false},"CachedAsset:text:en_US-components/messages/ThreadedReplyList-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/ThreadedReplyList-1740415735000","value":{"title":"{count, plural, one{# Reply} other{# Replies}}","title@board:BLOG":"{count, plural, one{# Comment} other{# Comments}}","title@board:TKB":"{count, plural, one{# Comment} other{# Comments}}","title@board:IDEA":"{count, plural, one{# Comment} other{# Comments}}","title@board:OCCASION":"{count, plural, one{# Comment} other{# Comments}}","noRepliesTitle":"No Replies","noRepliesTitle@board:BLOG":"No Comments","noRepliesTitle@board:TKB":"No Comments","noRepliesTitle@board:IDEA":"No Comments","noRepliesTitle@board:OCCASION":"No Comments","noRepliesDescription":"Be the first to reply","noRepliesDescription@board:BLOG":"Be the first to comment","noRepliesDescription@board:TKB":"Be the first to comment","noRepliesDescription@board:IDEA":"Be the first to comment","noRepliesDescription@board:OCCASION":"Be the first to comment","messageReadOnlyAlert:BLOG":"Comments have been turned off for this post","messageReadOnlyAlert:TKB":"Comments have been turned off for this article","messageReadOnlyAlert:IDEA":"Comments have been turned off for this idea","messageReadOnlyAlert:FORUM":"Replies have been turned off for this discussion","messageReadOnlyAlert:OCCASION":"Comments have been turned off for this event"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageReplyCallToAction-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageReplyCallToAction-1740415735000","value":{"leaveReply":"Leave a reply...","leaveReply@board:BLOG@message:root":"Leave a comment...","leaveReply@board:TKB@message:root":"Leave a comment...","leaveReply@board:IDEA@message:root":"Leave a comment...","leaveReply@board:OCCASION@message:root":"Leave a comment...","repliesTurnedOff.FORUM":"Replies are turned off for this topic","repliesTurnedOff.BLOG":"Comments are turned off for this topic","repliesTurnedOff.TKB":"Comments are turned off for this topic","repliesTurnedOff.IDEA":"Comments are turned off for this topic","repliesTurnedOff.OCCASION":"Comments are turned off for this topic","infoText":"Stop poking me!"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageSubject-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageSubject-1740415735000","value":{"noSubject":"(no subject)"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageBody-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageBody-1740415735000","value":{"showMessageBody":"Show More","mentionsErrorTitle":"{mentionsType, select, board {Board} user {User} message {Message} other {}} No Longer Available","mentionsErrorMessage":"The {mentionsType} you are trying to view has been removed from the community.","videoProcessing":"Video is being processed. Please try again in a few minutes.","bannerTitle":"Video provider requires cookies to play the video. Accept to continue or {url} it directly on the provider's site.","buttonTitle":"Accept","urlText":"watch"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageCustomFields-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageCustomFields-1740415735000","value":{"CustomField.default.label":"Value of {name}"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageRevision-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageRevision-1740415735000","value":{"lastUpdatedDatePublished":"{publishCount, plural, one{Published} other{Updated}} {date}","lastUpdatedDateDraft":"Created {date}","version":"Version {major}.{minor}"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageReplyButton-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageReplyButton-1740415735000","value":{"repliesCount":"{count}","title":"Reply","title@board:BLOG@message:root":"Comment","title@board:TKB@message:root":"Comment","title@board:IDEA@message:root":"Comment","title@board:OCCASION@message:root":"Comment"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageAuthorBio-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageAuthorBio-1740415735000","value":{"sendMessage":"Send Message","actionMessage":"Follow this blog board to get notified when there's new activity","coAuthor":"CO-PUBLISHER","contributor":"CONTRIBUTOR","userProfile":"View Profile","iconlink":"Go to {name} {type}"},"localOverride":false},"CachedAsset:text:en_US-components/guides/GuideBottomNavigation-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/guides/GuideBottomNavigation-1740415735000","value":{"nav.label":"Previous/Next Page","nav.previous":"Previous","nav.next":"Next"},"localOverride":false},"CachedAsset:text:en_US-components/customComponent/CustomComponent-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/customComponent/CustomComponent-1740415735000","value":{"errorMessage":"Error rendering component id: {customComponentId}","bannerTitle":"Video provider requires cookies to play the video. Accept to continue or {url} it directly on the provider's site.","buttonTitle":"Accept","urlText":"watch"},"localOverride":false},"CachedAsset:text:en_US-components/users/UserLink-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/users/UserLink-1740415735000","value":{"authorName":"View Profile: {author}","anonymous":"Anonymous"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/users/UserRank-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/users/UserRank-1740415735000","value":{"rankName":"{rankName}","userRank":"Author rank {rankName}"},"localOverride":false},"CachedAsset:text:en_US-components/users/UserRegistrationDate-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/users/UserRegistrationDate-1740415735000","value":{"noPrefix":"{date}","withPrefix":"Joined {date}"},"localOverride":false},"CachedAsset:text:en_US-components/tags/TagView/TagViewChip-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-components/tags/TagView/TagViewChip-1740415735000","value":{"tagLabelName":"Tag name {tagName}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/users/UserAvatar-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/users/UserAvatar-1740415735000","value":{"altText":"{login}'s avatar","altTextGeneric":"User's avatar"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/ranks/UserRankLabel-1740415735000":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/ranks/UserRankLabel-1740415735000","value":{"altTitle":"Icon for {rankName} rank"},"localOverride":false}}}},"page":"/kbs/TkbMessagePage/TkbMessagePage","query":{"guideId":"guide:7","boardId":"technicalarticles","messageSubject":"advanced-api-security-for-kubernetes-containers-running-in-aws---nginx-app-prote","messageId":"289036"},"buildId":"G6LFdF6Y8sb5g8rZyM3sC","runtimeConfig":{"buildInformationVisible":false,"logLevelApp":"info","logLevelMetrics":"info","openTelemetryClientEnabled":false,"openTelemetryConfigName":"f5","openTelemetryServiceVersion":"25.2.0","openTelemetryUniverse":"prod","openTelemetryCollector":"http://localhost:4318","openTelemetryRouteChangeAllowedTime":"5000","apolloDevToolsEnabled":false,"inboxMuteWipFeatureEnabled":false},"isFallback":false,"isExperimentalCompile":false,"dynamicIds":["./components/customComponent/CustomComponent/CustomComponent.tsx","./components/community/Navbar/NavbarWidget.tsx","./components/community/Breadcrumb/BreadcrumbWidget.tsx","./components/tkbs/TkbArticleWidget/TkbArticleWidget.tsx","./components/messages/MessageView/MessageViewStandard/MessageViewStandard.tsx","./components/messages/ThreadedReplyList/ThreadedReplyList.tsx","./components/customComponent/CustomComponentContent/TemplateContent.tsx","./components/customComponent/CustomComponentContent/HtmlContent.tsx","./components/customComponent/CustomComponentContent/CustomComponentScripts.tsx","../shared/client/components/common/List/UnwrappedList/UnwrappedList.tsx","./components/tags/TagView/TagView.tsx","./components/tags/TagView/TagViewChip/TagViewChip.tsx"],"appGip":true,"scriptLoader":[]}