diff --git a/.gitignore b/.gitignore
index e54f2a6..ce89575 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,8 +20,7 @@ Thumbs.db
=======
/.idea/
/src/__pycache__/
-/src/v4_1/__pycache__/
/src/v4_2/__pycache__/
-/src/v4_3/__pycache__/
+/src/v5_0/__pycache__/
/contrib/devportal/redocly/src/__pycache__/
/venv/
diff --git a/FEATURES.md b/FEATURES.md
index c27130d..e63cdaa 100644
--- a/FEATURES.md
+++ b/FEATURES.md
@@ -2,25 +2,25 @@
### NGINX `http` and `stream` servers
-| Feature | API v4.1 | API v4.2 | Notes |
-|----------------------------|-----------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| Upstreams | CRUD | CRUD |
Snippets supported: static and from source of truth |
-| HTTP servers | CRUD | CRUD | Snippets supported (`http`, `servers`, `locations`): static and from source of truth |
-| TCP/UDP servers | CRUD | CRUD | Snippets supported (`streams`, `servers`): static and from source of truth |
-| TLS | CRUD | CRUD | Certificates and keys can be dynamically fetched from source of truth |
-| Client authentication | X | X | See [client authentication](#Client-authentication) |
-| Upstream authentication | X | X | See [upstream and Source of truth authentication](#Upstream-and-Source-of-truth-authentication) |
-| Rate limiting | X | X | |
-| Active healthchecks | X | X | |
-| Cookie-based stickiness | X | X | |
-| HTTP headers manipulation | | X | To server: set, deleteTo client: add, delete, replace |
-| Maps | X | X | |
-| NGINX Plus REST API access | X | X | |
-| NGINX App Protect WAF | X | X | Per-policy CRUD at `server` and `location` levelSupport for dataplane-based bundle compilationSecurity policies can be fetched from source of truth |
+| Feature | API v4.2 | API v5.0 | Notes |
+|----------------------------|----------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| Upstreams | CRUD | CRUD | Snippets supported: static and from source of truth |
+| HTTP servers | CRUD | CRUD | Snippets supported (`http`, `servers`, `locations`): static and from source of truth |
+| TCP/UDP servers | CRUD | CRUD | Snippets supported (`streams`, `servers`): static and from source of truth |
+| TLS | CRUD | CRUD | Certificates and keys can be dynamically fetched from source of truth |
+| Client authentication | X | X | See [client authentication](#Client-authentication) |
+| Upstream authentication | X | X | See [upstream and Source of truth authentication](#Upstream-and-Source-of-truth-authentication) |
+| Rate limiting | X | X | |
+| Active healthchecks | X | X | |
+| Cookie-based stickiness | X | X | |
+| HTTP headers manipulation | X | X | To server: set, deleteTo client: add, delete, replace |
+| Maps | X | X | |
+| NGINX Plus REST API access | X | X | |
+| NGINX App Protect WAF | X | X | Per-policy CRUD at `server` and `location` levelSupport for dataplane-based bundle compilationSecurity policies can be fetched from source of truth |
### API Gateway
-| Feature | API v4.1 | API v4.2 | Notes |
+| Feature | API v4.2 | API v5.0 | Notes |
|----------------------------------------------|----------|----------|-------------------------------------------------------------------------------|
| Configuration generation from OpenAPI schema | X | X | |
| HTTP methods enforcement | X | X | |
@@ -30,13 +30,13 @@
### API Gateway - Developer Portal
-| Feature | API v4.1 | API v4.2 | Notes |
+| Feature | API v4.2 | API v5.0 | Notes |
|-------------------------------------------------|----------|----------|---------------------------|
| Developer Portal generation from OpenAPI schema | X | X | Based on Redocly |
### Client authentication
-| Type | Description | API v4.1 | API v4.2 | Notes |
+| Type | Description | API v4.2 | API v5.0 | Notes |
|------|----------------------|----------|----------|-------------------------------------|
| jwt | Java Web Token (JWT) | X | X | |
| mtls | Mutual TLS | X | X | Supported for HTTP servers |
@@ -85,9 +85,9 @@ Client-side authentication profiles to be defined under `.declaration.http.authe
### Client authorization
-| Type | Description | API v4.1 | API v4.2 | Notes |
+| Type | Description | API v4.2 | API v5.0 | Notes |
|------|----------------------|----------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| jwt | Java Web Token (JWT) | | X | Based on JWT claims. Supported under .declaration.http.server[].declaration.http.server[].location[].declaration.http.server[].location[].apigateway |
+| jwt | Java Web Token (JWT) | X | X | Based on JWT claims. Supported under .declaration.http.server[].declaration.http.server[].location[].declaration.http.server[].location[].apigateway |
#### Examples
@@ -115,10 +115,10 @@ Client-side authorization profiles to be defined under `.declaration.http.author
### Upstream and Source of truth authentication
-| Type | Description | API v4.1 | API v4.2 | Notes |
+| Type | Description | API v4.2 | API v5.0 | Notes |
|--------------|----------------------------------------------|----------|----------|----------------------------------------------------------------------------------------|
| Bearer token | Authentication token as Authorization Bearer | X | X | `Bearer` Authorization header is injected in requests to upstreams and source of truth |
-| Basic Auth | Authentication token as Authorization Basic | | X | `Basic` Authorization header is injected in requests to upstreams and source of truth |
+| Basic Auth | Authentication token as Authorization Basic | X | X | `Basic` Authorization header is injected in requests to upstreams and source of truth |
| HTTP header | Authentication token in custom HTTP header | X | X | HTTP header is injected in requests to upstreams and source of truth |
| mTLS | Mutual TLS | X | X | Client certificate is sent to upstream / source of truth |
@@ -183,10 +183,10 @@ Server-side authentication profiles to be defined under `.declaration.http.authe
### HTTP Headers manipulation
-| Type | API v4.1 | API v4.2 | Notes |
-|-----------------------------|----------|----------|------------------------------------------------------------------------------------------------------------------------------|
-| Request (client to server) | | X | `set` - new header injection`delete` - client header removal |
-| Response (server to client) | | X | `add` - new header injection`delete` - server header removal`replace` - server header replacement |
+| Type | API v4.2 | API v5.0 | Notes |
+|-----------------------------|----------|---------|------------------------------------------------------------------------------------------------------------------------------|
+| Request (client to server) | X | X | `set` - new header injection`delete` - client header removal |
+| Response (server to client) | X | X | `add` - new header injection`delete` - server header removal`replace` - server header replacement |
#### Examples
@@ -232,14 +232,14 @@ To be defined under `.declaration.http.servers[].headers` and/or `.declaration.h
### NGINX Javascript
-| Hook type | API v4.1 | API v4.2 | Notes |
+| Hook type | API v4.2 | API v5.0 | Notes |
|-------------------|----------|----------|------------------------------------------------------------------------------------------------------------------------------|
-| js_body_filter | | X | Available in `declaration.http.server[].location[]` |
-| js_content | | X | Available in `declaration.http.server[].location[]` |
-| js_header_filter | | X | Available in `declaration.http.server[].location[]` |
-| js_periodic | | X | Available in `declaration.http.server[].location[]` |
-| js_preload_object | | X | Available in `.declaration.http``declaration.http.server[]``declaration.http.server[].location[]` |
-| js_set | | X | Available in `.declaration.http``declaration.http.server[]``declaration.http.server[].location[]` |
+| js_body_filter | X | X | Available in `declaration.http.server[].location[]` |
+| js_content | X | X | Available in `declaration.http.server[].location[]` |
+| js_header_filter | X | X | Available in `declaration.http.server[].location[]` |
+| js_periodic | X | X | Available in `declaration.http.server[].location[]` |
+| js_preload_object | X | X | Available in `.declaration.http``declaration.http.server[]``declaration.http.server[].location[]` |
+| js_set | X | X | Available in `.declaration.http``declaration.http.server[]``declaration.http.server[].location[]` |
Note: `njs` profiles can be included in base64-encoded format under `.declaration.http.njs[]` of fetched from an external source of truth
For detailed examples see the [Postman collection](/contrib/postman)
diff --git a/README.md b/README.md
index a4e7d49..9298259 100644
--- a/README.md
+++ b/README.md
@@ -144,8 +144,8 @@ See the [features list](/FEATURES.md)
Usage details and JSON schema are available here:
-- [API v4.2](/USAGE-v4.2.md) - latest
-- [API v4.1](/USAGE-v4.1.md)
+- [API v5.0](/USAGE-v5.0.md) - latest
+- [API v4.2](/USAGE-v4.2.md)
A sample Postman collection and usage instructions can be found [here](/contrib/postman)
diff --git a/USAGE-v4.1.md b/USAGE-v4.1.md
deleted file mode 100644
index 4b5e1be..0000000
--- a/USAGE-v4.1.md
+++ /dev/null
@@ -1,257 +0,0 @@
-# Usage for API v4.1
-
-Version 4.1 API requires:
-
-- NGINX Instance Manager 2.14+
-- NGINX Plus R30+
-
-If NGINX App Protect declarations are used:
-- NGINX App Protect Policy Compiler 4.2.0+
-- NGINX Plus instances running App Protect WAF 4.2.0+ using `precompiled_publication: true` in `/etc/nginx-agent/nginx-agent.conf`
-
-The JSON schema is self explanatory. See also the [sample Postman collection](/contrib/postman)
-
-- `.output.type` defines how NGINX configuration will be returned:
- - *plaintext* - plaintext format
- - *json* - JSON-wrapped, base64-encoded
- - *configmap* - Kubernetes Configmap in YAML format.
- - `.output.configmap.name` must be set to the ConfigMap name
- - `.output.configmap.filename` must be set to the NGINX configuration filename
- - `.output.configmap.namespace` the optional namespace for the ConfigMap
- - *http* - NGINX configuration is POSTed to custom url
- - `.output.http.url` the URL to POST the configuration to
- - *nms* - NGINX configuration is published as a Staged Config to NGINX Instance Manager
- - `.output.nms.url` the NGINX Instance Manager URL
- - `.output.nms.username` the NGINX Instance Manager authentication username
- - `.output.nms.password` the NGINX Instance Manager authentication password
- - `.output.nms.instancegroup` the NGINX Instance Manager instance group to publish the configuration to
- - `.output.nms.synctime` **optional**, used for GitOps autosync. When specified and the declaration includes HTTP(S) references to NGINX App Protect policies, TLS certificates/keys/chains, the HTTP(S) endpoints will be checked every `synctime` seconds and if external contents have changed, the updated configuration will automatically be published to NGINX Instance Manager
- - `.output.nms.modules` an optional array of NGINX module names (ie. 'ngx_http_app_protect_module', 'ngx_http_js_module','ngx_stream_js_module')
- - `.output.nms.certificates` an optional array of TLS certificates/keys/chains to be published
- - `.output.nms.certificates[].type` the item type ('certificate', 'key', 'chain')
- - `.output.nms.certificates[].name` the certificate/key/chain name with no path/extension (ie. 'test-application')
- - `.output.nms.certificates[].contents` the content: this can be either base64-encoded or be a HTTP(S) URL that will be fetched dynamically from a source of truth
- - `.output.nms.policies[]` an optional array of NGINX App Protect security policies
- - `.output.nms.policies[].type` the policy type ('app_protect')
- - `.output.nms.policies[].name` the policy name (ie. 'prod-policy')
- - `.output.nms.policies[].active_tag` the policy tag to enable among all available versions (ie. 'v1')
- - `.output.nms.policies[].versions[]` array with all available policy versions
- - `.output.nms.policies[].versions[].tag` the policy version's tag name
- - `.output.nms.policies[].versions[].displayName` the policy version's display name
- - `.output.nms.policies[].versions[].description` the policy version's description
- - `.output.nms.policies[].versions[].contents` this can be either base64-encoded or be a HTTP(S) URL that will be fetched dynamically from a source of truth
-- `.declaration` describes the NGINX configuration to be created.
-
-### Locations ###
-
-Locations `.declaration.http.servers[].locations[].uri` match modifiers in `.declaration.http.servers[].locations[].urimatch` can be:
-
-- *prefix* - prefix URI matching
-- *exact* - exact URI matching
-- *regex* - case sensitive regex matching
-- *iregex* - case insensitive regex matching
-- *best* - case sensitive regex matching that halts any other location matching once a match is made
-
-### API Gateway ###
-
-Swagger files and OpenAPI schemas can be used to automatically configure NGINX as an API Gateway. Developer portal creation is supported through [Redocly](https://redocly.com/)
-
-Declaration path `.declaration.http.servers[].locations[].apigateway` defines the API Gateway configuration:
-
-- `openapi_schema` - the base64-encoded schema, or the schema URL. YAML and JSON are supported
-- `api_gateway.enabled` - enable/disable API Gateway provisioning
-- `api_gateway.strip_uri` - removes the `.declaration.http.servers[].locations[].uri` part of the URI before forwarding requests to the upstream
-- `api_gateway.server_url` - the base URL of the upstream server
-- `developer_portal.enabled` - enable/disable Developer portal provisioning
-- `developer_portal.uri` - the trailing part of the Developer portal URI, this is appended to `.declaration.http.servers[].locations[].uri`. If omitted it defaults to `devportal.html`
-- `authentication` - optional, used to enforce JWT authentication at the API Gateway level
-- `authentication.client` - JWT authentication profile name
-- `authentication.enforceOnPaths` - if set to `true` JWT authentication is enforced on all API endpoints listed under `authentication.paths`. if set to `false` JWT authentication is enforced on all API endpoints but those listed under `authentication.paths`
-- `rate_limit` - optional, used to enforce rate limiting at the API Gateway level
-- `rate_limit.enforceOnPaths` - if set to `true` rate limiting is enforced on all API endpoints listed under `rate_limit.paths`. if set to `false` rate limiting is enforced on all API endpoints but those listed under `rate_limit.paths`
-
-A sample API Gateway declaration to publish the `https://petstore.swagger.io` REST API and enforce:
-
-- REST API endpoint URIs
-- HTTP Methods
-- Rate limiting on `/user/login` and `/user/logout`
-- JWT authentication on `/user/login` and `/usr/logout`
-
-is:
-
-```commandline
-{
- "output": {
- "type": "nms",
- "nms": {
- "url": "{{nim_host}}",
- "username": "{{nim_username}}",
- "password": "{{nim_password}}",
- "instancegroup": "{{nim_instancegroup}}",
- "synctime": 0,
- "modules": [
- "ngx_http_js_module",
- "ngx_stream_js_module"
- ]
- }
- },
- "declaration": {
- "http": {
- "servers": [
- {
- "name": "Petstore API",
- "names": [
- "apigw.nginx.lab"
- ],
- "resolver": "8.8.8.8",
- "listen": {
- "address": "80"
- },
- "log": {
- "access": "/var/log/nginx/apigw.nginx.lab-access_log",
- "error": "/var/log/nginx/apigw.nginx.lab-error_log"
- },
- "locations": [
- {
- "uri": "/petstore",
- "urimatch": "prefix",
- "apigateway": {
- "openapi_schema": {
- "content": "http://petstore.swagger.io/v2/swagger.json",
- "authentication": [
- {
- "profile": "Source of truth authentication profile using HTTP header token authentication"
- }
- ]
- },
- "api_gateway": {
- "enabled": true,
- "strip_uri": true,
- "server_url": "https://petstore.swagger.io/v2"
- },
- "developer_portal": {
- "enabled": false,
- "uri": "/petstore-devportal.html"
- },
- "authentication": {
- "client": [
- {
- "profile": "Petstore JWT Authentication"
- }
- ],
- "enforceOnPaths": true,
- "paths": [
- "/user/login",
- "/user/logout"
- ]
- },
- "rate_limit": [
- {
- "profile": "petstore_ratelimit",
- "httpcode": 429,
- "burst": 0,
- "delay": 0,
- "enforceOnPaths": true,
- "paths": [
- "/user/login",
- "/user/logout"
- ]
- }
- ]
- },
- "log": {
- "access": "/var/log/nginx/petstore-access_log",
- "error": "/var/log/nginx/petstore-error_log"
- }
- }
- ]
- }
- ],
- "rate_limit": [
- {
- "name": "petstore_ratelimit",
- "key": "$binary_remote_addr",
- "size": "10m",
- "rate": "2r/s"
- }
- ],
- "authentication": {
- "client": [
- {
- "name": "Petstore JWT Authentication",
- "type": "jwt",
- "jwt": {
- "realm": "Petstore Authentication",
- "key": "{\"keys\": [{\"k\":\"ZmFudGFzdGljand0\",\"kty\":\"oct\",\"kid\":\"0001\"}]}",
- "cachetime": 5
- }
- }
- ],
- "server": [
- {
- "name": "Source of truth authentication profile using HTTP header token authentication",
- "type": "token",
- "token": {
- "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDI0ODEzNjcsImV4cCI6MTcwMjQ4MTM2OH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIl19.SKA_7MszAypMEtX5NDQ0TcUbVYx_Wt0hrtmuyTmrVKU",
- "type": "header",
- "location": "X-AUTH-TOKEN"
- }
- }
- ]
- }
- }
- }
-}
-```
-
-It can be tested using:
-
-```
-curl -iH "Host: apigw.nginx.lab" http:///petstore/store/inventory
-```
-
-Authentication failed:
-
-```
-curl -i http://apigw.nginx.lab/petstore/user/login
-```
-
-Authentication Succeeded:
-
-```
-curl -i http://apigw.nginx.lab/petstore/user/login -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDI0ODEzNjcsImV4cCI6MTcwMjQ4MTM2OH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIl19.SKA_7MszAypMEtX5NDQ0TcUbVYx_Wt0hrtmuyTmrVKU"
-```
-
-The API Developer portal can be accessed at:
-
- http:///petstore/petstore-devportal.html
-
-### Maps ###
-
-Map entries `.declaration.maps[].entries.keymatch` can be:
-
-- *exact* - exact variable matching
-- *regex* - case sensitive regex matching
-- *iregex* - case insensitive regex matching
-
-### Snippets ###
-
-Snippets for http, upstream, server and location can be specified as:
-- base64-encoded content
-- HTTP(S) URL of a source of truth to fetch snippet content from. Content on the source of truth must be plaintext, it will be automatically base64-encoded
-
-### Methods ###
-
-- `POST /v4.1/config/` - Publish a new declaration
-- `PATCH /v4.1/config/{config_uid}` - Update an existing declaration
- - Per-HTTP server CRUD
- - Per-HTTP upstream CRUD
- - Per-Stream server CRUD
- - Per-Stream upstream CRUD
- - Per-NGINX App Protect WAF policy CRUD
-- `GET /v4.1/config/{config_uid}` - Retrieve an existing declaration
-- `DELETE /v4.1/config/{config_uid}` - Delete an existing declaration
-
-### Usage Examples ###
-
-A sample Postman collection is available [here](/contrib/postman)
\ No newline at end of file
diff --git a/USAGE-v5.0.md b/USAGE-v5.0.md
new file mode 100644
index 0000000..f399187
--- /dev/null
+++ b/USAGE-v5.0.md
@@ -0,0 +1,197 @@
+# Usage for NGINX Declarative API v5.0
+
+Version 5.0 supports:
+
+- [NGINX Instance Manager](https://docs.nginx.com/nginx-management-suite/nim/) 2.14+
+- [NGINX Plus](https://docs.nginx.com/nginx/) R30+
+- [NGINX App Protect WAF](https://docs.nginx.com/nginx-app-protect-waf/) 4.2.0+ with compiled [policy bundles](https://docs.nginx.com/nginx-app-protect-waf/v5/admin-guide/compiler/)
+
+The JSON schema is self explanatory. See also the [sample Postman collection](/contrib/postman)
+
+- `.output.type` defines how NGINX configuration will be returned:
+ - *plaintext* - plaintext format
+ - *json* - JSON-wrapped, base64-encoded
+ - *configmap* - Kubernetes Configmap in YAML format.
+ - `.output.configmap.name` must be set to the ConfigMap name
+ - `.output.configmap.filename` must be set to the NGINX configuration filename
+ - `.output.configmap.namespace` the optional namespace for the ConfigMap
+ - *http* - NGINX configuration is POSTed to custom url
+ - `.output.http.url` the URL to POST the configuration to
+ - *nms* - NGINX configuration is published as a Staged Config to NGINX Instance Manager
+ - `.output.nms.url` the NGINX Instance Manager URL
+ - `.output.nms.username` the NGINX Instance Manager authentication username
+ - `.output.nms.password` the NGINX Instance Manager authentication password
+ - `.output.nms.instancegroup` the NGINX Instance Manager instance group to publish the configuration to
+ - `.output.nms.synctime` **optional**, used for GitOps autosync. When specified and the declaration includes HTTP(S) references to NGINX App Protect policies, TLS certificates/keys/chains, the HTTP(S) endpoints will be checked every `synctime` seconds and if external contents have changed, the updated configuration will automatically be published to NGINX Instance Manager
+ - `.output.nms.modules` an optional array of NGINX module names (ie. 'ngx_http_app_protect_module', 'ngx_http_js_module','ngx_stream_js_module')
+ - `.output.nms.certificates` an optional array of TLS certificates/keys/chains to be published
+ - `.output.nms.certificates[].type` the item type ('certificate', 'key', 'chain')
+ - `.output.nms.certificates[].name` the certificate/key/chain name with no path/extension (ie. 'test-application')
+ - `.output.nms.certificates[].contents` the content: this can be either base64-encoded or be a HTTP(S) URL that will be fetched dynamically from a source of truth
+ - `.output.nms.policies[]` an optional array of NGINX App Protect security policies
+ - `.output.nms.policies[].type` the policy type ('app_protect')
+ - `.output.nms.policies[].name` the policy name (ie. 'prod-policy')
+ - `.output.nms.policies[].active_tag` the policy tag to enable among all available versions (ie. 'v1')
+ - `.output.nms.policies[].versions[]` array with all available policy versions
+ - `.output.nms.policies[].versions[].tag` the policy version's tag name
+ - `.output.nms.policies[].versions[].displayName` the policy version's display name
+ - `.output.nms.policies[].versions[].description` the policy version's description
+ - `.output.nms.policies[].versions[].contents` this can be either base64-encoded or be a HTTP(S) URL that will be fetched dynamically from a source of truth
+- `.declaration` describes the NGINX configuration to be created.
+
+### Locations ###
+
+Locations `.declaration.http.servers[].locations[].uri` match modifiers in `.declaration.http.servers[].locations[].urimatch` can be:
+
+- *prefix* - prefix URI matching
+- *exact* - exact URI matching
+- *regex* - case sensitive regex matching
+- *iregex* - case insensitive regex matching
+- *best* - case sensitive regex matching that halts any other location matching once a match is made
+
+### Javascript profiles ###
+
+NGINX Javascript profiles are defined in `.declaration.http.njs[]`:
+
+- `name` - the NJS profile name
+- `file.content` - the base64-encoded njs source code or the `http(s)://` URL of the file
+- `file.authentication.server[0].profile` - authentication profile name if `file.content` is a URL and the request must be authenticated
+
+### Javascript hooks ###
+
+NGINX Javascript hooks can be used in:
+
+- `.declaration.http.njs`
+ - Supported hooks:
+ - `js_preload_object'
+ - 'js_set`
+- `.declaration.http.server[].njs`
+ - Supported hooks:
+ - `js_preload_object'
+ - 'js_set`
+- `.declaration.http.server[].location[].njs`
+ - Supported hooks:
+ - `js_body_filter'
+ - 'js_content'
+ - 'js_header_filter'
+ - 'js_periodic'
+ - 'js_preload_object'
+ - 'js_set`
+
+Hooks invocation is:
+
+```
+"njs": [
+ {
+ "hook": {
+ "name": "",
+ "parameters": [
+ {
+ "name": "",
+ "value": ""
+ }
+ ]
+ },
+ "profile": "",
+ "function": ""
+ }
+]
+```
+
+For detailed examples see the [Postman collection](/contrib/postman)
+
+### API Gateway ###
+
+Swagger files and OpenAPI schemas can be used to automatically configure NGINX as an API Gateway. Developer portal creation is supported through [Redocly](https://redocly.com/)
+
+Declaration path `.declaration.http.servers[].locations[].apigateway` defines the API Gateway configuration:
+
+- `openapi_schema` - the base64-encoded schema, or the schema URL. YAML and JSON are supported
+- `api_gateway.enabled` - enable/disable API Gateway provisioning
+- `api_gateway.strip_uri` - removes the `.declaration.http.servers[].locations[].uri` part of the URI before forwarding requests to the upstream
+- `api_gateway.server_url` - the base URL of the upstream server
+- `developer_portal.enabled` - enable/disable Developer portal provisioning
+- `developer_portal.uri` - the trailing part of the Developer portal URI, this is appended to `.declaration.http.servers[].locations[].uri`. If omitted it defaults to `devportal.html`
+- `authentication` - optional, used to enforce authentication at the API Gateway level
+- `authentication.client[]` - authentication profile names
+- `authentication.enforceOnPaths` - if set to `true` authentication is enforced on all API endpoints listed under `authentication.paths`. if set to `false` authentication is enforced on all API endpoints but those listed under `authentication.paths`
+- `authentication.paths` - paths to enforce authentication
+- `authorization[]` - optional, used to enforce authorization
+- `authorization[].profile` - authorization profile name
+- `authorization[].enforceOnPaths` - if set to `true` authorization is enforced on all API endpoints listed under `authorization.paths`. if set to `false` authorization is enforced on all API endpoints but those listed under `authorization[].paths`
+- `authorization[].paths` - paths to enforce authorization
+- `rate_limit` - optional, used to enforce rate limiting at the API Gateway level
+- `rate_limit.enforceOnPaths` - if set to `true` rate limiting is enforced on all API endpoints listed under `rate_limit.paths`. if set to `false` rate limiting is enforced on all API endpoints but those listed under `rate_limit.paths`
+
+A sample API Gateway declaration to publish the `https://petstore.swagger.io` REST API and enforce:
+
+- REST API endpoint URIs
+- HTTP Methods
+- Rate limiting on `/user/login`, `/usr/logout` and `/pet/{petId}/uploadImage`
+- JWT authentication on `/user/login`, `/usr/logout` and `/pet/{petId}/uploadImage`
+- JWT claim-based authorization on `/user/login`, `/usr/logout` and `/pet/{petId}/uploadImage`
+
+can be found in the [Postman collection](/contrib/)
+
+### Maps ###
+
+Map entries `.declaration.maps[].entries.keymatch` can be:
+
+- *exact* - exact variable matching
+- *regex* - case sensitive regex matching
+- *iregex* - case insensitive regex matching
+
+### Snippets ###
+
+Snippets for `http`, `upstream`, `server` and `location` can be specified as:
+- base64-encoded content
+- HTTP(S) URL of a source of truth to fetch snippet content from. Content on the source of truth must be plaintext
+- source of truth authentication is supported through authentication profiles
+
+### Authentication profiles ###
+
+Client and Server authentication profiles can be defined in the declarative json at `.declaration.http.authentication`
+
+```commandline
+ "authentication": {
+ "client": [
+ {
+ "name": "",
+ "type": "",
+ "": {
+ "": "",
+ [...]
+ }
+ },
+ [...]
+ ],
+ "server": [
+ {
+ "name": "",
+ "type": "",
+ "": {
+ "": "",
+ [...]
+ }
+ },
+ [...]
+ ]
+```
+
+For a list of all supported authentication profile types see the [feature matrix](/FEATURES.md)
+
+### API endpoints ###
+
+- `POST /v5.0/config/` - Publish a new declaration
+- `PATCH /v5.0/config/{config_uid}` - Update an existing declaration
+ - Per-HTTP server CRUD
+ - Per-HTTP upstream CRUD
+ - Per-Stream server CRUD
+ - Per-Stream upstream CRUD
+ - Per-NGINX App Protect WAF policy CRUD
+- `GET /v5.0/config/{config_uid}` - Retrieve an existing declaration
+- `DELETE /v5.0/config/{config_uid}` - Delete an existing declaration
+
+### Usage Examples ###
+
+A sample Postman collection is available [here](/contrib/postman)
\ No newline at end of file
diff --git a/contrib/postman/NGINX Declarative API.postman_collection.json b/contrib/postman/NGINX Declarative API.postman_collection.json
index 5484297..9ca3cde 100644
--- a/contrib/postman/NGINX Declarative API.postman_collection.json
+++ b/contrib/postman/NGINX Declarative API.postman_collection.json
@@ -1,15 +1,15 @@
{
"info": {
- "_postman_id": "2c626339-a5f6-4283-8a6a-6dc7469cd514",
+ "_postman_id": "5182067d-a117-4979-850b-80d3310afd9a",
"name": "NGINX Declarative API",
- "description": "Declarative REST API and GitOps automation layer for NGINX Instance Manager",
+ "description": "Declarative REST API and GitOps automation layer for NGINX Instance Manager\n\n[https://github.com/f5devcentral/NGINX-Declarative-API/](https://github.com/f5devcentral/NGINX-Declarative-API/)",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
"_exporter_id": "1667416",
- "_collection_link": "https://orange-rocket-1353.postman.co/workspace/NGINX-Declarative-API~8ba6e9c1-a04b-4484-8193-bbb142560553/collection/1667416-2c626339-a5f6-4283-8a6a-6dc7469cd514?action=share&source=collection_link&creator=1667416"
+ "_collection_link": "https://orange-rocket-1353.postman.co/workspace/NGINX-Declarative-API~8ba6e9c1-a04b-4484-8193-bbb142560553/collection/1667416-5182067d-a117-4979-850b-80d3310afd9a?action=share&source=collection_link&creator=1667416"
},
"item": [
{
- "name": "v4.1",
+ "name": "v4.2",
"item": [
{
"name": "Configuration generation",
@@ -231,7 +231,8 @@
"exec": [
""
],
- "type": "text/javascript"
+ "type": "text/javascript",
+ "packages": {}
}
}
],
@@ -240,7 +241,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"json\"\n },\n \"declaration\": {\n \"layer4\": {\n \"servers\": [\n {\n \"name\": \"sample_layer4_service\",\n \"listen\": {\n \"address\": \"10053\",\n \"protocol\": \"tcp\",\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"upstream\": \"l4_upstream\",\n \"snippet\": \"IyBUaGlzIGlzIGEgbDQgdXBzdHJlYW0gc25pcHBldCBjb21tZW50Cg==\"\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"l4_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:53\"\n },\n {\n \"server\": \"10.0.0.2:53\"\n }\n ]\n }\n ]\n },\n \"http\": {\n \"servers\": [\n {\n \"name\": \"HTTP test application\",\n \"names\": [\n \"server_8080.nginx.lab\",\n \"server_8081.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"127.0.0.1:8080\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/access_log\",\n \"error\": \"/var/log/nginx/error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/test\",\n \"urimatch\": \"exact\",\n \"upstream\": \"http://test_upstream\",\n \"health_check\": {\n \"enabled\": true,\n \"uri\": \"/healthcheck\",\n \"interval\": 5,\n \"fails\": 3,\n \"passes\": 2\n },\n \"rate_limit\": {\n \"profile\": \"test_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 10,\n \"delay\": 3\n },\n \"app_protect\": {\n \"enabled\": true,\n \"policy\": \"test_policy\",\n \"log\": {\n \"profile_name\": \"log_illegal\",\n \"enabled\": true,\n \"destination\": \"192.168.1.5:514\"\n }\n },\n \"snippet\": \"IyBUaGlzIGlzIGEgbG9jYXRpb24gc25pcHBldCBjb21tZW50Cg==\"\n }\n ],\n \"app_protect\": {\n \"enabled\": true,\n \"policy\": \"test_policy\",\n \"log\": {\n \"profile_name\": \"log_blocked\",\n \"enabled\": true,\n \"destination\": \"192.168.1.5:514\"\n }\n },\n \"snippet\": \"IyBUaGlzIGlzIGEgc2VydmVyIHNuaXBwZXQgY29tbWVudAo=\"\n },\n {\n \"name\": \"another HTTP test application\",\n \"names\": [\n \"server_443\"\n ],\n \"listen\": {\n \"address\": \"127.0.0.1:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"upstream\": \"http://test_upstream\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:80\",\n \"weight\": 5,\n \"max_fails\": 2,\n \"fail_timeout\": \"30s\",\n \"max_conns\": 3,\n \"slow_start\": \"30s\"\n },\n {\n \"server\": \"10.0.0.2:80\",\n \"backup\": true\n }\n ],\n \"sticky\": {\n \"cookie\": \"cookie_name\",\n \"expires\": \"1h\",\n \"domain\": \".testserver\",\n \"path\": \"/\"\n },\n \"snippet\": \"IyBUaGlzIGlzIGEgdXBzdHJlYW0gc25pcHBldCBjb21tZW50Cg==\"\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"test_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"1r/s\"\n }\n ],\n \"maps\": [\n {\n \"match\": \"$host$request_uri\",\n \"variable\": \"$backend\",\n \"entries\": [\n {\n \"key\": \"www.test.lab/app1/\",\n \"keymatch\": \"iregex\",\n \"value\": \"upstream_1\"\n },\n {\n \"key\": \"(.*).test.lab/app2/\",\n \"keymatch\": \"regex\",\n \"value\": \"upstream_2\"\n }\n ]\n }\n ],\n \"nginx_plus_api\": {\n \"write\": true,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"snippet\": \"IyBUaGlzIGlzIGEgSFRUUCBzbmlwcGV0IGNvbW1lbnQK\"\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"json\"\n },\n \"declaration\": {\n \"layer4\": {\n \"servers\": [\n {\n \"name\": \"sample_layer4_service\",\n \"listen\": {\n \"address\": \"10053\",\n \"protocol\": \"tcp\",\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"upstream\": \"l4_upstream\",\n \"snippet\": {\n \"content\": \"IyBUaGlzIGlzIGEgbDQgdXBzdHJlYW0gc25pcHBldCBjb21tZW50Cg==\"\n }\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"l4_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:53\"\n },\n {\n \"server\": \"10.0.0.2:53\"\n }\n ]\n }\n ]\n },\n \"http\": {\n \"servers\": [\n {\n \"name\": \"HTTP test application\",\n \"names\": [\n \"server_8080.nginx.lab\",\n \"server_8081.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"127.0.0.1:8080\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/access_log\",\n \"error\": \"/var/log/nginx/error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/test\",\n \"urimatch\": \"exact\",\n \"upstream\": \"http://test_upstream\",\n \"health_check\": {\n \"enabled\": true,\n \"uri\": \"/healthcheck\",\n \"interval\": 5,\n \"fails\": 3,\n \"passes\": 2\n },\n \"rate_limit\": {\n \"profile\": \"test_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 10,\n \"delay\": 3\n },\n \"app_protect\": {\n \"enabled\": true,\n \"policy\": \"test_policy\",\n \"log\": {\n \"profile_name\": \"log_illegal\",\n \"enabled\": true,\n \"destination\": \"192.168.1.5:514\"\n }\n },\n \"snippet\": {\n \"content\": \"IyBUaGlzIGlzIGEgbG9jYXRpb24gc25pcHBldCBjb21tZW50Cg==\"\n }\n }\n ],\n \"app_protect\": {\n \"enabled\": true,\n \"policy\": \"test_policy\",\n \"log\": {\n \"profile_name\": \"log_blocked\",\n \"enabled\": true,\n \"destination\": \"192.168.1.5:514\"\n }\n },\n \"snippet\": {\n \"content\": \"IyBUaGlzIGlzIGEgc2VydmVyIHNuaXBwZXQgY29tbWVudAo=\"\n }\n },\n {\n \"name\": \"another HTTP test application\",\n \"names\": [\n \"server_443\"\n ],\n \"listen\": {\n \"address\": \"127.0.0.1:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"upstream\": \"http://test_upstream\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:80\",\n \"weight\": 5,\n \"max_fails\": 2,\n \"fail_timeout\": \"30s\",\n \"max_conns\": 3,\n \"slow_start\": \"30s\"\n },\n {\n \"server\": \"10.0.0.2:80\",\n \"backup\": true\n }\n ],\n \"sticky\": {\n \"cookie\": \"cookie_name\",\n \"expires\": \"1h\",\n \"domain\": \".testserver\",\n \"path\": \"/\"\n },\n \"snippet\": {\n \"content\": \"IyBUaGlzIGlzIGEgdXBzdHJlYW0gc25pcHBldCBjb21tZW50Cg==\"\n }\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"test_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"1r/s\"\n }\n ],\n \"maps\": [\n {\n \"match\": \"$host$request_uri\",\n \"variable\": \"$backend\",\n \"entries\": [\n {\n \"key\": \"www.test.lab/app1/\",\n \"keymatch\": \"iregex\",\n \"value\": \"upstream_1\"\n },\n {\n \"key\": \"(.*).test.lab/app2/\",\n \"keymatch\": \"regex\",\n \"value\": \"upstream_2\"\n }\n ]\n }\n ],\n \"nginx_plus_api\": {\n \"write\": true,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"snippet\": {\n \"content\": \"IyBUaGlzIGlzIGEgSFRUUCBzbmlwcGV0IGNvbW1lbnQK\"\n }\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -271,7 +272,8 @@
"exec": [
""
],
- "type": "text/javascript"
+ "type": "text/javascript",
+ "packages": {}
}
}
],
@@ -280,7 +282,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"configmap\",\n \"configmap\": {\n \"name\": \"nginx.test\",\n \"filename\": \"testservice.conf\",\n \"namespace\": \"test-namespace\"\n }\n },\n \"declaration\": {\n \"layer4\": {\n \"servers\": [\n {\n \"name\": \"sample_layer4_service\",\n \"listen\": {\n \"address\": \"10053\",\n \"protocol\": \"tcp\",\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"upstream\": \"l4_upstream\",\n \"snippet\": \"IyBUaGlzIGlzIGEgbDQgdXBzdHJlYW0gc25pcHBldCBjb21tZW50Cg==\"\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"l4_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:53\"\n },\n {\n \"server\": \"10.0.0.2:53\"\n }\n ]\n }\n ]\n },\n \"http\": {\n \"servers\": [\n {\n \"name\": \"HTTP test application\",\n \"names\": [\n \"server_8080.nginx.lab\",\n \"server_8081.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"127.0.0.1:8080\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/access_log\",\n \"error\": \"/var/log/nginx/error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/test\",\n \"urimatch\": \"exact\",\n \"upstream\": \"http://test_upstream\",\n \"health_check\": {\n \"enabled\": true,\n \"uri\": \"/healthcheck\",\n \"interval\": 5,\n \"fails\": 3,\n \"passes\": 2\n },\n \"rate_limit\": {\n \"profile\": \"test_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 10,\n \"delay\": 3\n },\n \"app_protect\": {\n \"enabled\": true,\n \"policy\": \"test_policy\",\n \"log\": {\n \"profile_name\": \"log_illegal\",\n \"enabled\": true,\n \"destination\": \"192.168.1.5:514\"\n }\n },\n \"snippet\": \"IyBUaGlzIGlzIGEgbG9jYXRpb24gc25pcHBldCBjb21tZW50Cg==\"\n }\n ],\n \"app_protect\": {\n \"enabled\": true,\n \"policy\": \"test_policy\",\n \"log\": {\n \"profile_name\": \"log_blocked\",\n \"enabled\": true,\n \"destination\": \"192.168.1.5:514\"\n }\n },\n \"snippet\": \"IyBUaGlzIGlzIGEgc2VydmVyIHNuaXBwZXQgY29tbWVudAo=\"\n },\n {\n \"name\": \"another HTTP test application\",\n \"names\": [\n \"server_443\"\n ],\n \"listen\": {\n \"address\": \"127.0.0.1:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"upstream\": \"http://test_upstream\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:80\",\n \"weight\": 5,\n \"max_fails\": 2,\n \"fail_timeout\": \"30s\",\n \"max_conns\": 3,\n \"slow_start\": \"30s\"\n },\n {\n \"server\": \"10.0.0.2:80\",\n \"backup\": true\n }\n ],\n \"sticky\": {\n \"cookie\": \"cookie_name\",\n \"expires\": \"1h\",\n \"domain\": \".testserver\",\n \"path\": \"/\"\n },\n \"snippet\": \"IyBUaGlzIGlzIGEgdXBzdHJlYW0gc25pcHBldCBjb21tZW50Cg==\"\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"test_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"1r/s\"\n }\n ],\n \"maps\": [\n {\n \"match\": \"$host$request_uri\",\n \"variable\": \"$backend\",\n \"entries\": [\n {\n \"key\": \"www.test.lab/app1/\",\n \"keymatch\": \"iregex\",\n \"value\": \"upstream_1\"\n },\n {\n \"key\": \"(.*).test.lab/app2/\",\n \"keymatch\": \"regex\",\n \"value\": \"upstream_2\"\n }\n ]\n }\n ],\n \"nginx_plus_api\": {\n \"write\": true,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"snippet\": \"IyBUaGlzIGlzIGEgSFRUUCBzbmlwcGV0IGNvbW1lbnQK\"\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"configmap\",\n \"configmap\": {\n \"name\": \"nginx.test\",\n \"filename\": \"testservice.conf\",\n \"namespace\": \"test-namespace\"\n }\n },\n \"declaration\": {\n \"layer4\": {\n \"servers\": [\n {\n \"name\": \"sample_layer4_service\",\n \"listen\": {\n \"address\": \"10053\",\n \"protocol\": \"tcp\",\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"upstream\": \"l4_upstream\",\n \"snippet\": {\n \"content\": \"IyBUaGlzIGlzIGEgbDQgdXBzdHJlYW0gc25pcHBldCBjb21tZW50Cg==\"\n }\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"l4_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:53\"\n },\n {\n \"server\": \"10.0.0.2:53\"\n }\n ]\n }\n ]\n },\n \"http\": {\n \"servers\": [\n {\n \"name\": \"HTTP test application\",\n \"names\": [\n \"server_8080.nginx.lab\",\n \"server_8081.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"127.0.0.1:8080\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/access_log\",\n \"error\": \"/var/log/nginx/error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/test\",\n \"urimatch\": \"exact\",\n \"upstream\": \"http://test_upstream\",\n \"health_check\": {\n \"enabled\": true,\n \"uri\": \"/healthcheck\",\n \"interval\": 5,\n \"fails\": 3,\n \"passes\": 2\n },\n \"rate_limit\": {\n \"profile\": \"test_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 10,\n \"delay\": 3\n },\n \"app_protect\": {\n \"enabled\": true,\n \"policy\": \"test_policy\",\n \"log\": {\n \"profile_name\": \"log_illegal\",\n \"enabled\": true,\n \"destination\": \"192.168.1.5:514\"\n }\n },\n \"snippet\": {\n \"content\": \"IyBUaGlzIGlzIGEgbG9jYXRpb24gc25pcHBldCBjb21tZW50Cg==\"\n }\n }\n ],\n \"app_protect\": {\n \"enabled\": true,\n \"policy\": \"test_policy\",\n \"log\": {\n \"profile_name\": \"log_blocked\",\n \"enabled\": true,\n \"destination\": \"192.168.1.5:514\"\n }\n },\n \"snippet\": {\n \"content\": \"IyBUaGlzIGlzIGEgc2VydmVyIHNuaXBwZXQgY29tbWVudAo=\"\n }\n },\n {\n \"name\": \"another HTTP test application\",\n \"names\": [\n \"server_443\"\n ],\n \"listen\": {\n \"address\": \"127.0.0.1:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"upstream\": \"http://test_upstream\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:80\",\n \"weight\": 5,\n \"max_fails\": 2,\n \"fail_timeout\": \"30s\",\n \"max_conns\": 3,\n \"slow_start\": \"30s\"\n },\n {\n \"server\": \"10.0.0.2:80\",\n \"backup\": true\n }\n ],\n \"sticky\": {\n \"cookie\": \"cookie_name\",\n \"expires\": \"1h\",\n \"domain\": \".testserver\",\n \"path\": \"/\"\n },\n \"snippet\": {\n \"content\": \"IyBUaGlzIGlzIGEgdXBzdHJlYW0gc25pcHBldCBjb21tZW50Cg==\"\n }\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"test_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"1r/s\"\n }\n ],\n \"maps\": [\n {\n \"match\": \"$host$request_uri\",\n \"variable\": \"$backend\",\n \"entries\": [\n {\n \"key\": \"www.test.lab/app1/\",\n \"keymatch\": \"iregex\",\n \"value\": \"upstream_1\"\n },\n {\n \"key\": \"(.*).test.lab/app2/\",\n \"keymatch\": \"regex\",\n \"value\": \"upstream_2\"\n }\n ]\n }\n ],\n \"nginx_plus_api\": {\n \"write\": true,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"snippet\": {\n \"content\": \"IyBUaGlzIGlzIGEgSFRUUCBzbmlwcGV0IGNvbW1lbnQK\"\n }\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -311,7 +313,8 @@
"exec": [
""
],
- "type": "text/javascript"
+ "type": "text/javascript",
+ "packages": {}
}
}
],
@@ -320,7 +323,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"http\",\n \"http\": {\n \"url\": \"http://192.168.1.19:8080/path/service\"\n }\n },\n \"declaration\": {\n \"layer4\": {\n \"servers\": [\n {\n \"name\": \"sample_layer4_service\",\n \"listen\": {\n \"address\": \"10053\",\n \"protocol\": \"tcp\",\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"upstream\": \"l4_upstream\",\n \"snippet\": \"IyBUaGlzIGlzIGEgbDQgdXBzdHJlYW0gc25pcHBldCBjb21tZW50Cg==\"\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"l4_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:53\"\n },\n {\n \"server\": \"10.0.0.2:53\"\n }\n ]\n }\n ]\n },\n \"http\": {\n \"servers\": [\n {\n \"name\": \"HTTP test application\",\n \"names\": [\n \"server_8080.nginx.lab\",\n \"server_8081.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"127.0.0.1:8080\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/access_log\",\n \"error\": \"/var/log/nginx/error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/test\",\n \"urimatch\": \"exact\",\n \"upstream\": \"http://test_upstream\",\n \"health_check\": {\n \"enabled\": true,\n \"uri\": \"/healthcheck\",\n \"interval\": 5,\n \"fails\": 3,\n \"passes\": 2\n },\n \"rate_limit\": {\n \"profile\": \"test_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 10,\n \"delay\": 3\n },\n \"app_protect\": {\n \"enabled\": true,\n \"policy\": \"test_policy\",\n \"log\": {\n \"profile_name\": \"log_illegal\",\n \"enabled\": true,\n \"destination\": \"192.168.1.5:514\"\n }\n },\n \"snippet\": \"IyBUaGlzIGlzIGEgbG9jYXRpb24gc25pcHBldCBjb21tZW50Cg==\"\n }\n ],\n \"app_protect\": {\n \"enabled\": true,\n \"policy\": \"test_policy\",\n \"log\": {\n \"profile_name\": \"log_blocked\",\n \"enabled\": true,\n \"destination\": \"192.168.1.5:514\"\n }\n },\n \"snippet\": \"IyBUaGlzIGlzIGEgc2VydmVyIHNuaXBwZXQgY29tbWVudAo=\"\n },\n {\n \"name\": \"another HTTP test application\",\n \"names\": [\n \"server_443\"\n ],\n \"listen\": {\n \"address\": \"127.0.0.1:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"upstream\": \"http://test_upstream\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:80\",\n \"weight\": 5,\n \"max_fails\": 2,\n \"fail_timeout\": \"30s\",\n \"max_conns\": 3,\n \"slow_start\": \"30s\"\n },\n {\n \"server\": \"10.0.0.2:80\",\n \"backup\": true\n }\n ],\n \"sticky\": {\n \"cookie\": \"cookie_name\",\n \"expires\": \"1h\",\n \"domain\": \".testserver\",\n \"path\": \"/\"\n },\n \"snippet\": \"IyBUaGlzIGlzIGEgdXBzdHJlYW0gc25pcHBldCBjb21tZW50Cg==\"\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"test_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"1r/s\"\n }\n ],\n \"maps\": [\n {\n \"match\": \"$host$request_uri\",\n \"variable\": \"$backend\",\n \"entries\": [\n {\n \"key\": \"www.test.lab/app1/\",\n \"keymatch\": \"iregex\",\n \"value\": \"upstream_1\"\n },\n {\n \"key\": \"(.*).test.lab/app2/\",\n \"keymatch\": \"regex\",\n \"value\": \"upstream_2\"\n }\n ]\n }\n ],\n \"nginx_plus_api\": {\n \"write\": true,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"snippet\": \"IyBUaGlzIGlzIGEgSFRUUCBzbmlwcGV0IGNvbW1lbnQK\"\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"http\",\n \"http\": {\n \"url\": \"http://192.168.1.19:8080/path/service\"\n }\n },\n \"declaration\": {\n \"layer4\": {\n \"servers\": [\n {\n \"name\": \"sample_layer4_service\",\n \"listen\": {\n \"address\": \"10053\",\n \"protocol\": \"tcp\",\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"upstream\": \"l4_upstream\",\n \"snippet\": {\n \"content\": \"IyBUaGlzIGlzIGEgbDQgdXBzdHJlYW0gc25pcHBldCBjb21tZW50Cg==\"\n }\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"l4_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:53\"\n },\n {\n \"server\": \"10.0.0.2:53\"\n }\n ]\n }\n ]\n },\n \"http\": {\n \"servers\": [\n {\n \"name\": \"HTTP test application\",\n \"names\": [\n \"server_8080.nginx.lab\",\n \"server_8081.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"127.0.0.1:8080\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/access_log\",\n \"error\": \"/var/log/nginx/error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/test\",\n \"urimatch\": \"exact\",\n \"upstream\": \"http://test_upstream\",\n \"health_check\": {\n \"enabled\": true,\n \"uri\": \"/healthcheck\",\n \"interval\": 5,\n \"fails\": 3,\n \"passes\": 2\n },\n \"rate_limit\": {\n \"profile\": \"test_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 10,\n \"delay\": 3\n },\n \"app_protect\": {\n \"enabled\": true,\n \"policy\": \"test_policy\",\n \"log\": {\n \"profile_name\": \"log_illegal\",\n \"enabled\": true,\n \"destination\": \"192.168.1.5:514\"\n }\n },\n \"snippet\": {\n \"content\": \"IyBUaGlzIGlzIGEgbG9jYXRpb24gc25pcHBldCBjb21tZW50Cg==\"\n }\n }\n ],\n \"app_protect\": {\n \"enabled\": true,\n \"policy\": \"test_policy\",\n \"log\": {\n \"profile_name\": \"log_blocked\",\n \"enabled\": true,\n \"destination\": \"192.168.1.5:514\"\n }\n },\n \"snippet\": {\n \"content\": \"IyBUaGlzIGlzIGEgc2VydmVyIHNuaXBwZXQgY29tbWVudAo=\"\n }\n },\n {\n \"name\": \"another HTTP test application\",\n \"names\": [\n \"server_443\"\n ],\n \"listen\": {\n \"address\": \"127.0.0.1:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"upstream\": \"http://test_upstream\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:80\",\n \"weight\": 5,\n \"max_fails\": 2,\n \"fail_timeout\": \"30s\",\n \"max_conns\": 3,\n \"slow_start\": \"30s\"\n },\n {\n \"server\": \"10.0.0.2:80\",\n \"backup\": true\n }\n ],\n \"sticky\": {\n \"cookie\": \"cookie_name\",\n \"expires\": \"1h\",\n \"domain\": \".testserver\",\n \"path\": \"/\"\n },\n \"snippet\": {\n \"content\": \"IyBUaGlzIGlzIGEgdXBzdHJlYW0gc25pcHBldCBjb21tZW50Cg==\"\n }\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"test_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"1r/s\"\n }\n ],\n \"maps\": [\n {\n \"match\": \"$host$request_uri\",\n \"variable\": \"$backend\",\n \"entries\": [\n {\n \"key\": \"www.test.lab/app1/\",\n \"keymatch\": \"iregex\",\n \"value\": \"upstream_1\"\n },\n {\n \"key\": \"(.*).test.lab/app2/\",\n \"keymatch\": \"regex\",\n \"value\": \"upstream_2\"\n }\n ]\n }\n ],\n \"nginx_plus_api\": {\n \"write\": true,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"snippet\": {\n \"content\": \"IyBUaGlzIGlzIGEgSFRUUCBzbmlwcGV0IGNvbW1lbnQK\"\n }\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -368,7 +371,8 @@
"",
"pm.collectionVariables.set('configUid',respData.configUid);"
],
- "type": "text/javascript"
+ "type": "text/javascript",
+ "packages": {}
}
}
],
@@ -377,7 +381,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Ergast API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"8.8.8.8\",\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/apigw.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/apigw.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/ergast\",\n \"urimatch\": \"prefix\",\n \"snippet\": {\n \"content\": \"IyBUZXN0IFNOSVBQRVQK\"\n },\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://raw.githubusercontent.com/adampax/ergast-f1-openapi-doc/e558eea18e176e4f78a8765ac7eccc804b5157ff/ergast-openapi-doc.yaml\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"uri\": \"/ergast-devportal.html\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/ergast-access_log\",\n \"error\": \"/var/log/nginx/ergast-error_log\"\n }\n }\n }\n ]\n }\n ]\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Ergast API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"8.8.8.8\",\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/apigw.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/apigw.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/ergast\",\n \"urimatch\": \"prefix\",\n \"snippet\": {\n \"content\": \"IyBUZXN0IFNOSVBQRVQK\"\n },\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://raw.githubusercontent.com/adampax/ergast-f1-openapi-doc/e558eea18e176e4f78a8765ac7eccc804b5157ff/ergast-openapi-doc.yaml\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"uri\": \"/ergast-devportal.html\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/ergast-access_log\",\n \"error\": \"/var/log/nginx/ergast-error_log\"\n }\n }\n }\n ]\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -417,7 +421,8 @@
"",
"pm.collectionVariables.set('configUid',respData.configUid);"
],
- "type": "text/javascript"
+ "type": "text/javascript",
+ "packages": {}
}
}
],
@@ -426,7 +431,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"8.8.8.8\",\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/apigw.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/apigw.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"http://petstore.swagger.io/v2/swagger.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore.swagger.io/v2\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"uri\": \"/petstore-devportal.html\"\n },\n \"rate_limit\": [\n {\n \"profile\": \"petstore_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 0,\n \"delay\": 0,\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\"\n ]\n }\n ]\n },\n \"log\": {\n \"access\": \"/var/log/nginx/petstore-access_log\",\n \"error\": \"/var/log/nginx/petstore-error_log\"\n }\n }\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"petstore_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"2r/s\"\n }\n ]\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"8.8.8.8\",\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/apigw.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/apigw.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"name\": \"Petstore API Gateway\",\n \"openapi_schema\": {\n \"content\": \"http://petstore.swagger.io/v2/swagger.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore.swagger.io/v2\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"uri\": \"/petstore-devportal.html\"\n },\n \"rate_limit\": [\n {\n \"profile\": \"petstore_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 0,\n \"delay\": 0,\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\"\n ]\n }\n ]\n },\n \"log\": {\n \"access\": \"/var/log/nginx/petstore-access_log\",\n \"error\": \"/var/log/nginx/petstore-error_log\"\n }\n }\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"petstore_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"2r/s\"\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -449,7 +454,7 @@
"response": []
},
{
- "name": "Petstore API Gateway RateLimit + JWT Authentication",
+ "name": "Petstore API Gateway RateLimit + JWT AuthN/AuthZ",
"event": [
{
"listen": "test",
@@ -461,7 +466,53 @@
"",
"pm.collectionVariables.set('configUid',respData.configUid);"
],
- "type": "text/javascript"
+ "type": "text/javascript",
+ "packages": {}
+ }
+ }
+ ],
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"8.8.8.8\",\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/apigw.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/apigw.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"http://petstore.swagger.io/v2/swagger.json\",\n \"authentication\": [\n {\n \"profile\": \"Source of truth authentication profile using HTTP header token authentication\"\n }\n ]\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore.swagger.io/v2\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"uri\": \"/petstore-devportal.html\"\n },\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"Petstore JWT Authentication\"\n }\n ],\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\"\n ]\n },\n \"authorization\": [\n {\n \"profile\": \"JWT role based authorization\",\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\"\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"profile\": \"petstore_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 0,\n \"delay\": 0,\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\"\n ]\n }\n ]\n },\n \"log\": {\n \"access\": \"/var/log/nginx/petstore-access_log\",\n \"error\": \"/var/log/nginx/petstore-error_log\"\n }\n }\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"petstore_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"2r/s\"\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"Petstore JWT Authentication\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"Petstore Authentication\",\n \"key\": \"{\\\"keys\\\": [{\\\"k\\\":\\\"ZmFudGFzdGljand0\\\",\\\"kty\\\":\\\"oct\\\",\\\"kid\\\":\\\"0001\\\"}]}\",\n \"cachetime\": 5\n }\n }\n ],\n \"server\": [\n {\n \"name\": \"Source of truth authentication profile using bearer token authentication\",\n \"type\": \"token\",\n \"token\": {\n \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDI0ODEzNjcsImV4cCI6MTcwMjQ4MTM2OH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIl19.SKA_7MszAypMEtX5NDQ0TcUbVYx_Wt0hrtmuyTmrVKU\",\n \"type\": \"bearer\"\n }\n },\n {\n \"name\": \"Source of truth authentication profile using HTTP header token authentication\",\n \"type\": \"token\",\n \"token\": {\n \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDI0ODEzNjcsImV4cCI6MTcwMjQ4MTM2OH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIl19.SKA_7MszAypMEtX5NDQ0TcUbVYx_Wt0hrtmuyTmrVKU\",\n \"type\": \"header\",\n \"location\": \"X-AUTH-TOKEN\"\n }\n }\n ]\n },\n \"authorization\": [\n {\n \"name\": \"JWT role based authorization\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"claims\": [\n {\n \"name\": \"roles\",\n \"value\": [\n \"~(devops)\"\n ]\n }\n ]\n }\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Petstore API Gateway RateLimit + JWT AuthN/AuthZ + WAF",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript",
+ "packages": {}
}
}
],
@@ -470,7 +521,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"8.8.8.8\",\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/apigw.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/apigw.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"http://petstore.swagger.io/v2/swagger.json\",\n \"authentication\": [\n {\n \"profile\": \"Source of truth authentication profile using HTTP header token authentication\"\n }\n ]\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore.swagger.io/v2\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"uri\": \"/petstore-devportal.html\"\n },\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"Petstore JWT Authentication\"\n }\n ],\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\"\n ]\n },\n \"rate_limit\": [\n {\n \"profile\": \"petstore_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 0,\n \"delay\": 0,\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\"\n ]\n }\n ]\n },\n \"log\": {\n \"access\": \"/var/log/nginx/petstore-access_log\",\n \"error\": \"/var/log/nginx/petstore-error_log\"\n }\n }\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"petstore_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"2r/s\"\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"Petstore JWT Authentication\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"Petstore Authentication\",\n \"key\": \"{\\\"keys\\\": [{\\\"k\\\":\\\"ZmFudGFzdGljand0\\\",\\\"kty\\\":\\\"oct\\\",\\\"kid\\\":\\\"0001\\\"}]}\",\n \"cachetime\": 5\n }\n }\n ],\n \"server\": [\n {\n \"name\": \"Source of truth authentication profile using bearer token authentication\",\n \"type\": \"token\",\n \"token\": {\n \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDI0ODEzNjcsImV4cCI6MTcwMjQ4MTM2OH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIl19.SKA_7MszAypMEtX5NDQ0TcUbVYx_Wt0hrtmuyTmrVKU\",\n \"type\": \"bearer\"\n }\n },\n {\n \"name\": \"Source of truth authentication profile using HTTP header token authentication\",\n \"type\": \"token\",\n \"token\": {\n \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDI0ODEzNjcsImV4cCI6MTcwMjQ4MTM2OH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIl19.SKA_7MszAypMEtX5NDQ0TcUbVYx_Wt0hrtmuyTmrVKU\",\n \"type\": \"header\",\n \"location\": \"X-AUTH-TOKEN\"\n }\n }\n ]\n }\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert.key\"\n }\n }\n ],\n \"policies\": [\n {\n \"type\": \"app_protect\",\n \"name\": \"production-policy\",\n \"active_tag\": \"xss-blocked\",\n \"versions\": [\n {\n \"tag\": \"xss-blocked\",\n \"displayName\": \"Production Policy - XSS blocked\",\n \"description\": \"This is a production-ready policy - XSS blocked\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/nap-policy-xss-blocked-bot-allowed.json\"\n }\n },\n {\n \"tag\": \"xss-allowed\",\n \"displayName\": \"Production Policy - XSS allowed\",\n \"description\": \"This is a production-ready policy - XSS allowed\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"8.8.8.8\",\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/apigw.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/apigw.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"http://petstore.swagger.io/v2/swagger.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore.swagger.io/v2\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"uri\": \"/petstore-devportal.html\"\n },\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"Petstore JWT Authentication\"\n }\n ],\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\",\n \"/pet/{petId}/uploadImage\"\n ]\n },\n \"authorization\": [\n {\n \"profile\": \"JWT role based authorization\",\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\",\n \"/pet/{petId}/uploadImage\"\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"profile\": \"petstore_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 0,\n \"delay\": 0,\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\",\n \"/pet/{petId}/uploadImage\"\n ]\n }\n ]\n },\n \"log\": {\n \"access\": \"/var/log/nginx/petstore-access_log\",\n \"error\": \"/var/log/nginx/petstore-error_log\"\n },\n \"app_protect\": {\n \"enabled\": true,\n \"policy\": \"production-policy\",\n \"log\": {\n \"profile_name\": \"secops_dashboard\",\n \"enabled\": true,\n \"destination\": \"127.0.0.1:514\"\n }\n }\n }\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"petstore_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"2r/s\"\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"Petstore JWT Authentication\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"Petstore Authentication\",\n \"key\": \"{\\\"keys\\\": [{\\\"k\\\":\\\"ZmFudGFzdGljand0\\\",\\\"kty\\\":\\\"oct\\\",\\\"kid\\\":\\\"0001\\\"}]}\",\n \"cachetime\": 5\n }\n }\n ]\n },\n \"authorization\": [\n {\n \"name\": \"JWT role based authorization\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"claims\": [\n {\n \"name\": \"roles\",\n \"value\": [\n \"~(devops)\"\n ],\n \"errorcode\": 403\n }\n ]\n }\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -507,7 +558,8 @@
"",
"pm.collectionVariables.set('configUid',respData.configUid);"
],
- "type": "text/javascript"
+ "type": "text/javascript",
+ "packages": {}
}
}
],
@@ -516,7 +568,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore and Ergast API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"192.168.2.13\",\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/apigw.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/apigw.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"http://petstore.swagger.io/v2/swagger.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore.swagger.io/v2\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"uri\": \"/petstore-devportal.html\"\n },\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"Petstore JWT Authentication\"\n }\n ],\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\"\n ]\n },\n \"rate_limit\": [\n {\n \"profile\": \"petstore_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 0,\n \"delay\": 0,\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\"\n ]\n }\n ],\n \"log\": {\n \"access\": \"/var/log/nginx/petstore-access_log\",\n \"error\": \"/var/log/nginx/petstore-error_log\"\n }\n }\n },\n {\n \"uri\": \"/ergast\",\n \"urimatch\": \"prefix\",\n \"snippet\": {\n \"content\": \"IyBUZXN0IFNOSVBQRVQK\"\n },\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://raw.githubusercontent.com/adampax/ergast-f1-openapi-doc/e558eea18e176e4f78a8765ac7eccc804b5157ff/ergast-openapi-doc.yaml\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"uri\": \"/ergast-devportal.html\"\n },\n \"rate_limit\": [\n {\n \"profile\": \"ergast_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 0,\n \"delay\": 0\n }\n ],\n \"log\": {\n \"access\": \"/var/log/nginx/ergast-access_log\",\n \"error\": \"/var/log/nginx/ergast-error_log\"\n }\n }\n }\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"ergast_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"1r/s\"\n },\n {\n \"name\": \"petstore_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"2r/s\"\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"Petstore JWT Authentication\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"Petstore Authentication\",\n \"key\": \"{\\\"keys\\\": [{\\\"k\\\":\\\"ZmFudGFzdGljand0\\\",\\\"kty\\\":\\\"oct\\\",\\\"kid\\\":\\\"0001\\\"}]}\",\n \"cachetime\": 5\n }\n }\n ]\n }\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore and Ergast API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"192.168.2.13\",\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/apigw.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/apigw.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"http://petstore.swagger.io/v2/swagger.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore.swagger.io/v2\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"uri\": \"/petstore-devportal.html\"\n },\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"Petstore JWT Authentication\"\n }\n ],\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\"\n ]\n },\n \"rate_limit\": [\n {\n \"profile\": \"petstore_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 0,\n \"delay\": 0,\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\"\n ]\n }\n ],\n \"log\": {\n \"access\": \"/var/log/nginx/petstore-access_log\",\n \"error\": \"/var/log/nginx/petstore-error_log\"\n }\n }\n },\n {\n \"uri\": \"/ergast\",\n \"urimatch\": \"prefix\",\n \"snippet\": {\n \"content\": \"IyBUZXN0IFNOSVBQRVQK\"\n },\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://raw.githubusercontent.com/adampax/ergast-f1-openapi-doc/e558eea18e176e4f78a8765ac7eccc804b5157ff/ergast-openapi-doc.yaml\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"uri\": \"/ergast-devportal.html\"\n },\n \"rate_limit\": [\n {\n \"profile\": \"ergast_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 0,\n \"delay\": 0\n }\n ],\n \"log\": {\n \"access\": \"/var/log/nginx/ergast-access_log\",\n \"error\": \"/var/log/nginx/ergast-error_log\"\n }\n }\n }\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"ergast_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"1r/s\"\n },\n {\n \"name\": \"petstore_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"2r/s\"\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"Petstore JWT Authentication\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"Petstore Authentication\",\n \"key\": \"{\\\"keys\\\": [{\\\"k\\\":\\\"ZmFudGFzdGljand0\\\",\\\"kty\\\":\\\"oct\\\",\\\"kid\\\":\\\"0001\\\"}]}\",\n \"cachetime\": 5\n }\n }\n ]\n }\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -556,7 +608,8 @@
"",
"pm.collectionVariables.set('configUid',respData.configUid);"
],
- "type": "text/javascript"
+ "type": "text/javascript",
+ "packages": {}
}
}
],
@@ -565,7 +618,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\",\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"HTTP test application\",\n \"names\": [\n \"patched_server.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"127.0.0.1:8080\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/access_log\",\n \"error\": \"/var/log/nginx/error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:80\"\n },\n {\n \"server\": \"10.0.0.2:80\"\n }\n ]\n }\n ]\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"HTTP test application\",\n \"names\": [\n \"patched_server.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"127.0.0.1:8080\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/access_log\",\n \"error\": \"/var/log/nginx/error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:80\"\n },\n {\n \"server\": \"10.0.0.2:80\"\n }\n ]\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -600,7 +653,8 @@
"",
"pm.collectionVariables.set('configUid',respData.configUid);"
],
- "type": "text/javascript"
+ "type": "text/javascript",
+ "packages": {}
}
}
],
@@ -609,7 +663,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\",\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:80\"\n },\n {\n \"server\": \"10.0.0.2:80\"\n },\n {\n \"server\": \"10.0.0.3:80\"\n },\n {\n \"server\": \"10.0.0.4:80\"\n },\n {\n \"server\": \"10.0.0.5:80\"\n }\n ]\n }\n ]\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:80\"\n },\n {\n \"server\": \"10.0.0.2:80\"\n },\n {\n \"server\": \"10.0.0.3:80\"\n },\n {\n \"server\": \"10.0.0.4:80\"\n },\n {\n \"server\": \"10.0.0.5:80\"\n }\n ]\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -645,7 +699,8 @@
"",
"pm.collectionVariables.set('configUid',respData.configUid);"
],
- "type": "text/javascript"
+ "type": "text/javascript",
+ "packages": {}
}
}
],
@@ -654,7 +709,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\",\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:80\"\n },\n {\n \"server\": \"10.0.0.2:80\"\n }\n ]\n },\n {\n \"name\": \"test_upstream_added\",\n \"origin\": [\n {\n \"server\": \"192.168.1.1:80\"\n },\n {\n \"server\": \"192.168.1.2:80\"\n }\n ]\n }\n ]\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:80\"\n },\n {\n \"server\": \"10.0.0.2:80\"\n }\n ]\n },\n {\n \"name\": \"test_upstream_added\",\n \"origin\": [\n {\n \"server\": \"192.168.1.1:80\"\n },\n {\n \"server\": \"192.168.1.2:80\"\n }\n ]\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -690,7 +745,8 @@
"",
"pm.collectionVariables.set('configUid',respData.configUid);"
],
- "type": "text/javascript"
+ "type": "text/javascript",
+ "packages": {}
}
}
],
@@ -699,7 +755,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\",\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"HTTP test application\",\n \"names\": [\n \"patched_server_v2.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"127.0.0.1:8080\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/access_v2_log\",\n \"error\": \"/var/log/nginx/error_v2_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream_added\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream_added\",\n \"origin\": [\n {\n \"server\": \"192.168.1.100:80\",\n \"weight\": 5,\n \"max_fails\": 2,\n \"fail_timeout\": \"30s\",\n \"max_conns\": 3,\n \"slow_start\": \"30s\"\n },\n {\n \"server\": \"192.168.1.101:80\"\n },\n {\n \"server\": \"192.168.1.102:80\"\n },\n {\n \"server\": \"192.168.1.103:80\"\n }\n ]\n }\n ]\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"HTTP test application\",\n \"names\": [\n \"patched_server_v2.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"127.0.0.1:8080\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/access_v2_log\",\n \"error\": \"/var/log/nginx/error_v2_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream_added\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream_added\",\n \"origin\": [\n {\n \"server\": \"192.168.1.100:80\",\n \"weight\": 5,\n \"max_fails\": 2,\n \"fail_timeout\": \"30s\",\n \"max_conns\": 3,\n \"slow_start\": \"30s\"\n },\n {\n \"server\": \"192.168.1.101:80\"\n },\n {\n \"server\": \"192.168.1.102:80\"\n },\n {\n \"server\": \"192.168.1.103:80\"\n }\n ]\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -735,7 +791,8 @@
"",
"pm.collectionVariables.set('configUid',respData.configUid);"
],
- "type": "text/javascript"
+ "type": "text/javascript",
+ "packages": {}
}
}
],
@@ -744,7 +801,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\",\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"HTTP test application\"\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream_added\"\n }\n ]\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"HTTP test application\"\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream_added\"\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -780,7 +837,8 @@
"",
"pm.collectionVariables.set('configUid',respData.configUid);"
],
- "type": "text/javascript"
+ "type": "text/javascript",
+ "packages": {}
}
}
],
@@ -789,7 +847,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\",\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n }\n },\n \"declaration\": {\n \"layer4\": {\n \"servers\": [\n {\n \"name\": \"TCP_10053_service\",\n \"listen\": {\n \"address\": \"10053\",\n \"protocol\": \"tcp\"\n },\n \"upstream\": \"TCP_10053_upstream\"\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"TCP_10053_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:53\"\n },\n {\n \"server\": \"10.0.0.2:53\"\n },\n {\n \"server\": \"10.0.0.3:53\"\n },\n {\n \"server\": \"10.0.0.4:53\"\n }\n ]\n }\n ]\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"layer4\": {\n \"servers\": [\n {\n \"name\": \"TCP_10053_service\",\n \"listen\": {\n \"address\": \"10053\",\n \"protocol\": \"tcp\"\n },\n \"upstream\": \"TCP_10053_upstream\"\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"TCP_10053_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:53\"\n },\n {\n \"server\": \"10.0.0.2:53\"\n },\n {\n \"server\": \"10.0.0.3:53\"\n },\n {\n \"server\": \"10.0.0.4:53\"\n }\n ]\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -825,7 +883,8 @@
"",
"pm.collectionVariables.set('configUid',respData.configUid);"
],
- "type": "text/javascript"
+ "type": "text/javascript",
+ "packages": {}
}
}
],
@@ -834,7 +893,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\",\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n }\n },\n \"declaration\": {\n \"layer4\": {\n \"servers\": [\n {\n \"name\": \"TCP_15432_service\",\n \"listen\": {\n \"address\": \"15432\",\n \"protocol\": \"tcp\"\n },\n \"upstream\": \"TCP_15432_upstream\"\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"TCP_15432_upstream\",\n \"origin\": [\n {\n \"server\": \"172.16.10.1:5432\"\n },\n {\n \"server\": \"172.16.10.1:5432\"\n }\n ]\n }\n ]\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"layer4\": {\n \"servers\": [\n {\n \"name\": \"TCP_15432_service\",\n \"listen\": {\n \"address\": \"15432\",\n \"protocol\": \"tcp\"\n },\n \"upstream\": \"TCP_15432_upstream\"\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"TCP_15432_upstream\",\n \"origin\": [\n {\n \"server\": \"172.16.10.1:5432\"\n },\n {\n \"server\": \"172.16.10.1:5432\"\n }\n ]\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -870,7 +929,8 @@
"",
"pm.collectionVariables.set('configUid',respData.configUid);"
],
- "type": "text/javascript"
+ "type": "text/javascript",
+ "packages": {}
}
}
],
@@ -879,7 +939,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\",\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n }\n },\n \"declaration\": {\n \"layer4\": {\n \"servers\": [\n {\n \"name\": \"TCP_10053_service\"\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"TCP_10053_upstream\"\n }\n ]\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"layer4\": {\n \"servers\": [\n {\n \"name\": \"TCP_10053_service\"\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"TCP_10053_upstream\"\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -915,7 +975,8 @@
"",
"pm.collectionVariables.set('configUid',respData.configUid);"
],
- "type": "text/javascript"
+ "type": "text/javascript",
+ "packages": {}
}
}
],
@@ -924,137 +985,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\",\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n }\n },\n \"declaration\": {\n \"layer4\": {\n \"servers\": [\n {\n \"name\": \"TCP_15432_service\"\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"TCP_15432_upstream\"\n }\n ]\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
- }
- }
- },
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
- ],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config",
- "{{configUid}}"
- ]
- }
- },
- "response": []
- },
- {
- "name": "Get declaration status",
- "event": [
- {
- "listen": "test",
- "script": {
- "exec": [
- ""
- ],
- "type": "text/javascript"
- }
- }
- ],
- "protocolProfileBehavior": {
- "disableBodyPruning": true
- },
- "request": {
- "method": "GET",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "",
- "options": {
- "raw": {
- "language": "json"
- }
- }
- },
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}/status",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
- ],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config",
- "{{configUid}}",
- "status"
- ]
- }
- },
- "response": []
- },
- {
- "name": "Get declaration",
- "event": [
- {
- "listen": "test",
- "script": {
- "exec": [
- ""
- ],
- "type": "text/javascript"
- }
- }
- ],
- "protocolProfileBehavior": {
- "disableBodyPruning": true
- },
- "request": {
- "method": "GET",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "",
- "options": {
- "raw": {
- "language": "json"
- }
- }
- },
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
- ],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config",
- "{{configUid}}"
- ]
- }
- },
- "response": []
- },
- {
- "name": "Delete declaration",
- "event": [
- {
- "listen": "test",
- "script": {
- "exec": [
- ""
- ],
- "type": "text/javascript"
- }
- }
- ],
- "request": {
- "method": "DELETE",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"layer4\": {\n \"servers\": [\n {\n \"name\": \"TCP_15432_service\"\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"TCP_15432_upstream\"\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -1318,7 +1249,8 @@
"",
"pm.collectionVariables.set('configUid',respData.configUid);"
],
- "type": "text/javascript"
+ "type": "text/javascript",
+ "packages": {}
}
}
],
@@ -1327,7 +1259,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\",\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n }\n },\n \"declaration\": {\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\"\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -1482,10 +1414,10 @@
]
},
{
- "name": "JWT Client Authentication",
+ "name": "HTTP Headers Manipulation",
"item": [
{
- "name": "JWT Client Authentication - local JWT key",
+ "name": "Create test echo service",
"event": [
{
"listen": "test",
@@ -1506,7 +1438,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online-boutique.lan-access_log\",\n \"error\": \"/var/log/nginx/online-boutique.lan-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://onlineboutique_upstream\",\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"online_boutique_jwt_authentication_local\"\n }\n ]\n }\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"onlineboutique_upstream\",\n \"origin\": [\n {\n \"server\": \"192.168.2.200:80\"\n }\n ]\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"online_boutique_jwt_authentication_local\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"Online Boutique Authentication\",\n \"key\": \"{\\\"keys\\\": [{\\\"k\\\":\\\"ZmFudGFzdGljand0\\\",\\\"kty\\\":\\\"oct\\\",\\\"kid\\\":\\\"0001\\\"}]}\",\n \"cachetime\": 5\n }\n },\n {\n \"name\": \"online_boutique_jwt_authentication_key_from_url\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"Online Boutique Authentication GitOps\",\n \"key\": \"http://192.168.2.19/jwks.json\",\n \"cachetime\": 5\n }\n }\n ]\n }\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test echo app\",\n \"names\": [\n \"echo.vm-test.ie.ff.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:80\"\n },\n \"resolver\": \"8.8.8.8\",\n \"log\": {\n \"access\": \"/var/log/nginx/test-echo-access_log\",\n \"error\": \"/var/log/nginx/test-echo-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test-echo-upstream\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test-echo-upstream\",\n \"origin\": [\n {\n \"server\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -1529,7 +1461,7 @@
"response": []
},
{
- "name": "Change to use JWT key stored on external URL",
+ "name": "Manipulate headers - server level",
"event": [
{
"listen": "test",
@@ -1550,7 +1482,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online-boutique.lan-access_log\",\n \"error\": \"/var/log/nginx/online-boutique.lan-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://onlineboutique_upstream\",\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"online_boutique_jwt_authentication_key_from_url\"\n }\n ]\n }\n }\n ]\n }\n ]\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test echo app\",\n \"names\": [\n \"echo.vm-test.ie.ff.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:80\"\n },\n \"resolver\": \"8.8.8.8\",\n \"log\": {\n \"access\": \"/var/log/nginx/test-echo-access_log\",\n \"error\": \"/var/log/nginx/test-echo-error_log\"\n },\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"X-Injected-Client-IP\",\n \"value\": \"$remote_addr\"\n },\n {\n \"name\": \"X-Injected-Echo-Test-Version\",\n \"value\": \"v1\"\n },\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ],\n \"delete\": [\n \"User-Agent\"\n ]\n },\n \"to_client\": {\n \"add\": [\n {\n \"name\": \"X-Injected-Response-Status\",\n \"value\": \"$status\"\n }\n ],\n \"delete\": [\n \"vary\"\n ],\n \"replace\": [\n {\n \"name\": \"Server\",\n \"value\": \"Echo Test Server\"\n }\n ]\n }\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test-echo-upstream\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test-echo-upstream\",\n \"origin\": [\n {\n \"server\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -1572,14 +1504,9 @@
}
},
"response": []
- }
- ]
- },
- {
- "name": "Load Balancing",
- "item": [
+ },
{
- "name": "Create Coffee App v1",
+ "name": "Manipulate headers - location level",
"event": [
{
"listen": "test",
@@ -1596,11 +1523,11 @@
}
],
"request": {
- "method": "POST",
+ "method": "PATCH",
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Coffee v1\",\n \"names\": [\n \"coffee-v1.vm-test.ie.ff.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/coffee-v1-access_log\",\n \"error\": \"/var/log/nginx/coffee-v1-error_log\"\n },\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"Host\",\n \"value\": \"coffee-v1.k8s.f5.ff.lan\"\n }\n ]\n },\n \"to_client\": {\n \"add\": [\n {\n \"name\": \"X-Response-Status\",\n \"value\": \"$status\"\n }\n ],\n \"delete\": [\n \"Date\"\n ],\n \"replace\": [\n {\n \"name\": \"Server\",\n \"value\": \"Hidden Server\"\n }\n ]\n }\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://coffee-v1\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"coffee-v1\",\n \"origin\": [\n {\n \"server\": \"192.168.2.47\"\n },\n {\n \"server\": \"192.168.2.48\"\n }\n ]\n }\n ]\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test echo app\",\n \"names\": [\n \"echo.vm-test.ie.ff.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:80\"\n },\n \"resolver\": \"8.8.8.8\",\n \"log\": {\n \"access\": \"/var/log/nginx/test-echo-access_log\",\n \"error\": \"/var/log/nginx/test-echo-error_log\"\n },\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"X-Injected-Client-IP\",\n \"value\": \"$remote_addr\"\n },\n {\n \"name\": \"X-Injected-Echo-Test-Version\",\n \"value\": \"v1\"\n },\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ],\n \"delete\": [\n \"User-Agent\"\n ]\n },\n \"to_client\": {\n \"add\": [\n {\n \"name\": \"X-Injected-Response-Status\",\n \"value\": \"$status\"\n }\n ],\n \"delete\": [\n \"vary\"\n ],\n \"replace\": [\n {\n \"name\": \"Server\",\n \"value\": \"Echo Test Server\"\n }\n ]\n }\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test-echo-upstream\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test-echo-upstream\",\n \"origin\": [\n {\n \"server\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -1608,7 +1535,7 @@
}
},
"url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
"protocol": "http",
"host": [
"{{ncg_host}}"
@@ -1616,34 +1543,43 @@
"port": "{{ncg_port}}",
"path": [
"{{ngc_api_version}}",
- "config"
+ "config",
+ "{{configUid}}"
]
}
},
"response": []
- },
+ }
+ ],
+ "description": "Test using:\n\n`curl -i echo.vm-test.ie.ff.lan`\n\nThe actual FQDN can be modified in the request JSON body"
+ },
+ {
+ "name": "HTTPS server",
+ "item": [
{
- "name": "Get declaration status",
+ "name": "TLS Offload",
"event": [
{
"listen": "test",
"script": {
"exec": [
- ""
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
],
- "type": "text/javascript"
+ "type": "text/javascript",
+ "packages": {}
}
}
],
- "protocolProfileBehavior": {
- "disableBodyPruning": true
- },
"request": {
- "method": "GET",
+ "method": "POST",
"header": [],
"body": {
"mode": "raw",
- "raw": "",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert.key\"\n }\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online_boutique_https_access_log\",\n \"error\": \"/var/log/nginx/online_boutique_https_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://upstream_boutique\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"upstream_boutique\",\n \"origin\": [\n {\n \"server\": \"192.168.2.200:80\"\n }\n ]\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -1651,7 +1587,7 @@
}
},
"url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}/status",
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
"protocol": "http",
"host": [
"{{ncg_host}}"
@@ -1659,36 +1595,36 @@
"port": "{{ncg_port}}",
"path": [
"{{ngc_api_version}}",
- "config",
- "{{configUid}}",
- "status"
+ "config"
]
}
},
"response": []
},
{
- "name": "Get declaration",
+ "name": "TLS Offload and NGINX App Protect",
"event": [
{
"listen": "test",
"script": {
"exec": [
- ""
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
],
- "type": "text/javascript"
+ "type": "text/javascript",
+ "packages": {}
}
}
],
- "protocolProfileBehavior": {
- "disableBodyPruning": true
- },
"request": {
- "method": "GET",
+ "method": "POST",
"header": [],
"body": {
"mode": "raw",
- "raw": "",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert.key\"\n }\n }\n ],\n \"policies\": [\n {\n \"type\": \"app_protect\",\n \"name\": \"production-policy\",\n \"active_tag\": \"xss-blocked\",\n \"versions\": [\n {\n \"tag\": \"xss-blocked\",\n \"displayName\": \"Production Policy - GitOps\",\n \"description\": \"This is a production-ready policy - Managed by GitOps\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/nap-policy-xss-blocked.json\"\n }\n }\n ]\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online_boutique_https_access_log\",\n \"error\": \"/var/log/nginx/online_boutique_https_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://upstream_boutique\"\n }\n ],\n \"app_protect\": {\n \"enabled\": true,\n \"policy\": \"production-policy\",\n \"log\": {\n \"profile_name\": \"secops_dashboard\",\n \"enabled\": true,\n \"destination\": \"127.0.0.1:514\"\n }\n }\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"upstream_boutique\",\n \"origin\": [\n {\n \"server\": \"192.168.1.200:80\"\n }\n ]\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -1696,7 +1632,7 @@
}
},
"url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
"protocol": "http",
"host": [
"{{ncg_host}}"
@@ -1704,32 +1640,40 @@
"port": "{{ncg_port}}",
"path": [
"{{ngc_api_version}}",
- "config",
- "{{configUid}}"
+ "config"
]
}
},
"response": []
- },
+ }
+ ]
+ },
+ {
+ "name": "JWT Client Authentication",
+ "item": [
{
- "name": "Delete declaration",
+ "name": "JWT Client Authentication - local JWT key and Bearer token",
"event": [
{
"listen": "test",
"script": {
"exec": [
- ""
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
],
"type": "text/javascript"
}
}
],
"request": {
- "method": "DELETE",
+ "method": "POST",
"header": [],
"body": {
"mode": "raw",
- "raw": "",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test service\",\n \"resolver\": \"8.8.8.8\",\n \"names\": [\n \"test.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/test.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/test.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream\",\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"JWT Auth with hardwired key and Bearer token\"\n }\n ]\n },\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n }\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"JWT Auth with hardwired key and Bearer token\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"JWT Authentication\",\n \"key\": \"{\\\"keys\\\": [{\\\"k\\\":\\\"ZmFudGFzdGljand0\\\",\\\"kty\\\":\\\"oct\\\",\\\"kid\\\":\\\"0001\\\"}]}\"\n }\n },\n {\n \"name\": \"JWT Auth with external key and Bearer token\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"JWT Authentication GitOps\",\n \"key\": \"http://192.168.2.5:20080/jwks.json\",\n \"cachetime\": 5\n }\n },\n {\n \"name\": \"JWT Auth with hardwired key and token in auth_token query string parameter\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"JWT Authentication\",\n \"key\": \"{\\\"keys\\\": [{\\\"k\\\":\\\"ZmFudGFzdGljand0\\\",\\\"kty\\\":\\\"oct\\\",\\\"kid\\\":\\\"0001\\\"}]}\",\n \"token_location\": \"$arg_auth_token\"\n }\n },\n {\n \"name\": \"JWT Auth with hardwired key and token in X-Auth-Token HTTP header\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"JWT Authentication\",\n \"key\": \"{\\\"keys\\\": [{\\\"k\\\":\\\"ZmFudGFzdGljand0\\\",\\\"kty\\\":\\\"oct\\\",\\\"kid\\\":\\\"0001\\\"}]}\",\n \"token_location\": \"$http_x_auth_token\"\n }\n }\n ]\n }\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -1737,7 +1681,7 @@
}
},
"url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
"protocol": "http",
"host": [
"{{ncg_host}}"
@@ -1745,20 +1689,14 @@
"port": "{{ncg_port}}",
"path": [
"{{ngc_api_version}}",
- "config",
- "{{configUid}}"
+ "config"
]
}
},
"response": []
- }
- ]
- },
- {
- "name": "mTLS Client Authentication",
- "item": [
+ },
{
- "name": "HTTPS server with mTLS, OCSP, SSL Stapling",
+ "name": "JWT secret fetched from URL",
"event": [
{
"listen": "test",
@@ -1775,11 +1713,11 @@
}
],
"request": {
- "method": "POST",
+ "method": "PATCH",
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"server_cert\",\n \"contents\": {\n \"content\": \"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUdSRENDQkN5Z0F3SUJBZ0lVTTNJQVZIRmxhSTVsY1d0TjZxOUVhcnlka0w4d0RRWUpLb1pJaHZjTkFRRUwKQlFBd1NURUxNQWtHQTFVRUJoTUNTVlF4RFRBTEJnTlZCQWdNQkVGemRHa3hFVEFQQmdOVkJBb01DRlJsYzNRZwpUR0ZpTVJnd0ZnWURWUVFEREE5MmJTMWliR0Z1YXk1bVppNXNZVzR3SGhjTk1qTXdOakE0TVRBd01qTTVXaGNOCk1qUXdOakEzTVRBd01qTTVXakJKTVFzd0NRWURWUVFHRXdKSlZERU5NQXNHQTFVRUNBd0VRWE4wYVRFUk1BOEcKQTFVRUNnd0lWR1Z6ZENCTVlXSXhHREFXQmdOVkJBTU1EM1p0TFdKc1lXNXJMbVptTG14aGJqQ0NBaUl3RFFZSgpLb1pJaHZjTkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFMRFQ2bnZleVZlNi9VZlk2aUtHVC9oV1A0cktDSGR0ClloZWU3RGVZR29QWGhGVjB6a3grVWExanBEZ21WUE1kVEJBdnoxODg5NzlEcHBqdmNYeFhsRmpnaUhjWDhpWVgKSXovSUVMc3dKRUNITWNsNkxmelA5eDVUY1gxTEdFblFOTWhHRzA2MjlxU2NCQmQyUUNiWlY0UWE1TkxlQnQ4cQpHQ2lXY3JiQnR3YlpiSGo1dk9aenJrdHBtRFBGS1V4bXR5b2dBQnNaTllnL0F3Y1l2RXdBOEQ0QTN0VEgxcGhvCkdYY3ZvZWpJelhRMUdmYys5azR3OFhHYWFQOGd2bTdOMXN2MnU2Yld4SHRGZHpWQk9udzJyaHUvWGYyY0N0dW4KUnIxSENKQXRRSDlkbDhzZks1czBSRlVuTlVYbFBiNTFBTjBjVFVGbEYrZlVUVmVON3dNMTdmeVZVY3IydTltSwo0UGdoWjkvMml0ZUpZV3hjK3k4V2NEQzBUV3hwZ2paVEw5Tk1GK2t6SXV2TjJOWFFybjcvSU5UQTMvNFlmWGRPCloxelpTdTlkclRMcG5DZHRpOWxuRHBKODd3bW41cVZSTlZiTlZRbldEeW5yZnoyTU1DY21jLzcvdkJFN2dDemQKNFJLWHJLdHloenlQSitycmh3NmpxYVA4QytaZGRvKzkvak9QVDFTSnUxZ21VbzFuZ2hBMWh2N0M5RUYrM2xQVApYSk5WV3dtYkdWK0p4cUdKSjJSa2toMlIrZTVIREdRY2hGWjJIcXBGTGVQN0trTHJBR2RkZFZQWEZhQ0RiU0R6ClJQd0I5WFlhakg5Zm5QWEtFT3ZpVEJhQVNjWUZwTXB5cm02UkxHUGRSVnE2RUNYVlB4MDdHdGFCaEVvVWIwK2YKVkZnNExtQkx4MldQQWdNQkFBR2pnZ0VpTUlJQkhqQUpCZ05WSFJNRUFqQUFNQkVHQ1dDR1NBR0crRUlCQVFRRQpBd0lHUURBekJnbGdoa2dCaHZoQ0FRMEVKaFlrVDNCbGJsTlRUQ0JIWlc1bGNtRjBaV1FnVTJWeWRtVnlJRU5sCmNuUnBabWxqWVhSbE1CMEdBMVVkRGdRV0JCVHZFZWJGK1JDV0JhcGVPWUdpQ0YyVHZxbExYekNCaEFZRFZSMGoKQkgwd2U0QVVFdW9Db3kvcmhMQmxzcm5KdXE2QzFJczQxbFNoVGFSTE1Fa3hDekFKQmdOVkJBWVRBa2xVTVEwdwpDd1lEVlFRSURBUkJjM1JwTVJFd0R3WURWUVFLREFoVVpYTjBJRXhoWWpFWU1CWUdBMVVFQXd3UGRtMHRZbXhoCmJtc3VabVl1YkdGdWdoUld4QjhCa3lmK1RkQXc2Q3dPZE1aT0k0NlZ2REFPQmdOVkhROEJBZjhFQkFNQ0JhQXcKRXdZRFZSMGxCQXd3Q2dZSUt3WUJCUVVIQXdFd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dJQkFHUDR6ZkdseTI1RwpneTBSeC9SSTNpNzJDVlIrSXY3SW5WTUVGWDZqRHRNV3hSblFtRGZsMWtTOVF1Y3hNb0tnOE9URStMcnlzdGJsClF4WGZiakZQekNoNHB1UGtGTmNBeG1mVmR4b20xR1lodWpoYTBQOUswUURZSDZycGlUaFdSQ2greUovQm1qZ2wKTlJabks4WGRqME85Ui9XKzJrTFRac2VFbS9hZHFVQ3dkYzNBWWlNWGh4QXkvQlh3bFRQeDMyMHZCcXYxZGFyVgp5ZlVoRlM1Rkg3enV2bGtGQ1p6M3lpOGYvYXMwbkRTUkFrY3dPRFQvN1diQlN4QTk3ZzJmRk1EMEI3WlUvbndGCmU4VnRzNDl3YmZ6QWJRMk40RUc2OEVhODE1VlFRM2N6YWthdjBCdkxHL2UwT0habGxYcUVhV1ZlWFJtSWFFOHcKWko5OEhUaDJMbUlFV2Jpdm94Kyt2UXd3bVhKTm1DRFVXNnVmcHdBOVdKQ0VhYmhxeXdGVzh1dFVENzRTVXE3SApEUDhNamtJZ0o3ekl2Tkd1RkFsSzd6c2xpV2pzeUN1OGVNamhvN2pVRFhGR1R0R0ZMUGtVa08vSysrSGVVRFg0Cm1OWDJ2aHI3NGRqRkNBTTEvOTYxWnB5NUFYUzZkd2g3MFlJL2dMdldSL0J1ejBnNEp6YUI2UFo4M1ErYm9QVHYKM1ZIS2xOWjlKQlhRTmtSc3N6U0dYWG5MYmtOTmNwVFg2cnAyZ1pUSS9NNDhGTnBxanAxOXRpQVg3bWN0cTl2SgpNejhvemhEcHZmSTlnMjFsNFZlRGdpbWEwTDVBc1pQbFdIQlZjcy9yL3dMU2YzWFVYZEs0UHpCQUdIRFBidXYrCnpKOVNqS0NFVll2bHRhMHlUUVBCSFJPa2Y2MG1sVmh6Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"server_key\",\n \"contents\": {\n \"content\": \"LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlKS0FJQkFBS0NBZ0VBc05QcWU5N0pWN3I5UjlqcUlvWlArRlkvaXNvSWQyMWlGNTdzTjVnYWc5ZUVWWFRPClRINVJyV09rT0NaVTh4MU1FQy9QWHp6M3YwT21tTzl4ZkZlVVdPQ0lkeGZ5SmhjalA4Z1F1ekFrUUljeHlYb3QKL00vM0hsTnhmVXNZU2RBMHlFWWJUcmIycEp3RUYzWkFKdGxYaEJyazB0NEczeW9ZS0paeXRzRzNCdGxzZVBtOAo1bk91UzJtWU04VXBUR2EzS2lBQUd4azFpRDhEQnhpOFRBRHdQZ0RlMU1mV21HZ1pkeStoNk1qTmREVVo5ejcyClRqRHhjWnBvL3lDK2JzM1d5L2E3cHRiRWUwVjNOVUU2ZkRhdUc3OWQvWndLMjZkR3ZVY0lrQzFBZjEyWHl4OHIKbXpSRVZTYzFSZVU5dm5VQTNSeE5RV1VYNTlSTlY0M3ZBelh0L0pWUnl2YTcyWXJnK0NGbjMvYUsxNGxoYkZ6NwpMeFp3TUxSTmJHbUNObE12MDB3WDZUTWk2ODNZMWRDdWZ2OGcxTURmL2hoOWQwNW5YTmxLNzEydE11bWNKMjJMCjJXY09rbnp2Q2FmbXBWRTFWczFWQ2RZUEtldC9QWXd3Snlaei92KzhFVHVBTE4zaEVwZXNxM0tIUEk4bjZ1dUgKRHFPcG8vd0w1bDEyajczK000OVBWSW03V0NaU2pXZUNFRFdHL3NMMFFYN2VVOU5jazFWYkNac1pYNG5Hb1lrbgpaR1NTSFpINTdrY01aQnlFVm5ZZXFrVXQ0L3NxUXVzQVoxMTFVOWNWb0lOdElQTkUvQUgxZGhxTWYxK2M5Y29RCjYrSk1Gb0JKeGdXa3luS3VicEVzWTkxRldyb1FKZFUvSFRzYTFvR0VTaFJ2VDU5VVdEZ3VZRXZIWlk4Q0F3RUEKQVFLQ0FnQVBUR1pQRFRsU004VlIvL3hSdkZrUzNUTm1LSkNPOUpHMkJYUGVZM1IzejUrTlhTdTBCb0craEk1aQpwVDVZUWtLZ2ErSi9GT0ZDVlBJRzdVQmVSNTE0Q3dVRGVMamtmci8zOXJFcjRNQmlMTkFyNUR3eVVUUEtGZUlOCnV2K0E4MWg5czBNTmpsck1ad3NibElsOFV2VjFZblpGb0J2c0Z0SThRTGZ3QTlaMzZ6dXRRNzRLR2h3TVBqaUMKMGgzK2xDeG9vcGdmd0JDWGx3d0dBeWZYVTRWMWQ5SFBpdktRQVFHakJDWDM0OWVTcEQxNDNLT21wQ2xmY01LQQp3QzU1bTZsbndCTUFIamlsaVo4RXBuNE8zUlEzSmxsVlpiaXl4RWdrZkE3TG1uNm9Ca3Jwc2VxdDVObThuRVhKCnBFbXhQcUl5Znc1WUNBMEhhNkM5WUhRN1RPRW9BbHBmWld4azAxSnpoVi9aK3FmVHM1YlMwQWNaTzFOVDRaeDgKWlF2eHQ0TDJINVcrK2R6RjhReTlidzQ2M3lKb1dydWxtNy9uQ3YvL1FpNGl0eHRnYyt0N2lwVXZzaUdTVktVWQpPelhCSXNWTUlnd0F6eUtTSEhPL21rMkEwVkgxaHB3emY2L0RzR2wxSjM4TU9pVGo4dEx1RWt3cFY4WGh5MnZwCkd0cXpsT21DS1hodlVDam9iZWlYSWJwSlIzeEM1NmliRjVadk0vQUdONzI5K0xKRFNwbHJtWVJRVHh1UTJWSE8KQWFXQ01SQWFBdUtCVnBxYTRjd25WRy9POEpkN2ZPSi9tMFlIN3FpRlJHREdvdVNOdHZJUUVtaXVkK3dRWjJ6dwpUcmFNVWk0SENtNEFPa0ZNVXBsRmt1ajA2ZHRqM2RIWUtPQkdMK25vaUp4WmJxb3kwUUtDQVFFQTFiZUl6WHh6CnRFRlp2OGRlOXljOWdCUUtNNUNIbHp6NUNMZXVkTitvemxxeDNCMW1PRStxbFkyaEd3RklIWVBJajFLYS83RlkKbExmNFpiUEJRMFhiNUo5VzQzSGIyTnEydXdRQ3ZiSXhVMW9zaGJVWlhZc2FUaE15azc2VzQ5YjU3UC9HdFE3NwpTbkVZTXNrTzRUQndyS3lBdVhDVHRtTk1Qa2J1NFBxT05PeVFQY3o3Yi92VEU1eERjMENMVS9oUXM3NWFHeCs1Citld2VjeEZNa0JKTVo2c2N5TzcySEdSNHZwTHduRXUvcU5uN2JmUElSaUx1T3BwTTdHNlUwQlBPL2todHJ5ZmQKV3U3MHJYZGJSdGRJUHlsQWxSOG9zczJqWWsrRHNPUnNESm9pbkk5WU1Va3dmdHdCNTRQbytGRGtGOHBzV202RQpSaklpenFBK0piWDlTd0tDQVFFQTA4Ly9oM0NabDg2M2xUZHNrU1JKRUZKc0RtdkZkUStzMWtlNUFwMjdnWTBXCmZJbEFGZFlRR3RORUVlTk9xS3EwdTFtS0lqWHFacWNTdU9DNzZIYTE5Tk9waHVoK1dwV0t2Ni9BTWtQSjE5SUIKQ3RqS0lkc2s0U2M3WG02MnNOV1pnQm5XT1Z3QVdzU0VzTHRac1NvWUJUVTJJS1pBOVJOWHhkSEQreGZ2SWJkNApZYngzTzk4WklNQzNlVFFiOW9jVHZab0RNWGdLaHRtTy9iMnlSeEVDSGpGRmxzYlhhc1RPeG5XOWZSVXJtdGVqCk9pdVlXaEZOM2R6dmpuVEdLY0xieWY0MWpHaUVUeFViUHVpei9ZMmk5NldCNVN6MW9zaGorRU1OaFhtRzZSYXUKQUIvelhwNldtSUJ2bDNpU0lzOGJRNkh3Qm1DTjc1R2VVVG1GUUlyaVRRS0NBUUVBbTkzWVN5MXA0VndNRGI5bApObElMRzM4Q0ZhdGlDRjR5cmpYd2FWSzVkWTVWeTFneHRmMzhSa2hkNkNrZUpGQjVsSFhGajVnVEo1dW84TnVSCnB2T3JOT2swNEhxb3dWWjZFSmtUT3JCY0l4TlFCMUFXS05BTHBrZUFDcHJreDFTQlFHVW0wZVFVUjYyRjNYd2YKZXdMdUdqRlJURzJiZlZpY1FZdFFLd3J4YmczZUFRU2ZtSU9MNVBDQmpPdlU4YS9YZzgvZlBZcjlBeFkrK3VMeAorTjB2bGlnSXZVN3lkYkNkRXpodGZVQU5qeU16cVhRemExdU1iWGNkaFEzOVFHaEIvZGhyRG1TL250Tko1YjEzCjk0bUpLbTkycDR0ckRrVEYxU3h5dWk5TjBqOFQ0U1QyU0RPOXg3ZkROOHRQdk5LYUYvUE01SU5YdXk1VGptajIKQ21EWlV3S0NBUUFOUVJYSFh1ZHRsWFR0ZEhOcHZiQ0l3ZStiRTJsZXd1VlkzMUlYZE5GWDhRRTROOHAzMDFaYwpwMTI2Rk5SR1A3QmhqTi9VOWpTOXliU2xOd0xyTUFxQTBJSHFQRUF6NE9tMnh3T3E0WTBPNFVoSmFubHpsdWYrCjR0cVhOU3hmY201UmtzeFIrSXpaSVRVQWJpalZxa0dvaWNUaVZDVDZjUVJzRDQxSStCMXhxYTV4eHo1YTA4SVoKeDVWemt5d3d5QkVYS3owSjZtNFdOQ1Q3Z2RSWEdCeGUwVXgrZStEZEFJWEQ2M2c1RElzVy9HbHRhVzcySytFSQpnaHZIZVUweExjMWRIWGd5V2hQMWN1ZXFqeHM4UVpHeUYzeENZQWJhOGRrM250S0l5S3NGaVBMSWRUZGdjMklQCkZ2SmtzeG5KN2RYUjdKODlkdXRLMDN6cHJrVEZYaXQ5QW9JQkFDcjhkb2ZCcFlFL1JuTlFwbVNET29DRm1sdTkKQlozN3h5K0puZ2FrQ2RSdHFyR1lDdkZMSnI2QnpGdXE0SHpsM0piTkRCM1BkYSs4Z2VNd2cxU1htTEhrRVFrTQpXV2ptNHpmU3hiTUtKamx3REdoeUlwSU9nQ2FQL1hyT2hxTGl4bnJ6UHFHZmM4R0FZTDE2Rm1PeGVqbVk5aERtCmNibkFqZlNwUjF1WEt2S2d6d1NLQ0VWdzc0VjJSRmRqQXBLVDl3bkpOQTZiWHQ5SXFkaS96d3BYbDQ0OVczdVMKNjRjVVpaK3luYnQ5QUlxbFNjMDdNRHl1TUtueExMbDFLeEJYenNxZlVsYWtlRGVoVmdGS05OOTNXQWJJc09ieAp1d1hTd0hXa1B6RGFHeE9wdzlSMHo2S2t2N25YZnBIYW1RWENBZEdsRjkyc1QwYW80Y3FuejFJSmJ2bz0KLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0K\"\n }\n },\n {\n \"type\": \"certificate\",\n \"name\": \"cacert\",\n \"contents\": {\n \"content\": \"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZjekNDQTF1Z0F3SUJBZ0lVVnNRZkFaTW4vazNRTU9nc0RuVEdUaU9PbGJ3d0RRWUpLb1pJaHZjTkFRRUwKQlFBd1NURUxNQWtHQTFVRUJoTUNTVlF4RFRBTEJnTlZCQWdNQkVGemRHa3hFVEFQQmdOVkJBb01DRlJsYzNRZwpUR0ZpTVJnd0ZnWURWUVFEREE5MmJTMWliR0Z1YXk1bVppNXNZVzR3SGhjTk1qTXdOakE0TURrMU5EQTRXaGNOCk1qUXdOakEzTURrMU5EQTRXakJKTVFzd0NRWURWUVFHRXdKSlZERU5NQXNHQTFVRUNBd0VRWE4wYVRFUk1BOEcKQTFVRUNnd0lWR1Z6ZENCTVlXSXhHREFXQmdOVkJBTU1EM1p0TFdKc1lXNXJMbVptTG14aGJqQ0NBaUl3RFFZSgpLb1pJaHZjTkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFLMlQwWXpkcjB0dWQzaVJRNGNzaGNhRVJTRzVjTDE2CkhRblhoYWw4emlUL1VRQUNIUGdzZDYwcWlEaldvQTJXb0lGWFFpUHkzOG1vZGtWRlR4Qmt5U2VldndOOFJiLzEKOFhaMS8yS1RnVmRDcHkvNm11WE15bXZYODJad05CVkV3QnoxUk5kbklUSk44cVh3a0d4bHozbDBib1loRkFyUQpNdmkxcW1RaHpDa2Zpb041MVkrYlBXOXpTQlFQdXNrcXJYYzRqTTJ0VENNQ2pTcFlvd1hXM1ppRmc5WEJ1Z09aCjFmdWd1Zmw4K1FJYzNZSEFoL1Z1NloraXFEOGxQeGRKODlBeDZaazVtOGdkVG9JdUhBbUNWaHFpUXBGRjkzSTgKbkYrSnRuYnBaNTRJUTZBbWYrYiswakMxdmY4Kzg0WUppaEVzWExyaGMxZTRTZ2dwdzEvcWpDb21QblhGVjEzUwpsUG5kVlhVR0taa1ZKdXdZTjJyZElmd3YrdCs5MGhwUVBmNmFBTjRCamRxOXdkdkQzSXVnS2JYZG5CQ0FUTEY4ClYyRTFTSE9VZGdRY3duK1d1WDVVOGdPa3B2b2VFN0g1REJ6Rks1WTZ2SHZlaTRlNkp3RTRDK3FJL1BmbTgreTEKNEpsOFBSOW5JQmdGQ3hrZWpwa2tRQ0I5U0dvMVZidzZhWmdZd0VQNHh6YXFYYXV3L3F4c0oxNUkrRTBndEs1OApuWUtkM0hqelk5Slh6V0NVNTdXbmc2SzNvTTIzNXpyRzJnNm1FaHQ4SStDckVMUFNuZURjZU8zVlJkc2dlblBCCis4U1JxVU8vWG9LWHNEU3I5amoxdWluVzYwTG5MZ0Zmc3JQeGlQVlZlMFh1TFZESlhCSlNoRDZDeGRyMnBSOGQKS25SRDZrTFpZZEtMQWdNQkFBR2pVekJSTUIwR0ExVWREZ1FXQkJRUzZnS2pMK3VFc0dXeXVjbTZyb0xVaXpqVwpWREFmQmdOVkhTTUVHREFXZ0JRUzZnS2pMK3VFc0dXeXVjbTZyb0xVaXpqV1ZEQVBCZ05WSFJNQkFmOEVCVEFECkFRSC9NQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUNBUUJad3B4Z2Z4N2thZFhvRHNyT1hUVXJ6dEFPMkFQRVJNaTAKaTkyNk9DTGFPbVVYZW1uKytXSUU1K2tUSE0wcS8vbUZCTURzSmdZSFVLUlNvRGNsNmh4TnVFNUNzS2trRVFTSgpMTHZrWlB0S2J5NGlxMitLZ1JtdVZxbXJNVTBYQzZMZDl3WmttL2huUjNtT3V6bko4MGZmV1JDQ0xGWDEwY2EzCnc5TGM1d1JLTFBZZXQvcEs5SitOYWN3TFJRYTczVFovMUpQNW9BU3czVjNoYkxlLy9UeWpnOURqUlZGY3FYWnEKWWs2Mm5qSkhZVzh3WmlhZzc0QXU4dHE5OG5KandBV1ROMFV5L2w1Q2VpWnV5bzZlU0RHVDNJNm1BdGU1VXBvWAppNXBkYlZ6VDdOZC9IOEwwZHZNdVZ2N0FmakZlcU91cUZNNkkzTnlvbStLWENxNmJQdGxBWEkzeVFZc0t4ZlRkCkw3SnRaTmx6MGJ6eHJhcHI4RmpYcjhML1ZkeHQza00xMnJwb2kzL3hsckR6Q2Q2b2YrQ1MxelBocUdpOUhvcUoKZEU5VGhYMklTdkd2akVSYzVVNFRsNjJBNHNyeGJQbUt0eWx3dGNGVEJacUJiRGY3ZjBBc2cveWhndXdTcktsQQpBNkRWVXVCRFErdGpwZ0N0b0ZlOEhLVDJ6UFVlaEQ2ZjVNQkhmU2ZUZ1crTlhFSXNvVDNsampjY1hsYXhPcFJWCkNQNWxCczNmekxyYnBxbUlLaWZhdWlTNWM4TzlSUjhjQTVzeWlBOTBmbmJIdDlmdGxpRG9jcFRzNUtrbjk2NkIKZUxMM1dXVldCYUtvanJzY1RkVXJoalNnVVBmam5FTXpnVzR2eEc3d3BVNHR2ME4yaEtHUWc0bVhhcDV0SU5Pcwp4WktnZXRHUldnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=\"\n }\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"vm-blank.ff.lan\"\n ],\n \"resolver\": \"192.168.1.13\",\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"server_cert\",\n \"key\": \"server_key\",\n \"trusted_ca_certificates\": \"cacert\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ],\n \"mtls\": {\n \"enabled\": \"on\",\n \"client_certificates\": \"cacert\"\n },\n \"ocsp\": {\n \"enabled\": \"on\",\n \"responder\": \"http://ocsp.k8s.ie.ff.lan\"\n },\n \"stapling\": {\n \"enabled\": true,\n \"verify\": true,\n \"responder\": \"http://ocsp.k8s.ie.ff.lan\"\n }\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/vm-blank.ff.lan_access_log\",\n \"error\": \"/var/log/nginx/vm-blank.ff.lan_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://origin_server\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"origin_server\",\n \"origin\": [\n {\n \"server\": \"192.168.1.200:80\"\n }\n ]\n }\n ]\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test service\",\n \"resolver\": \"8.8.8.8\",\n \"names\": [\n \"test.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/test.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/test.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream\",\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"JWT Auth with external key and Bearer token\"\n }\n ]\n },\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n }\n }\n ]\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -1787,7 +1725,7 @@
}
},
"url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
"protocol": "http",
"host": [
"{{ncg_host}}"
@@ -1795,19 +1733,15 @@
"port": "{{ncg_port}}",
"path": [
"{{ngc_api_version}}",
- "config"
+ "config",
+ "{{configUid}}"
]
}
},
"response": []
- }
- ]
- },
- {
- "name": "NGINX App Protect WAF",
- "item": [
+ },
{
- "name": "Create initial NGINX configuration with NGINX App Protect WAF",
+ "name": "JWT token in auth_token query string parameter",
"event": [
{
"listen": "test",
@@ -1824,11 +1758,11 @@
}
],
"request": {
- "method": "POST",
+ "method": "PATCH",
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\",\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.1/www.online-boutique.local.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.1/www.online-boutique.local.key\"\n }\n }\n ],\n \"policies\": [\n {\n \"type\": \"app_protect\",\n \"name\": \"production-policy\",\n \"active_tag\": \"xss-blocked\",\n \"versions\": [\n {\n \"tag\": \"xss-blocked\",\n \"displayName\": \"Production Policy - XSS blocked\",\n \"description\": \"This is a production-ready policy - XSS blocked\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.1/nap-policy-xss-blocked.json\"\n }\n },\n {\n \"tag\": \"xss-allowed\",\n \"displayName\": \"Production Policy - XSS allowed\",\n \"description\": \"This is a production-ready policy - XSS allowed\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.1/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online_boutique_https_access_log\",\n \"error\": \"/var/log/nginx/online_boutique_https_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://upstream_boutique\"\n }\n ],\n \"app_protect\": {\n \"enabled\": true,\n \"policy\": \"production-policy\",\n \"log\": {\n \"profile_name\": \"secops_dashboard\",\n \"enabled\": true,\n \"destination\": \"127.0.0.1:514\"\n }\n }\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"upstream_boutique\",\n \"origin\": [\n {\n \"server\": \"192.168.1.200:80\"\n }\n ]\n }\n ]\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test service\",\n \"resolver\": \"8.8.8.8\",\n \"names\": [\n \"test.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/test.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/test.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream\",\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"JWT Auth with hardwired key and token in auth_token query string parameter\"\n }\n ]\n },\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n }\n }\n ]\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -1836,7 +1770,7 @@
}
},
"url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
"protocol": "http",
"host": [
"{{ncg_host}}"
@@ -1844,14 +1778,15 @@
"port": "{{ncg_port}}",
"path": [
"{{ngc_api_version}}",
- "config"
+ "config",
+ "{{configUid}}"
]
}
},
"response": []
},
{
- "name": "Change active NGINX App Protect policy",
+ "name": "JWT token in HTTP X-Auth-Token header",
"event": [
{
"listen": "test",
@@ -1872,7 +1807,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\",\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ],\n \"policies\": [\n {\n \"type\": \"app_protect\",\n \"name\": \"production-policy\",\n \"active_tag\": \"xss-allowed\",\n \"versions\": [\n {\n \"tag\": \"xss-blocked\",\n \"displayName\": \"Production Policy - XSS blocked\",\n \"description\": \"Production-ready policy - XSS blocked\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.1/nap-policy-xss-blocked.json\"\n }\n },\n {\n \"tag\": \"xss-allowed\",\n \"displayName\": \"Production Policy - XSS allowed\",\n \"description\": \"Production-ready policy - XSS allowed\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.1/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test service\",\n \"resolver\": \"8.8.8.8\",\n \"names\": [\n \"test.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/test.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/test.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream\",\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"JWT Auth with hardwired key and token in X-Auth-Token HTTP header\"\n }\n ]\n },\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n }\n }\n ]\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -1894,9 +1829,14 @@
}
},
"response": []
- },
+ }
+ ]
+ },
+ {
+ "name": "JWT Client Authentication and Authorization",
+ "item": [
{
- "name": "Update TLS certificates",
+ "name": "JWT Client Authentication and Authorization",
"event": [
{
"listen": "test",
@@ -1913,11 +1853,11 @@
}
],
"request": {
- "method": "PATCH",
+ "method": "POST",
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\",\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.1/www2.online-boutique.local.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.1/www2.online-boutique.local.key\"\n }\n }\n ]\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"JWT AuthN and AuthZ test server\",\n \"resolver\": \"8.8.8.8\",\n \"names\": [\n \"test.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/auth-test.nginx.lab_access_log\",\n \"error\": \"/var/log/nginx/auth-test.nginx.lab_error_log\"\n },\n \"headers\": {\n \"to_client\": {\n \"add\": [\n {\n \"name\": \"X-Injected-JWT-Group\",\n \"value\": \"$jwt_claim_roles\"\n }\n ]\n }\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream\",\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n },\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"jwt_authentication_local\"\n }\n ]\n },\n \"authorization\": {\n \"profile\": \"jwt role based authorization\"\n }\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"jwt_authentication_local\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"JWT Client Authentication\",\n \"key\": \"{\\\"keys\\\": [{\\\"k\\\":\\\"ZmFudGFzdGljand0\\\",\\\"kty\\\":\\\"oct\\\",\\\"kid\\\":\\\"0001\\\"}]}\",\n \"jwt_type\": \"signed\"\n }\n }\n ]\n },\n \"authorization\": [\n {\n \"name\": \"jwt role based authorization\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"claims\": [\n {\n \"name\": \"roles\",\n \"value\": [\n \"~(devops)\"\n ]\n }\n ]\n }\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -1925,7 +1865,7 @@
}
},
"url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
"protocol": "http",
"host": [
"{{ncg_host}}"
@@ -1933,15 +1873,19 @@
"port": "{{ncg_port}}",
"path": [
"{{ngc_api_version}}",
- "config",
- "{{configUid}}"
+ "config"
]
}
},
"response": []
- },
+ }
+ ]
+ },
+ {
+ "name": "mTLS Client Authentication",
+ "item": [
{
- "name": "Disable NGINX App Protect WAF",
+ "name": "HTTPS server with mTLS, OCSP, SSL Stapling",
"event": [
{
"listen": "test",
@@ -1953,16 +1897,17 @@
"",
"pm.collectionVariables.set('configUid',respData.configUid);"
],
- "type": "text/javascript"
+ "type": "text/javascript",
+ "packages": {}
}
}
],
"request": {
- "method": "PATCH",
+ "method": "POST",
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\",\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online_boutique_https_access_log\",\n \"error\": \"/var/log/nginx/online_boutique_https_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://upstream_boutique\"\n }\n ]\n }\n ]\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"server_cert\",\n \"contents\": {\n \"content\": \"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUdSRENDQkN5Z0F3SUJBZ0lVTTNJQVZIRmxhSTVsY1d0TjZxOUVhcnlka0w4d0RRWUpLb1pJaHZjTkFRRUwKQlFBd1NURUxNQWtHQTFVRUJoTUNTVlF4RFRBTEJnTlZCQWdNQkVGemRHa3hFVEFQQmdOVkJBb01DRlJsYzNRZwpUR0ZpTVJnd0ZnWURWUVFEREE5MmJTMWliR0Z1YXk1bVppNXNZVzR3SGhjTk1qTXdOakE0TVRBd01qTTVXaGNOCk1qUXdOakEzTVRBd01qTTVXakJKTVFzd0NRWURWUVFHRXdKSlZERU5NQXNHQTFVRUNBd0VRWE4wYVRFUk1BOEcKQTFVRUNnd0lWR1Z6ZENCTVlXSXhHREFXQmdOVkJBTU1EM1p0TFdKc1lXNXJMbVptTG14aGJqQ0NBaUl3RFFZSgpLb1pJaHZjTkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFMRFQ2bnZleVZlNi9VZlk2aUtHVC9oV1A0cktDSGR0ClloZWU3RGVZR29QWGhGVjB6a3grVWExanBEZ21WUE1kVEJBdnoxODg5NzlEcHBqdmNYeFhsRmpnaUhjWDhpWVgKSXovSUVMc3dKRUNITWNsNkxmelA5eDVUY1gxTEdFblFOTWhHRzA2MjlxU2NCQmQyUUNiWlY0UWE1TkxlQnQ4cQpHQ2lXY3JiQnR3YlpiSGo1dk9aenJrdHBtRFBGS1V4bXR5b2dBQnNaTllnL0F3Y1l2RXdBOEQ0QTN0VEgxcGhvCkdYY3ZvZWpJelhRMUdmYys5azR3OFhHYWFQOGd2bTdOMXN2MnU2Yld4SHRGZHpWQk9udzJyaHUvWGYyY0N0dW4KUnIxSENKQXRRSDlkbDhzZks1czBSRlVuTlVYbFBiNTFBTjBjVFVGbEYrZlVUVmVON3dNMTdmeVZVY3IydTltSwo0UGdoWjkvMml0ZUpZV3hjK3k4V2NEQzBUV3hwZ2paVEw5Tk1GK2t6SXV2TjJOWFFybjcvSU5UQTMvNFlmWGRPCloxelpTdTlkclRMcG5DZHRpOWxuRHBKODd3bW41cVZSTlZiTlZRbldEeW5yZnoyTU1DY21jLzcvdkJFN2dDemQKNFJLWHJLdHloenlQSitycmh3NmpxYVA4QytaZGRvKzkvak9QVDFTSnUxZ21VbzFuZ2hBMWh2N0M5RUYrM2xQVApYSk5WV3dtYkdWK0p4cUdKSjJSa2toMlIrZTVIREdRY2hGWjJIcXBGTGVQN0trTHJBR2RkZFZQWEZhQ0RiU0R6ClJQd0I5WFlhakg5Zm5QWEtFT3ZpVEJhQVNjWUZwTXB5cm02UkxHUGRSVnE2RUNYVlB4MDdHdGFCaEVvVWIwK2YKVkZnNExtQkx4MldQQWdNQkFBR2pnZ0VpTUlJQkhqQUpCZ05WSFJNRUFqQUFNQkVHQ1dDR1NBR0crRUlCQVFRRQpBd0lHUURBekJnbGdoa2dCaHZoQ0FRMEVKaFlrVDNCbGJsTlRUQ0JIWlc1bGNtRjBaV1FnVTJWeWRtVnlJRU5sCmNuUnBabWxqWVhSbE1CMEdBMVVkRGdRV0JCVHZFZWJGK1JDV0JhcGVPWUdpQ0YyVHZxbExYekNCaEFZRFZSMGoKQkgwd2U0QVVFdW9Db3kvcmhMQmxzcm5KdXE2QzFJczQxbFNoVGFSTE1Fa3hDekFKQmdOVkJBWVRBa2xVTVEwdwpDd1lEVlFRSURBUkJjM1JwTVJFd0R3WURWUVFLREFoVVpYTjBJRXhoWWpFWU1CWUdBMVVFQXd3UGRtMHRZbXhoCmJtc3VabVl1YkdGdWdoUld4QjhCa3lmK1RkQXc2Q3dPZE1aT0k0NlZ2REFPQmdOVkhROEJBZjhFQkFNQ0JhQXcKRXdZRFZSMGxCQXd3Q2dZSUt3WUJCUVVIQXdFd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dJQkFHUDR6ZkdseTI1RwpneTBSeC9SSTNpNzJDVlIrSXY3SW5WTUVGWDZqRHRNV3hSblFtRGZsMWtTOVF1Y3hNb0tnOE9URStMcnlzdGJsClF4WGZiakZQekNoNHB1UGtGTmNBeG1mVmR4b20xR1lodWpoYTBQOUswUURZSDZycGlUaFdSQ2greUovQm1qZ2wKTlJabks4WGRqME85Ui9XKzJrTFRac2VFbS9hZHFVQ3dkYzNBWWlNWGh4QXkvQlh3bFRQeDMyMHZCcXYxZGFyVgp5ZlVoRlM1Rkg3enV2bGtGQ1p6M3lpOGYvYXMwbkRTUkFrY3dPRFQvN1diQlN4QTk3ZzJmRk1EMEI3WlUvbndGCmU4VnRzNDl3YmZ6QWJRMk40RUc2OEVhODE1VlFRM2N6YWthdjBCdkxHL2UwT0habGxYcUVhV1ZlWFJtSWFFOHcKWko5OEhUaDJMbUlFV2Jpdm94Kyt2UXd3bVhKTm1DRFVXNnVmcHdBOVdKQ0VhYmhxeXdGVzh1dFVENzRTVXE3SApEUDhNamtJZ0o3ekl2Tkd1RkFsSzd6c2xpV2pzeUN1OGVNamhvN2pVRFhGR1R0R0ZMUGtVa08vSysrSGVVRFg0Cm1OWDJ2aHI3NGRqRkNBTTEvOTYxWnB5NUFYUzZkd2g3MFlJL2dMdldSL0J1ejBnNEp6YUI2UFo4M1ErYm9QVHYKM1ZIS2xOWjlKQlhRTmtSc3N6U0dYWG5MYmtOTmNwVFg2cnAyZ1pUSS9NNDhGTnBxanAxOXRpQVg3bWN0cTl2SgpNejhvemhEcHZmSTlnMjFsNFZlRGdpbWEwTDVBc1pQbFdIQlZjcy9yL3dMU2YzWFVYZEs0UHpCQUdIRFBidXYrCnpKOVNqS0NFVll2bHRhMHlUUVBCSFJPa2Y2MG1sVmh6Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"server_key\",\n \"contents\": {\n \"content\": \"LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlKS0FJQkFBS0NBZ0VBc05QcWU5N0pWN3I5UjlqcUlvWlArRlkvaXNvSWQyMWlGNTdzTjVnYWc5ZUVWWFRPClRINVJyV09rT0NaVTh4MU1FQy9QWHp6M3YwT21tTzl4ZkZlVVdPQ0lkeGZ5SmhjalA4Z1F1ekFrUUljeHlYb3QKL00vM0hsTnhmVXNZU2RBMHlFWWJUcmIycEp3RUYzWkFKdGxYaEJyazB0NEczeW9ZS0paeXRzRzNCdGxzZVBtOAo1bk91UzJtWU04VXBUR2EzS2lBQUd4azFpRDhEQnhpOFRBRHdQZ0RlMU1mV21HZ1pkeStoNk1qTmREVVo5ejcyClRqRHhjWnBvL3lDK2JzM1d5L2E3cHRiRWUwVjNOVUU2ZkRhdUc3OWQvWndLMjZkR3ZVY0lrQzFBZjEyWHl4OHIKbXpSRVZTYzFSZVU5dm5VQTNSeE5RV1VYNTlSTlY0M3ZBelh0L0pWUnl2YTcyWXJnK0NGbjMvYUsxNGxoYkZ6NwpMeFp3TUxSTmJHbUNObE12MDB3WDZUTWk2ODNZMWRDdWZ2OGcxTURmL2hoOWQwNW5YTmxLNzEydE11bWNKMjJMCjJXY09rbnp2Q2FmbXBWRTFWczFWQ2RZUEtldC9QWXd3Snlaei92KzhFVHVBTE4zaEVwZXNxM0tIUEk4bjZ1dUgKRHFPcG8vd0w1bDEyajczK000OVBWSW03V0NaU2pXZUNFRFdHL3NMMFFYN2VVOU5jazFWYkNac1pYNG5Hb1lrbgpaR1NTSFpINTdrY01aQnlFVm5ZZXFrVXQ0L3NxUXVzQVoxMTFVOWNWb0lOdElQTkUvQUgxZGhxTWYxK2M5Y29RCjYrSk1Gb0JKeGdXa3luS3VicEVzWTkxRldyb1FKZFUvSFRzYTFvR0VTaFJ2VDU5VVdEZ3VZRXZIWlk4Q0F3RUEKQVFLQ0FnQVBUR1pQRFRsU004VlIvL3hSdkZrUzNUTm1LSkNPOUpHMkJYUGVZM1IzejUrTlhTdTBCb0craEk1aQpwVDVZUWtLZ2ErSi9GT0ZDVlBJRzdVQmVSNTE0Q3dVRGVMamtmci8zOXJFcjRNQmlMTkFyNUR3eVVUUEtGZUlOCnV2K0E4MWg5czBNTmpsck1ad3NibElsOFV2VjFZblpGb0J2c0Z0SThRTGZ3QTlaMzZ6dXRRNzRLR2h3TVBqaUMKMGgzK2xDeG9vcGdmd0JDWGx3d0dBeWZYVTRWMWQ5SFBpdktRQVFHakJDWDM0OWVTcEQxNDNLT21wQ2xmY01LQQp3QzU1bTZsbndCTUFIamlsaVo4RXBuNE8zUlEzSmxsVlpiaXl4RWdrZkE3TG1uNm9Ca3Jwc2VxdDVObThuRVhKCnBFbXhQcUl5Znc1WUNBMEhhNkM5WUhRN1RPRW9BbHBmWld4azAxSnpoVi9aK3FmVHM1YlMwQWNaTzFOVDRaeDgKWlF2eHQ0TDJINVcrK2R6RjhReTlidzQ2M3lKb1dydWxtNy9uQ3YvL1FpNGl0eHRnYyt0N2lwVXZzaUdTVktVWQpPelhCSXNWTUlnd0F6eUtTSEhPL21rMkEwVkgxaHB3emY2L0RzR2wxSjM4TU9pVGo4dEx1RWt3cFY4WGh5MnZwCkd0cXpsT21DS1hodlVDam9iZWlYSWJwSlIzeEM1NmliRjVadk0vQUdONzI5K0xKRFNwbHJtWVJRVHh1UTJWSE8KQWFXQ01SQWFBdUtCVnBxYTRjd25WRy9POEpkN2ZPSi9tMFlIN3FpRlJHREdvdVNOdHZJUUVtaXVkK3dRWjJ6dwpUcmFNVWk0SENtNEFPa0ZNVXBsRmt1ajA2ZHRqM2RIWUtPQkdMK25vaUp4WmJxb3kwUUtDQVFFQTFiZUl6WHh6CnRFRlp2OGRlOXljOWdCUUtNNUNIbHp6NUNMZXVkTitvemxxeDNCMW1PRStxbFkyaEd3RklIWVBJajFLYS83RlkKbExmNFpiUEJRMFhiNUo5VzQzSGIyTnEydXdRQ3ZiSXhVMW9zaGJVWlhZc2FUaE15azc2VzQ5YjU3UC9HdFE3NwpTbkVZTXNrTzRUQndyS3lBdVhDVHRtTk1Qa2J1NFBxT05PeVFQY3o3Yi92VEU1eERjMENMVS9oUXM3NWFHeCs1Citld2VjeEZNa0JKTVo2c2N5TzcySEdSNHZwTHduRXUvcU5uN2JmUElSaUx1T3BwTTdHNlUwQlBPL2todHJ5ZmQKV3U3MHJYZGJSdGRJUHlsQWxSOG9zczJqWWsrRHNPUnNESm9pbkk5WU1Va3dmdHdCNTRQbytGRGtGOHBzV202RQpSaklpenFBK0piWDlTd0tDQVFFQTA4Ly9oM0NabDg2M2xUZHNrU1JKRUZKc0RtdkZkUStzMWtlNUFwMjdnWTBXCmZJbEFGZFlRR3RORUVlTk9xS3EwdTFtS0lqWHFacWNTdU9DNzZIYTE5Tk9waHVoK1dwV0t2Ni9BTWtQSjE5SUIKQ3RqS0lkc2s0U2M3WG02MnNOV1pnQm5XT1Z3QVdzU0VzTHRac1NvWUJUVTJJS1pBOVJOWHhkSEQreGZ2SWJkNApZYngzTzk4WklNQzNlVFFiOW9jVHZab0RNWGdLaHRtTy9iMnlSeEVDSGpGRmxzYlhhc1RPeG5XOWZSVXJtdGVqCk9pdVlXaEZOM2R6dmpuVEdLY0xieWY0MWpHaUVUeFViUHVpei9ZMmk5NldCNVN6MW9zaGorRU1OaFhtRzZSYXUKQUIvelhwNldtSUJ2bDNpU0lzOGJRNkh3Qm1DTjc1R2VVVG1GUUlyaVRRS0NBUUVBbTkzWVN5MXA0VndNRGI5bApObElMRzM4Q0ZhdGlDRjR5cmpYd2FWSzVkWTVWeTFneHRmMzhSa2hkNkNrZUpGQjVsSFhGajVnVEo1dW84TnVSCnB2T3JOT2swNEhxb3dWWjZFSmtUT3JCY0l4TlFCMUFXS05BTHBrZUFDcHJreDFTQlFHVW0wZVFVUjYyRjNYd2YKZXdMdUdqRlJURzJiZlZpY1FZdFFLd3J4YmczZUFRU2ZtSU9MNVBDQmpPdlU4YS9YZzgvZlBZcjlBeFkrK3VMeAorTjB2bGlnSXZVN3lkYkNkRXpodGZVQU5qeU16cVhRemExdU1iWGNkaFEzOVFHaEIvZGhyRG1TL250Tko1YjEzCjk0bUpLbTkycDR0ckRrVEYxU3h5dWk5TjBqOFQ0U1QyU0RPOXg3ZkROOHRQdk5LYUYvUE01SU5YdXk1VGptajIKQ21EWlV3S0NBUUFOUVJYSFh1ZHRsWFR0ZEhOcHZiQ0l3ZStiRTJsZXd1VlkzMUlYZE5GWDhRRTROOHAzMDFaYwpwMTI2Rk5SR1A3QmhqTi9VOWpTOXliU2xOd0xyTUFxQTBJSHFQRUF6NE9tMnh3T3E0WTBPNFVoSmFubHpsdWYrCjR0cVhOU3hmY201UmtzeFIrSXpaSVRVQWJpalZxa0dvaWNUaVZDVDZjUVJzRDQxSStCMXhxYTV4eHo1YTA4SVoKeDVWemt5d3d5QkVYS3owSjZtNFdOQ1Q3Z2RSWEdCeGUwVXgrZStEZEFJWEQ2M2c1RElzVy9HbHRhVzcySytFSQpnaHZIZVUweExjMWRIWGd5V2hQMWN1ZXFqeHM4UVpHeUYzeENZQWJhOGRrM250S0l5S3NGaVBMSWRUZGdjMklQCkZ2SmtzeG5KN2RYUjdKODlkdXRLMDN6cHJrVEZYaXQ5QW9JQkFDcjhkb2ZCcFlFL1JuTlFwbVNET29DRm1sdTkKQlozN3h5K0puZ2FrQ2RSdHFyR1lDdkZMSnI2QnpGdXE0SHpsM0piTkRCM1BkYSs4Z2VNd2cxU1htTEhrRVFrTQpXV2ptNHpmU3hiTUtKamx3REdoeUlwSU9nQ2FQL1hyT2hxTGl4bnJ6UHFHZmM4R0FZTDE2Rm1PeGVqbVk5aERtCmNibkFqZlNwUjF1WEt2S2d6d1NLQ0VWdzc0VjJSRmRqQXBLVDl3bkpOQTZiWHQ5SXFkaS96d3BYbDQ0OVczdVMKNjRjVVpaK3luYnQ5QUlxbFNjMDdNRHl1TUtueExMbDFLeEJYenNxZlVsYWtlRGVoVmdGS05OOTNXQWJJc09ieAp1d1hTd0hXa1B6RGFHeE9wdzlSMHo2S2t2N25YZnBIYW1RWENBZEdsRjkyc1QwYW80Y3FuejFJSmJ2bz0KLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0K\"\n }\n },\n {\n \"type\": \"certificate\",\n \"name\": \"cacert\",\n \"contents\": {\n \"content\": \"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZjekNDQTF1Z0F3SUJBZ0lVVnNRZkFaTW4vazNRTU9nc0RuVEdUaU9PbGJ3d0RRWUpLb1pJaHZjTkFRRUwKQlFBd1NURUxNQWtHQTFVRUJoTUNTVlF4RFRBTEJnTlZCQWdNQkVGemRHa3hFVEFQQmdOVkJBb01DRlJsYzNRZwpUR0ZpTVJnd0ZnWURWUVFEREE5MmJTMWliR0Z1YXk1bVppNXNZVzR3SGhjTk1qTXdOakE0TURrMU5EQTRXaGNOCk1qUXdOakEzTURrMU5EQTRXakJKTVFzd0NRWURWUVFHRXdKSlZERU5NQXNHQTFVRUNBd0VRWE4wYVRFUk1BOEcKQTFVRUNnd0lWR1Z6ZENCTVlXSXhHREFXQmdOVkJBTU1EM1p0TFdKc1lXNXJMbVptTG14aGJqQ0NBaUl3RFFZSgpLb1pJaHZjTkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFLMlQwWXpkcjB0dWQzaVJRNGNzaGNhRVJTRzVjTDE2CkhRblhoYWw4emlUL1VRQUNIUGdzZDYwcWlEaldvQTJXb0lGWFFpUHkzOG1vZGtWRlR4Qmt5U2VldndOOFJiLzEKOFhaMS8yS1RnVmRDcHkvNm11WE15bXZYODJad05CVkV3QnoxUk5kbklUSk44cVh3a0d4bHozbDBib1loRkFyUQpNdmkxcW1RaHpDa2Zpb041MVkrYlBXOXpTQlFQdXNrcXJYYzRqTTJ0VENNQ2pTcFlvd1hXM1ppRmc5WEJ1Z09aCjFmdWd1Zmw4K1FJYzNZSEFoL1Z1NloraXFEOGxQeGRKODlBeDZaazVtOGdkVG9JdUhBbUNWaHFpUXBGRjkzSTgKbkYrSnRuYnBaNTRJUTZBbWYrYiswakMxdmY4Kzg0WUppaEVzWExyaGMxZTRTZ2dwdzEvcWpDb21QblhGVjEzUwpsUG5kVlhVR0taa1ZKdXdZTjJyZElmd3YrdCs5MGhwUVBmNmFBTjRCamRxOXdkdkQzSXVnS2JYZG5CQ0FUTEY4ClYyRTFTSE9VZGdRY3duK1d1WDVVOGdPa3B2b2VFN0g1REJ6Rks1WTZ2SHZlaTRlNkp3RTRDK3FJL1BmbTgreTEKNEpsOFBSOW5JQmdGQ3hrZWpwa2tRQ0I5U0dvMVZidzZhWmdZd0VQNHh6YXFYYXV3L3F4c0oxNUkrRTBndEs1OApuWUtkM0hqelk5Slh6V0NVNTdXbmc2SzNvTTIzNXpyRzJnNm1FaHQ4SStDckVMUFNuZURjZU8zVlJkc2dlblBCCis4U1JxVU8vWG9LWHNEU3I5amoxdWluVzYwTG5MZ0Zmc3JQeGlQVlZlMFh1TFZESlhCSlNoRDZDeGRyMnBSOGQKS25SRDZrTFpZZEtMQWdNQkFBR2pVekJSTUIwR0ExVWREZ1FXQkJRUzZnS2pMK3VFc0dXeXVjbTZyb0xVaXpqVwpWREFmQmdOVkhTTUVHREFXZ0JRUzZnS2pMK3VFc0dXeXVjbTZyb0xVaXpqV1ZEQVBCZ05WSFJNQkFmOEVCVEFECkFRSC9NQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUNBUUJad3B4Z2Z4N2thZFhvRHNyT1hUVXJ6dEFPMkFQRVJNaTAKaTkyNk9DTGFPbVVYZW1uKytXSUU1K2tUSE0wcS8vbUZCTURzSmdZSFVLUlNvRGNsNmh4TnVFNUNzS2trRVFTSgpMTHZrWlB0S2J5NGlxMitLZ1JtdVZxbXJNVTBYQzZMZDl3WmttL2huUjNtT3V6bko4MGZmV1JDQ0xGWDEwY2EzCnc5TGM1d1JLTFBZZXQvcEs5SitOYWN3TFJRYTczVFovMUpQNW9BU3czVjNoYkxlLy9UeWpnOURqUlZGY3FYWnEKWWs2Mm5qSkhZVzh3WmlhZzc0QXU4dHE5OG5KandBV1ROMFV5L2w1Q2VpWnV5bzZlU0RHVDNJNm1BdGU1VXBvWAppNXBkYlZ6VDdOZC9IOEwwZHZNdVZ2N0FmakZlcU91cUZNNkkzTnlvbStLWENxNmJQdGxBWEkzeVFZc0t4ZlRkCkw3SnRaTmx6MGJ6eHJhcHI4RmpYcjhML1ZkeHQza00xMnJwb2kzL3hsckR6Q2Q2b2YrQ1MxelBocUdpOUhvcUoKZEU5VGhYMklTdkd2akVSYzVVNFRsNjJBNHNyeGJQbUt0eWx3dGNGVEJacUJiRGY3ZjBBc2cveWhndXdTcktsQQpBNkRWVXVCRFErdGpwZ0N0b0ZlOEhLVDJ6UFVlaEQ2ZjVNQkhmU2ZUZ1crTlhFSXNvVDNsampjY1hsYXhPcFJWCkNQNWxCczNmekxyYnBxbUlLaWZhdWlTNWM4TzlSUjhjQTVzeWlBOTBmbmJIdDlmdGxpRG9jcFRzNUtrbjk2NkIKZUxMM1dXVldCYUtvanJzY1RkVXJoalNnVVBmam5FTXpnVzR2eEc3d3BVNHR2ME4yaEtHUWc0bVhhcDV0SU5Pcwp4WktnZXRHUldnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=\"\n }\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"vm-blank.ff.lan\"\n ],\n \"resolver\": \"192.168.1.13\",\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"server_cert\",\n \"key\": \"server_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ],\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"mTLS-client-profile\"\n }\n ]\n }\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/vm-blank.ff.lan_access_log\",\n \"error\": \"/var/log/nginx/vm-blank.ff.lan_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://origin_server\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"origin_server\",\n \"origin\": [\n {\n \"server\": \"192.168.1.200:80\"\n }\n ]\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"mTLS-client-profile\",\n \"type\": \"mtls\",\n \"mtls\": {\n \"enabled\": \"on\",\n \"client_certificates\": \"cacert\",\n \"trusted_ca_certificates\": \"cacert\",\n \"ocsp\": {\n \"enabled\": \"on\",\n \"responder\": \"http://ocsp.k8s.ie.ff.lan\"\n },\n \"stapling\": {\n \"enabled\": true,\n \"verify\": true,\n \"responder\": \"http://ocsp.k8s.ie.ff.lan\"\n }\n }\n }\n ]\n }\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -1970,7 +1915,7 @@
}
},
"url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
"protocol": "http",
"host": [
"{{ncg_host}}"
@@ -1978,35 +1923,41 @@
"port": "{{ncg_port}}",
"path": [
"{{ngc_api_version}}",
- "config",
- "{{configUid}}"
+ "config"
]
}
},
"response": []
- },
+ }
+ ]
+ },
+ {
+ "name": "NGINX App Protect WAF",
+ "item": [
{
- "name": "Get declaration status",
+ "name": "Create initial NGINX configuration with NGINX App Protect WAF",
"event": [
{
"listen": "test",
"script": {
"exec": [
- ""
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
],
- "type": "text/javascript"
+ "type": "text/javascript",
+ "packages": {}
}
}
],
- "protocolProfileBehavior": {
- "disableBodyPruning": true
- },
"request": {
- "method": "GET",
+ "method": "POST",
"header": [],
"body": {
"mode": "raw",
- "raw": "",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert.key\"\n }\n }\n ],\n \"policies\": [\n {\n \"type\": \"app_protect\",\n \"name\": \"production-policy\",\n \"active_tag\": \"xss-blocked\",\n \"versions\": [\n {\n \"tag\": \"xss-blocked\",\n \"displayName\": \"Production Policy - XSS blocked\",\n \"description\": \"This is a production-ready policy - XSS blocked\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/nap-policy-xss-blocked.json\"\n }\n },\n {\n \"tag\": \"xss-allowed\",\n \"displayName\": \"Production Policy - XSS allowed\",\n \"description\": \"This is a production-ready policy - XSS allowed\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online_boutique_https_access_log\",\n \"error\": \"/var/log/nginx/online_boutique_https_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://upstream_boutique\"\n }\n ],\n \"app_protect\": {\n \"enabled\": true,\n \"policy\": \"production-policy\",\n \"log\": {\n \"profile_name\": \"secops_dashboard\",\n \"enabled\": true,\n \"destination\": \"127.0.0.1:514\"\n }\n }\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"upstream_boutique\",\n \"origin\": [\n {\n \"server\": \"192.168.1.200:80\"\n }\n ]\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -2014,7 +1965,7 @@
}
},
"url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}/status",
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
"protocol": "http",
"host": [
"{{ncg_host}}"
@@ -2022,36 +1973,36 @@
"port": "{{ncg_port}}",
"path": [
"{{ngc_api_version}}",
- "config",
- "{{configUid}}",
- "status"
+ "config"
]
}
},
"response": []
},
{
- "name": "Get declaration",
+ "name": "Change active NGINX App Protect policy",
"event": [
{
"listen": "test",
"script": {
"exec": [
- ""
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
],
- "type": "text/javascript"
+ "type": "text/javascript",
+ "packages": {}
}
}
],
- "protocolProfileBehavior": {
- "disableBodyPruning": true
- },
"request": {
- "method": "GET",
+ "method": "PATCH",
"header": [],
"body": {
"mode": "raw",
- "raw": "",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\"\n ],\n \"policies\": [\n {\n \"type\": \"app_protect\",\n \"name\": \"production-policy\",\n \"active_tag\": \"xss-allowed\",\n \"versions\": [\n {\n \"tag\": \"xss-blocked\",\n \"displayName\": \"Production Policy - XSS blocked\",\n \"description\": \"Production-ready policy - XSS blocked\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/nap-policy-xss-blocked.json\"\n }\n },\n {\n \"tag\": \"xss-allowed\",\n \"displayName\": \"Production Policy - XSS allowed\",\n \"description\": \"Production-ready policy - XSS allowed\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -2075,24 +2026,29 @@
"response": []
},
{
- "name": "Delete declaration",
+ "name": "Update TLS certificates",
"event": [
{
"listen": "test",
"script": {
"exec": [
- ""
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
],
- "type": "text/javascript"
+ "type": "text/javascript",
+ "packages": {}
}
}
],
"request": {
- "method": "DELETE",
+ "method": "PATCH",
"header": [],
"body": {
"mode": "raw",
- "raw": "",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert2.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert2.key\"\n }\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -2114,14 +2070,9 @@
}
},
"response": []
- }
- ]
- },
- {
- "name": "Server-side and source of truth authentication",
- "item": [
+ },
{
- "name": "Server-side and source of truth authentication",
+ "name": "Disable NGINX App Protect WAF",
"event": [
{
"listen": "test",
@@ -2133,16 +2084,17 @@
"",
"pm.collectionVariables.set('configUid',respData.configUid);"
],
- "type": "text/javascript"
+ "type": "text/javascript",
+ "packages": {}
}
}
],
"request": {
- "method": "POST",
+ "method": "PATCH",
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v2/www.online-boutique.local.crt\",\n \"authentication\": [\n {\n \"profile\": \"Basic authentication profile\"\n }\n ]\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v2/www.online-boutique.local.key\"\n }\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online_boutique_https_access_log\",\n \"error\": \"/var/log/nginx/online_boutique_https_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://upstream_boutique\",\n \"authentication\": {\n \"server\": [\n {\n \"profile\": \"Bearer token-based authentication profile\"\n }\n ]\n }\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"upstream_boutique\",\n \"origin\": [\n {\n \"server\": \"192.168.2.200:80\"\n }\n ]\n }\n ],\n \"authentication\": {\n \"server\": [\n {\n \"name\": \"Bearer token-based authentication profile\",\n \"type\": \"token\",\n \"token\": {\n \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDI0ODEzNjcsImV4cCI6MTcwMjQ4MTM2OH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIl19.SKA_7MszAypMEtX5NDQ0TcUbVYx_Wt0hrtmuyTmrVKU\",\n \"type\": \"bearer\"\n }\n },\n {\n \"name\": \"Header-based authentication profile\",\n \"type\": \"token\",\n \"token\": {\n \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDI0ODEzNjcsImV4cCI6MTcwMjQ4MTM2OH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIl19.SKA_7MszAypMEtX5NDQ0TcUbVYx_Wt0hrtmuyTmrVKU\",\n \"type\": \"header\",\n \"location\": \"X-AUTH-TOKEN\"\n }\n },\n {\n \"name\": \"Basic authentication profile\",\n \"type\": \"token\",\n \"token\": {\n \"type\": \"basic\",\n \"username\": \"authusername\",\n \"password\": \"YXV0aHBhc3N3b3Jk\"\n }\n }\n ]\n }\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online_boutique_https_access_log\",\n \"error\": \"/var/log/nginx/online_boutique_https_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://upstream_boutique\"\n }\n ]\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -2150,7 +2102,7 @@
}
},
"url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
"protocol": "http",
"host": [
"{{ncg_host}}"
@@ -2158,22 +2110,167 @@
"port": "{{ncg_port}}",
"path": [
"{{ngc_api_version}}",
- "config"
+ "config",
+ "{{configUid}}"
]
}
},
"response": []
}
]
- }
- ]
- }
- ]
- },
- {
- "name": "v4.2",
- "item": [
- {
+ },
+ {
+ "name": "NGINX Javascript",
+ "item": [
+ {
+ "name": "NGINX Javascript test",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript"
+ }
+ }
+ ],
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Example HTTP server with Javascript\",\n \"resolver\": \"8.8.8.8\",\n \"names\": [\n \"njs-test.vm-test.ie.ff.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/njs-test.nginx.lab_access_log\",\n \"error\": \"/var/log/nginx/njs-test.nginx.lab_error_log\"\n },\n \"njs\": [\n {\n \"hook\": {\n \"type\": \"js_set\",\n \"js_set\": {\n \"variable\": \"$serverVarSetByNjs\"\n }\n },\n \"profile\": \"njs_set_variable\",\n \"function\": \"njsSetVariable\"\n }\n ],\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"X-Injected-Client-IP\",\n \"value\": \"$remote_addr\"\n },\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n },\n \"locations\": [\n {\n \"uri\": \"/echo\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream\",\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"X-Injected-Client-IP\",\n \"value\": \"$remote_addr\"\n },\n {\n \"name\": \"X-HTTP-Var-Set-By-Njs\",\n \"value\": \"$httpVarSetByNjs\"\n },\n {\n \"name\": \"X-Server-Var-Set-By-Njs\",\n \"value\": \"$serverVarSetByNjs\"\n },\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n }\n },\n {\n \"uri\": \"/generatecontent\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream\",\n \"njs\": [\n {\n \"hook\": {\n \"type\": \"js_content\"\n },\n \"profile\": \"njs_set_content\",\n \"function\": \"njsSetContent\"\n }\n ],\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"X-Injected-Client-IP\",\n \"value\": \"$remote_addr\"\n },\n {\n \"name\": \"X-HTTP-Var-Set-By-Njs\",\n \"value\": \"$httpVarSetByNjs\"\n },\n {\n \"name\": \"X-Server-Var-Set-By-Njs\",\n \"value\": \"$serverVarSetByNjs\"\n },\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n }\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n ],\n \"njs\": [\n {\n \"hook\": {\n \"type\": \"js_set\",\n \"js_set\": {\n \"variable\": \"$httpVarSetByNjs\"\n }\n },\n \"profile\": \"njs_set_variable\",\n \"function\": \"njsSetVariable\"\n }\n ],\n \"njs_profiles\": [\n {\n \"name\": \"njs_set_variable\",\n \"file\": {\n \"content\": \"ZnVuY3Rpb24gbmpzU2V0VmFyaWFibGUocikgewogICAgcmV0dXJuICJWYXJpYWJsZV9zZXRfYnlfamF2YXNjcmlwdCAtIFVSSSAiK3IudXJpOwp9CgpleHBvcnQgZGVmYXVsdCB7bmpzU2V0VmFyaWFibGV9Cgo=\"\n }\n },\n {\n \"name\": \"njs_set_content\",\n \"file\": {\n \"content\": \"ZnVuY3Rpb24gbmpzU2V0Q29udGVudChyKSB7CiAgci5yZXR1cm4oMjAwLCAiSGVsbG8gd29ybGQhXG4iKTsKfQoKZXhwb3J0IGRlZmF1bHQge25qc1NldENvbnRlbnR9Cg==\"\n }\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config"
+ ]
+ }
+ },
+ "response": []
+ }
+ ]
+ },
+ {
+ "name": "Server-side and source of truth authentication",
+ "item": [
+ {
+ "name": "Bearer Token, Basic and HTTP header upstream authentication",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript"
+ }
+ }
+ ],
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v2/www.online-boutique.local.crt\",\n \"authentication\": [\n {\n \"profile\": \"Basic authentication profile\"\n }\n ]\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v2/www.online-boutique.local.key\"\n }\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online_boutique_https_access_log\",\n \"error\": \"/var/log/nginx/online_boutique_https_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://upstream_boutique\",\n \"authentication\": {\n \"server\": [\n {\n \"profile\": \"Bearer token-based authentication profile\"\n }\n ]\n }\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"upstream_boutique\",\n \"origin\": [\n {\n \"server\": \"192.168.2.200:80\"\n }\n ]\n }\n ],\n \"authentication\": {\n \"server\": [\n {\n \"name\": \"Bearer token-based authentication profile\",\n \"type\": \"token\",\n \"token\": {\n \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDI0ODEzNjcsImV4cCI6MTcwMjQ4MTM2OH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIl19.SKA_7MszAypMEtX5NDQ0TcUbVYx_Wt0hrtmuyTmrVKU\",\n \"type\": \"bearer\"\n }\n },\n {\n \"name\": \"Header-based authentication profile\",\n \"type\": \"token\",\n \"token\": {\n \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDI0ODEzNjcsImV4cCI6MTcwMjQ4MTM2OH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIl19.SKA_7MszAypMEtX5NDQ0TcUbVYx_Wt0hrtmuyTmrVKU\",\n \"type\": \"header\",\n \"location\": \"X-AUTH-TOKEN\"\n }\n },\n {\n \"name\": \"Basic authentication profile\",\n \"type\": \"token\",\n \"token\": {\n \"type\": \"basic\",\n \"username\": \"authusername\",\n \"password\": \"YXV0aHBhc3N3b3Jk\"\n }\n }\n ]\n }\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "mTLS upstream authentication",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
+ }
+ ],
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v2/www.online-boutique.local.crt\",\n \"authentication\": [\n {\n \"profile\": \"Basic authentication profile\"\n }\n ]\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v2/www.online-boutique.local.key\"\n }\n },\n {\n \"type\": \"certificate\",\n \"name\": \"client_cert\",\n \"contents\": {\n \"content\": \"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZBakNDQStxZ0F3SUJBZ0lVYXZ1aFhBOWFLVFJlYmZ2Y1BFU2Z0MjBUQXhzd0RRWUpLb1pJaHZjTkFRRUwKQlFBd1ZqRUxNQWtHQTFVRUJoTUNTVVV4RFRBTEJnTlZCQWdNQkVOdmNtc3hEVEFMQmdOVkJBY01CRU52Y21zeApFVEFQQmdOVkJBb01DRUZqYldVZ1RIUmtNUll3RkFZRFZRUUREQTEwWlhOMExtRmpiV1F1YkdGdU1CNFhEVEkwCk1EUXhOVEUzTURnMU0xb1hEVEkxTURReE5URTNNRGcxTTFvd1dERUxNQWtHQTFVRUJoTUNTVVV4RFRBTEJnTlYKQkFnTUJFTnZjbXN4RFRBTEJnTlZCQWNNQkVOdmNtc3hFVEFQQmdOVkJBb01DRUZqYldVZ1RIUmtNUmd3RmdZRApWUVFEREE5amJHbGxiblF1WVdOdFpTNXNZV0l3Z2dJaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQ0R3QXdnZ0lLCkFvSUNBUURUQ2kydi8rc08rdTJTcFF5ZVBLM3hnb3RyRUlDZGJYMmN4N0xkcnRDbE82a0xTM3IybWpxV1ptWkQKUWkvL0dIZXhYS3NaelBURDUyN0ZMZlREcExIb2h1MldmeUErQy9HN2JycXlNT0dQZ3lVcEI2NWN2THU4V1BNOApPa3lxVFdma0xkRnF2akFGclU5czMxUnljT3BQSlB0cFloRWlhQXZRWDlwRnhjalM2NUJscUFCMjY1YnlncGs2CmpsV1E5NTVWUzlmZlNLU3hpQTRCQXAzMHV3Rm5YRWtMcGRCenI1TkFKeXJqdXhzbHJGVEs4SGxvRmQ2MndzQUMKRjYrRGZmQ2FNLzVockljRkswSVFheHBpaWUyWllKaVFmNXJMeVd6VG1xMVh1QmsyaEhBWDNvQUY2bW9hcnVNOAo5UlhxQmlaNnFWdGFPQXFEK0pRVGNpYmVzekQ2Z2xoSitGM0VFTEJOWVhETmFLbGprQXRxVWFwYStXZEdVUkU4CnZvczA4TSsvOUlhWTdQeGtQNXB6bDhmaS9RaS9ESW9WLzh0UUlydFBIYzJqSTFSRkZoL3BpeDFsR2lyTlRBK0QKbTlURDJKT0hTU3VmdkRkRnV1YjFwMnF5TW5Nd3FFNklHOGpmTEg2TGNxRGFSbmcveVpVUTBqa01LSFYrd1gwegpkZ1RsMDVVWjZtMFpFNUdlK1FRaG5nY0FUemdrSWp3WlJod1JLOEx1Nmtwb2Vnb0dMUkhkTVNqcUV0NkNWc25BCmFLZ0hTbTJROE9MS1lJdlhVN1RpME9DNm5OdU40RDlKdkxGQXdPMUVFU2tCUXFQeThGby8zRVNZWU1FazJ6RzQKc3I0UXJ4Q2xuY2pwbUMrdkRmdHJuR055SVJvditOeS9zd2FSdkcvcm15ZnhEYVdNL3dJREFRQUJvNEhGTUlIQwpNQWtHQTFVZEV3UUNNQUF3RVFZSllJWklBWWI0UWdFQkJBUURBZ1dnTURNR0NXQ0dTQUdHK0VJQkRRUW1GaVJQCmNHVnVVMU5NSUVkbGJtVnlZWFJsWkNCRGJHbGxiblFnUTJWeWRHbG1hV05oZEdVd0hRWURWUjBPQkJZRUZGQmIKdmltZDYxekxLdlA0U2RZRFRWbndYdFVwTUI4R0ExVWRJd1FZTUJhQUZLY29GRHpMVnc1QXBiMzB5UTM0c25MZQpHQ1FWTUE0R0ExVWREd0VCL3dRRUF3SUY0REFkQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQWdZSUt3WUJCUVVICkF3UXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBSmg0cm9kZEVGemJwWk5kSW5zUmdubWVnWVIxSWlzUUxRU0IKcmNydEZxVmtLb3Rsc09EUXBFMThIRjBsbVA4WE9IU0hqYytYUVF5YlFNd1ViZ2RNbnhBZE1WaGFaMXppWElnaQpiUHgwOEY0YXR5MElJY1hyOVpFVnZTd1pheURBZHErb2s5RGpoRjQwYU5iQmFBTXB2NTRCL2U3OUNMSWZ6REo4CnNZaWw3K09abWlOUTJtZUNreVBYdXdhd3hTeVRnNVhWS3Q4VEtKQVJ5aTFJeWRHWkZRMTJGWFJHTE1BSjdaYngKRzlPd1ZvazExenpWNkRQZHFuZU5ER3BQRU5WZ2VmVjI0ZU1JVXUrYzhnSThYTU1GMU9VVWR3MmlEQmU4Q01TQQppc2h2aDFWYVZPNC96czlma2dLV2FXejNwQWprN3pkbWdaUnpXRUVHR0JMekJoQk5FQTg9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"client_key\",\n \"contents\": {\n \"content\": \"LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUpRd0lCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQ1Mwd2dna3BBZ0VBQW9JQ0FRRFRDaTJ2LytzTyt1MlMKcFF5ZVBLM3hnb3RyRUlDZGJYMmN4N0xkcnRDbE82a0xTM3IybWpxV1ptWkRRaS8vR0hleFhLc1p6UFRENTI3RgpMZlREcExIb2h1MldmeUErQy9HN2JycXlNT0dQZ3lVcEI2NWN2THU4V1BNOE9reXFUV2ZrTGRGcXZqQUZyVTlzCjMxUnljT3BQSlB0cFloRWlhQXZRWDlwRnhjalM2NUJscUFCMjY1YnlncGs2amxXUTk1NVZTOWZmU0tTeGlBNEIKQXAzMHV3Rm5YRWtMcGRCenI1TkFKeXJqdXhzbHJGVEs4SGxvRmQ2MndzQUNGNitEZmZDYU0vNWhySWNGSzBJUQpheHBpaWUyWllKaVFmNXJMeVd6VG1xMVh1QmsyaEhBWDNvQUY2bW9hcnVNODlSWHFCaVo2cVZ0YU9BcUQrSlFUCmNpYmVzekQ2Z2xoSitGM0VFTEJOWVhETmFLbGprQXRxVWFwYStXZEdVUkU4dm9zMDhNKy85SWFZN1B4a1A1cHoKbDhmaS9RaS9ESW9WLzh0UUlydFBIYzJqSTFSRkZoL3BpeDFsR2lyTlRBK0RtOVREMkpPSFNTdWZ2RGRGdXViMQpwMnF5TW5Nd3FFNklHOGpmTEg2TGNxRGFSbmcveVpVUTBqa01LSFYrd1gwemRnVGwwNVVaNm0wWkU1R2UrUVFoCm5nY0FUemdrSWp3WlJod1JLOEx1Nmtwb2Vnb0dMUkhkTVNqcUV0NkNWc25BYUtnSFNtMlE4T0xLWUl2WFU3VGkKME9DNm5OdU40RDlKdkxGQXdPMUVFU2tCUXFQeThGby8zRVNZWU1FazJ6RzRzcjRRcnhDbG5janBtQyt2RGZ0cgpuR055SVJvditOeS9zd2FSdkcvcm15ZnhEYVdNL3dJREFRQUJBb0lDQUJzWEZBK2krRmVFbW5rdE9xdHRUL1FsCk5TUlozL05WYjJuRlcyUGRqRHhKcGtUTzV2VS9qYThVd2ZmTVIrdWxCbWhSWkVmOFBweVBMc2J5USszV29iSjAKUk9JQlprVjdYd2ZDWDdEVUJDc0VtS3ZscDlvN3JVQmJqV0w1SmpJNDhYeDI3VFR0NlFMY05uVXhUZDUxanRPagpXYXFJdzNqNU1Oc0tFdDRncWlET2RhQzIvMzJaekZkTHNHNWdnRmRnUElZOUpYUXN3bHk2VnZjdzVpU0RoTnRICkcyYWxYYXdiL2s1Sk9OWTIyY3RDT0kyUnhPUGtPc3lYRkoxYTBRQStGYmxBWExKenVubE5ZNU9iOXEwWTFpa2sKSHpGeXBUcENSdmY2dzY3em00NUYvZVdkS0MzdmpnM29JK29GUS9vMTJUdjhWV3Bhc0ptSmoraUJ5aFRpOGx4YQpMempXaHNrUFZJUGJDYjFDTmIzZHNQSWVWYTVQYmRORGh2bHBQZFV4cXhKRGI4ZUFhemxSQXJVdmtaQnpkTjZtCjVwekljNGtMQnd3Wno5eGg1MzdsQ0tlZ3ZJYmdEMlQvMEM4SVFsWmFIK1M3azlWaVU2Z1RWSGNzU1RsSm52NVYKN3VCMWczVzJZRVloZFJxNlJOUXRZaUFuTktUS2ZYb3d1UUJteWRwVWRYWUljTE5GcER6eHgvRGdQSEhnU0J1dQpQZXVMZzdpemhSSndKMTQ1eW5VTlloQnROVVJaOWlRL1cwWTJOa242UWFBZDNld1pLaVg0S3lZU2k3TTF1MFJWCmFDc1BmZWJrWkRTUnRnQ2Q5N3dGSVYyTVh0UnpXNlpKUUlDWkhHTDVkYkJrNU0xQTI2NnJSYmcvTWZJSE9mdTMKRUZBVjc2aXoyVmNtSDRzblNZUHhBb0lCQVFEc0pNWElhM3ZyRXdRSkh0alRWZE9ONk9rbEExRVN4aWtjSWdSOAo3aFRWQXk3dmtORlpFVUhYczQ1TXlYQzRxTWlvUnFhZHVtOXpQWnFBQ0tQMHRWcXdDMVdOcUFrbDBQc1pZYXcrCmpKNjRDQXA4ZnJ4UDUrOVpWREtiamRWK1ZrK1lrbC9UL0Q1djNFTnZIdkVxN3ZMSE56dE9VSmFWZXNFRERQSW8KaER5SHhjRXQwTHRXTFhoNGNMSDhIQk9Kc0wxYXcxRlhNTk1qdERzazlBMTlJRFlYTHcwaWpIeC81c3hHUGcxSQpmMXRIemhpTlN5NUU5RG9pTmJxVFQvWEEyYVdCdjJ1ZlQybmw2ekticHZHNVo0VGlOUE5ESU5MaUFXOVNNQnJnCkJtaXJFVHU4MnVSa3hnaWZTM01CZ0ZFdXVtaSt2cEhwNzhGaUNOcHpZZUFwTUxjN0FvSUJBUURreVFVT29HVjEKTzZaNXJ4KzhLbVh1S3dmbXNHNmh5cmkrNEw4MzRQakVhbHdkdFhFUmphUG8vSTVhOVFoYjNnLzF5SUdiMzdLSgpPaTFCcGVRZ1owUEVQdFgyRWI0QTNCSTA5SzExWWFybnJGM2d6WS9CVWgveEZoL1YvVEVzTTloZTZ4YlhtRm9WCktvMlY1b2NlNnQzNUJuNHVLL2xkSEJKMHJnUENQdXNKVU9JMEhtUzZkdXNQcHczRFpESkZ5SEU4anptSllwcUsKMnBEMlBBMVZ5aVBBM3MwOU12TWdNSmJXajJLQVBoYk4xQXJnTERaUTFuZ0VwaVFtM3hWdmxIVkMzN0JHM0IzcApWbmtSRE9UZnF1N1BXek40aHZnMDRaNkxBdEZuYzNnMFFxRGcvcXZlS0xuclZwOUJEUlhWb0pZZkNMaVBkajZCCmFiYnFXQ0lYTnMwTkFvSUJBUURFWllrQk9UT2t2UG44UStWOVRzSldJa0hWZ0w2cTZKaEVSNTZIOE5MdW5ta28KNGI3Ylh0anQ5dTRBdXdDKzg5Ris4dE9jRnZTZVdidm5oRWdvTzdTaSthbzcyR2RUUmsyd1BHV3UxL0VoaWI1Kwo4RURhREVJcWZ6WmYzVVNVZ0dCT3VsNXN4anQvZVNlMGdYMStnYUQxUXVCV0wvd3RjaHlZMXVtSC9RTUN3TnY3CnFNQkYyaWQ1cy9Demh2NVE0K2Q0VnoyTlVKUXArN204OENWUHpieHU1N2o2NVBDZXgydFplRDQvNzN3UmFqMU4KTmh2VFNYUVlBNnVhM1VPOUVzYnQ5REFrSFQ0cjlNTHdaWlpnNXRIRCtObmhHS21MUWpvOWxyaWpYWEVyNVhkVAppSkd2cG15Qlg1VFV5TTI4R1ZrSVd5S3I5N1ZVUFp6Qm5jTjdQb01GQW9JQkFDSWRCekFESXAyMFkwSkpwb1c4CkhLN0NvODcyQjhrQUhVUDQ1d3BCOVZYME5nQUlDZkFBR3F5bTIrTWNIajcwZ1pTNGJQcjlBL1lLUXExRE94ekoKeVFUK0NaRkRXLzFzMHhvcVVhTHJDVHk2S3RWV1VWVVdGY1V3ODFaSkJvZjh3d3FFSzBmQ1k4dzhLQmh0NHovcwo3V1F3WDZncXptZmZ3N0M2TWIxSS9HckxNSzlzeU1BMDh4L0dYUHNCZWEyR0VieGg3c1paZVlteXhXS3gyWnN0CkpOK2hXU0VDODlXYzZTRGRDR2J1MngrZHVuRnFwajZ2ZS8zVmVCYUR0UUtLTkdIZ1VMeUFIY1dwS3l3cnJBVGQKeS9ZSE4wbUZkb1VNRDBQVEM3NU5MV005ZkJlUVliZ2lnblpnMkNZdStVNTlQMlVwTzd2SWVkRjZIZGdiaEJuSwpCaEVDZ2dFQkFNZmQ2Zi90RThTQlNFUnd5YW80SThuZkhTZUlMUklvM3pqRE5vWHZ6VHlwbG00a3ovYW9QeEF0CmhPYVNmZU41bFljMXFFUkRxZzRIVGRNTUkyenZPaVFuMHNGTEJFZ0UwT0VIOEZxZVZlZGgycUJucFdXWEhwTW8KREd4TnhpUnVpSDZpOEVMVWFoaU1NQkdQVi9ONjI5MDREbnUyYVVHcHlMTzZxems3SmM5VXlITC90QVNRTFIzagp6NFBhb2xTRE5rNzJSUks0VjIyZUprM2EwYVhjRU5vM1R0OUlTUTliMG5DYVVKbFJsZTA0d2QrOWUyN0FRNUNaCkVWbUtZT1JYcW9VTGNQOEcxRm1VUGhDRkU2aEI3L1hSVWpQdmJFdm5rS05Cdko2UHppT0RMdktRK3I4TzR0WkMKQi9LTDlCdjNmdUkvQlJLeU9WZVU1VnZ5MzUveUFxVT0KLS0tLS1FTkQgUFJJVkFURSBLRVktLS0tLQo=\"\n }\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online_boutique_https_access_log\",\n \"error\": \"/var/log/nginx/online_boutique_https_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://upstream_boutique\",\n \"authentication\": {\n \"server\": [\n {\n \"profile\": \"mTLS authentication profile\"\n }\n ]\n }\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"upstream_boutique\",\n \"origin\": [\n {\n \"server\": \"192.168.2.200:80\"\n }\n ]\n }\n ],\n \"authentication\": {\n \"server\": [\n {\n \"name\": \"mTLS authentication profile\",\n \"type\": \"mtls\",\n \"mtls\": {\n \"certificate\": \"client_cert\",\n \"key\": \"client_key\"\n }\n }\n ]\n }\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config"
+ ]
+ }
+ },
+ "response": []
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "description": "[https://github.com/f5devcentral/NGINX-Declarative-API/blob/main/USAGE-v4.2.md](https://github.com/f5devcentral/NGINX-Declarative-API/blob/main/USAGE-v4.2.md)"
+ },
+ {
+ "name": "v5.0",
+ "item": [
+ {
"name": "Configuration generation",
"item": [
{
@@ -2515,13 +2612,203 @@
"name": "Declarative automation examples",
"item": [
{
- "name": "API Gateway",
+ "name": "NGINX Instance Manager",
"item": [
{
- "name": "Ergast API",
+ "name": "API Gateway",
"item": [
{
- "name": "Ergast API Gateway and DevPortal",
+ "name": "Ergast API",
+ "item": [
+ {
+ "name": "Ergast API Gateway and DevPortal",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
+ }
+ ],
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Ergast API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"8.8.8.8\",\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/apigw.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/apigw.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/ergast\",\n \"urimatch\": \"prefix\",\n \"snippet\": {\n \"content\": \"IyBUZXN0IFNOSVBQRVQK\"\n },\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://raw.githubusercontent.com/adampax/ergast-f1-openapi-doc/e558eea18e176e4f78a8765ac7eccc804b5157ff/ergast-openapi-doc.yaml\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"uri\": \"/ergast-devportal.html\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/ergast-access_log\",\n \"error\": \"/var/log/nginx/ergast-error_log\"\n }\n }\n }\n ]\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config"
+ ]
+ }
+ },
+ "response": []
+ }
+ ]
+ },
+ {
+ "name": "Petstore API",
+ "item": [
+ {
+ "name": "Petstore API Gateway RateLimit",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
+ }
+ ],
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"8.8.8.8\",\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/apigw.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/apigw.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"name\": \"Petstore API Gateway\",\n \"openapi_schema\": {\n \"content\": \"http://petstore.swagger.io/v2/swagger.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore.swagger.io/v2\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"uri\": \"/petstore-devportal.html\"\n },\n \"rate_limit\": [\n {\n \"profile\": \"petstore_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 0,\n \"delay\": 0,\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\"\n ]\n }\n ]\n },\n \"log\": {\n \"access\": \"/var/log/nginx/petstore-access_log\",\n \"error\": \"/var/log/nginx/petstore-error_log\"\n }\n }\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"petstore_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"2r/s\"\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Petstore API Gateway RateLimit + JWT AuthN/AuthZ",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
+ }
+ ],
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"8.8.8.8\",\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/apigw.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/apigw.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"http://petstore.swagger.io/v2/swagger.json\",\n \"authentication\": [\n {\n \"profile\": \"Source of truth authentication profile using HTTP header token authentication\"\n }\n ]\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore.swagger.io/v2\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"uri\": \"/petstore-devportal.html\"\n },\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"Petstore JWT Authentication\"\n }\n ],\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\"\n ]\n },\n \"authorization\": [\n {\n \"profile\": \"JWT role based authorization\",\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\"\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"profile\": \"petstore_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 0,\n \"delay\": 0,\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\"\n ]\n }\n ]\n },\n \"log\": {\n \"access\": \"/var/log/nginx/petstore-access_log\",\n \"error\": \"/var/log/nginx/petstore-error_log\"\n }\n }\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"petstore_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"2r/s\"\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"Petstore JWT Authentication\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"Petstore Authentication\",\n \"key\": \"{\\\"keys\\\": [{\\\"k\\\":\\\"ZmFudGFzdGljand0\\\",\\\"kty\\\":\\\"oct\\\",\\\"kid\\\":\\\"0001\\\"}]}\",\n \"cachetime\": 5\n }\n }\n ],\n \"server\": [\n {\n \"name\": \"Source of truth authentication profile using bearer token authentication\",\n \"type\": \"token\",\n \"token\": {\n \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDI0ODEzNjcsImV4cCI6MTcwMjQ4MTM2OH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIl19.SKA_7MszAypMEtX5NDQ0TcUbVYx_Wt0hrtmuyTmrVKU\",\n \"type\": \"bearer\"\n }\n },\n {\n \"name\": \"Source of truth authentication profile using HTTP header token authentication\",\n \"type\": \"token\",\n \"token\": {\n \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDI0ODEzNjcsImV4cCI6MTcwMjQ4MTM2OH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIl19.SKA_7MszAypMEtX5NDQ0TcUbVYx_Wt0hrtmuyTmrVKU\",\n \"type\": \"header\",\n \"location\": \"X-AUTH-TOKEN\"\n }\n }\n ]\n },\n \"authorization\": [\n {\n \"name\": \"JWT role based authorization\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"claims\": [\n {\n \"name\": \"roles\",\n \"value\": [\n \"~(devops)\"\n ]\n }\n ]\n }\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Petstore API Gateway RateLimit + JWT AuthN/AuthZ + WAF",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
+ }
+ ],
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert.key\"\n }\n }\n ],\n \"policies\": [\n {\n \"type\": \"app_protect\",\n \"name\": \"production-policy\",\n \"active_tag\": \"xss-blocked\",\n \"versions\": [\n {\n \"tag\": \"xss-blocked\",\n \"displayName\": \"Production Policy - XSS blocked\",\n \"description\": \"This is a production-ready policy - XSS blocked\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/nap-policy-xss-blocked-bot-allowed.json\"\n }\n },\n {\n \"tag\": \"xss-allowed\",\n \"displayName\": \"Production Policy - XSS allowed\",\n \"description\": \"This is a production-ready policy - XSS allowed\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"8.8.8.8\",\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/apigw.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/apigw.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"http://petstore.swagger.io/v2/swagger.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore.swagger.io/v2\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"uri\": \"/petstore-devportal.html\"\n },\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"Petstore JWT Authentication\"\n }\n ],\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\",\n \"/pet/{petId}/uploadImage\"\n ]\n },\n \"authorization\": [\n {\n \"profile\": \"JWT role based authorization\",\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\",\n \"/pet/{petId}/uploadImage\"\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"profile\": \"petstore_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 0,\n \"delay\": 0,\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\",\n \"/pet/{petId}/uploadImage\"\n ]\n }\n ]\n },\n \"log\": {\n \"access\": \"/var/log/nginx/petstore-access_log\",\n \"error\": \"/var/log/nginx/petstore-error_log\"\n },\n \"app_protect\": {\n \"enabled\": true,\n \"policy\": \"production-policy\",\n \"log\": {\n \"profile_name\": \"secops_dashboard\",\n \"enabled\": true,\n \"destination\": \"127.0.0.1:514\"\n }\n }\n }\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"petstore_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"2r/s\"\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"Petstore JWT Authentication\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"Petstore Authentication\",\n \"key\": \"{\\\"keys\\\": [{\\\"k\\\":\\\"ZmFudGFzdGljand0\\\",\\\"kty\\\":\\\"oct\\\",\\\"kid\\\":\\\"0001\\\"}]}\",\n \"cachetime\": 5\n }\n }\n ]\n },\n \"authorization\": [\n {\n \"name\": \"JWT role based authorization\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"claims\": [\n {\n \"name\": \"roles\",\n \"value\": [\n \"~(devops)\"\n ],\n \"errorcode\": 403\n }\n ]\n }\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config"
+ ]
+ }
+ },
+ "response": []
+ }
+ ]
+ },
+ {
+ "name": "Petstore & Ergast API Gateway all in one",
"event": [
{
"listen": "test",
@@ -2543,7 +2830,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Ergast API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"8.8.8.8\",\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/apigw.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/apigw.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/ergast\",\n \"urimatch\": \"prefix\",\n \"snippet\": {\n \"content\": \"IyBUZXN0IFNOSVBQRVQK\"\n },\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://raw.githubusercontent.com/adampax/ergast-f1-openapi-doc/e558eea18e176e4f78a8765ac7eccc804b5157ff/ergast-openapi-doc.yaml\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"uri\": \"/ergast-devportal.html\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/ergast-access_log\",\n \"error\": \"/var/log/nginx/ergast-error_log\"\n }\n }\n }\n ]\n }\n ]\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore and Ergast API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"192.168.2.13\",\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/apigw.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/apigw.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"http://petstore.swagger.io/v2/swagger.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore.swagger.io/v2\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"uri\": \"/petstore-devportal.html\"\n },\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"Petstore JWT Authentication\"\n }\n ],\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\"\n ]\n },\n \"rate_limit\": [\n {\n \"profile\": \"petstore_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 0,\n \"delay\": 0,\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\"\n ]\n }\n ],\n \"log\": {\n \"access\": \"/var/log/nginx/petstore-access_log\",\n \"error\": \"/var/log/nginx/petstore-error_log\"\n }\n }\n },\n {\n \"uri\": \"/ergast\",\n \"urimatch\": \"prefix\",\n \"snippet\": {\n \"content\": \"IyBUZXN0IFNOSVBQRVQK\"\n },\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://raw.githubusercontent.com/adampax/ergast-f1-openapi-doc/e558eea18e176e4f78a8765ac7eccc804b5157ff/ergast-openapi-doc.yaml\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"uri\": \"/ergast-devportal.html\"\n },\n \"rate_limit\": [\n {\n \"profile\": \"ergast_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 0,\n \"delay\": 0\n }\n ],\n \"log\": {\n \"access\": \"/var/log/nginx/ergast-access_log\",\n \"error\": \"/var/log/nginx/ergast-error_log\"\n }\n }\n }\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"ergast_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"1r/s\"\n },\n {\n \"name\": \"petstore_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"2r/s\"\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"Petstore JWT Authentication\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"Petstore Authentication\",\n \"key\": \"{\\\"keys\\\": [{\\\"k\\\":\\\"ZmFudGFzdGljand0\\\",\\\"kty\\\":\\\"oct\\\",\\\"kid\\\":\\\"0001\\\"}]}\",\n \"cachetime\": 5\n }\n }\n ]\n }\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -2568,10 +2855,10 @@
]
},
{
- "name": "Petstore API",
+ "name": "CRUD automation",
"item": [
{
- "name": "Petstore API Gateway RateLimit",
+ "name": "Create initial NGINX configuration",
"event": [
{
"listen": "test",
@@ -2593,7 +2880,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"8.8.8.8\",\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/apigw.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/apigw.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"name\": \"Petstore API Gateway\",\n \"openapi_schema\": {\n \"content\": \"http://petstore.swagger.io/v2/swagger.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore.swagger.io/v2\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"uri\": \"/petstore-devportal.html\"\n },\n \"rate_limit\": [\n {\n \"profile\": \"petstore_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 0,\n \"delay\": 0,\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\"\n ]\n }\n ]\n },\n \"log\": {\n \"access\": \"/var/log/nginx/petstore-access_log\",\n \"error\": \"/var/log/nginx/petstore-error_log\"\n }\n }\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"petstore_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"2r/s\"\n }\n ]\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"HTTP test application\",\n \"names\": [\n \"patched_server.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"127.0.0.1:8080\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/access_log\",\n \"error\": \"/var/log/nginx/error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:80\"\n },\n {\n \"server\": \"10.0.0.2:80\"\n }\n ]\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -2616,7 +2903,7 @@
"response": []
},
{
- "name": "Petstore API Gateway RateLimit + JWT AuthN/AuthZ",
+ "name": "Update HTTP upstream",
"event": [
{
"listen": "test",
@@ -2634,11 +2921,11 @@
}
],
"request": {
- "method": "POST",
+ "method": "PATCH",
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"8.8.8.8\",\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/apigw.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/apigw.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"http://petstore.swagger.io/v2/swagger.json\",\n \"authentication\": [\n {\n \"profile\": \"Source of truth authentication profile using HTTP header token authentication\"\n }\n ]\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore.swagger.io/v2\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"uri\": \"/petstore-devportal.html\"\n },\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"Petstore JWT Authentication\"\n }\n ],\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\"\n ]\n },\n \"authorization\": [\n {\n \"profile\": \"JWT role based authorization\",\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\"\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"profile\": \"petstore_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 0,\n \"delay\": 0,\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\"\n ]\n }\n ]\n },\n \"log\": {\n \"access\": \"/var/log/nginx/petstore-access_log\",\n \"error\": \"/var/log/nginx/petstore-error_log\"\n }\n }\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"petstore_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"2r/s\"\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"Petstore JWT Authentication\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"Petstore Authentication\",\n \"key\": \"{\\\"keys\\\": [{\\\"k\\\":\\\"ZmFudGFzdGljand0\\\",\\\"kty\\\":\\\"oct\\\",\\\"kid\\\":\\\"0001\\\"}]}\",\n \"cachetime\": 5\n }\n }\n ],\n \"server\": [\n {\n \"name\": \"Source of truth authentication profile using bearer token authentication\",\n \"type\": \"token\",\n \"token\": {\n \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDI0ODEzNjcsImV4cCI6MTcwMjQ4MTM2OH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIl19.SKA_7MszAypMEtX5NDQ0TcUbVYx_Wt0hrtmuyTmrVKU\",\n \"type\": \"bearer\"\n }\n },\n {\n \"name\": \"Source of truth authentication profile using HTTP header token authentication\",\n \"type\": \"token\",\n \"token\": {\n \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDI0ODEzNjcsImV4cCI6MTcwMjQ4MTM2OH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIl19.SKA_7MszAypMEtX5NDQ0TcUbVYx_Wt0hrtmuyTmrVKU\",\n \"type\": \"header\",\n \"location\": \"X-AUTH-TOKEN\"\n }\n }\n ]\n },\n \"authorization\": [\n {\n \"name\": \"JWT role based authorization\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"claims\": [\n {\n \"name\": \"roles\",\n \"value\": [\n \"~(devops)\"\n ]\n }\n ]\n }\n }\n ]\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:80\"\n },\n {\n \"server\": \"10.0.0.2:80\"\n },\n {\n \"server\": \"10.0.0.3:80\"\n },\n {\n \"server\": \"10.0.0.4:80\"\n },\n {\n \"server\": \"10.0.0.5:80\"\n }\n ]\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -2646,7 +2933,7 @@
}
},
"url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
"protocol": "http",
"host": [
"{{ncg_host}}"
@@ -2654,14 +2941,15 @@
"port": "{{ncg_port}}",
"path": [
"{{ngc_api_version}}",
- "config"
+ "config",
+ "{{configUid}}"
]
}
},
"response": []
},
{
- "name": "Petstore API Gateway RateLimit + JWT AuthN/AuthZ + WAF",
+ "name": "Modify and add HTTP upstream",
"event": [
{
"listen": "test",
@@ -2679,11 +2967,11 @@
}
],
"request": {
- "method": "POST",
+ "method": "PATCH",
"header": [],
"body": {
"mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert.key\"\n }\n }\n ],\n \"policies\": [\n {\n \"type\": \"app_protect\",\n \"name\": \"production-policy\",\n \"active_tag\": \"xss-blocked\",\n \"versions\": [\n {\n \"tag\": \"xss-blocked\",\n \"displayName\": \"Production Policy - XSS blocked\",\n \"description\": \"This is a production-ready policy - XSS blocked\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/nap-policy-xss-blocked-bot-allowed.json\"\n }\n },\n {\n \"tag\": \"xss-allowed\",\n \"displayName\": \"Production Policy - XSS allowed\",\n \"description\": \"This is a production-ready policy - XSS allowed\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"8.8.8.8\",\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/apigw.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/apigw.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"http://petstore.swagger.io/v2/swagger.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore.swagger.io/v2\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"uri\": \"/petstore-devportal.html\"\n },\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"Petstore JWT Authentication\"\n }\n ],\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\",\n \"/pet/{petId}/uploadImage\"\n ]\n },\n \"authorization\": [\n {\n \"profile\": \"JWT role based authorization\",\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\",\n \"/pet/{petId}/uploadImage\"\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"profile\": \"petstore_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 0,\n \"delay\": 0,\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\",\n \"/pet/{petId}/uploadImage\"\n ]\n }\n ]\n },\n \"log\": {\n \"access\": \"/var/log/nginx/petstore-access_log\",\n \"error\": \"/var/log/nginx/petstore-error_log\"\n },\n \"app_protect\": {\n \"enabled\": true,\n \"policy\": \"production-policy\",\n \"log\": {\n \"profile_name\": \"secops_dashboard\",\n \"enabled\": true,\n \"destination\": \"127.0.0.1:514\"\n }\n }\n }\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"petstore_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"2r/s\"\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"Petstore JWT Authentication\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"Petstore Authentication\",\n \"key\": \"{\\\"keys\\\": [{\\\"k\\\":\\\"ZmFudGFzdGljand0\\\",\\\"kty\\\":\\\"oct\\\",\\\"kid\\\":\\\"0001\\\"}]}\",\n \"cachetime\": 5\n }\n }\n ]\n },\n \"authorization\": [\n {\n \"name\": \"JWT role based authorization\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"claims\": [\n {\n \"name\": \"roles\",\n \"value\": [\n \"~(devops)\"\n ],\n \"errorcode\": 403\n }\n ]\n }\n }\n ]\n }\n }\n}",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:80\"\n },\n {\n \"server\": \"10.0.0.2:80\"\n }\n ]\n },\n {\n \"name\": \"test_upstream_added\",\n \"origin\": [\n {\n \"server\": \"192.168.1.1:80\"\n },\n {\n \"server\": \"192.168.1.2:80\"\n }\n ]\n }\n ]\n }\n }\n}",
"options": {
"raw": {
"language": "json"
@@ -2691,7 +2979,7 @@
}
},
"url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
"protocol": "http",
"host": [
"{{ncg_host}}"
@@ -2699,1734 +2987,1550 @@
"port": "{{ncg_port}}",
"path": [
"{{ngc_api_version}}",
- "config"
+ "config",
+ "{{configUid}}"
]
}
},
"response": []
- }
- ]
- },
- {
- "name": "Petstore & Ergast API Gateway all in one",
- "event": [
+ },
{
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript",
- "packages": {}
- }
- }
- ],
- "request": {
- "method": "POST",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore and Ergast API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"192.168.2.13\",\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/apigw.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/apigw.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"http://petstore.swagger.io/v2/swagger.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore.swagger.io/v2\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"uri\": \"/petstore-devportal.html\"\n },\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"Petstore JWT Authentication\"\n }\n ],\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\"\n ]\n },\n \"rate_limit\": [\n {\n \"profile\": \"petstore_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 0,\n \"delay\": 0,\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/user/login\",\n \"/user/logout\"\n ]\n }\n ],\n \"log\": {\n \"access\": \"/var/log/nginx/petstore-access_log\",\n \"error\": \"/var/log/nginx/petstore-error_log\"\n }\n }\n },\n {\n \"uri\": \"/ergast\",\n \"urimatch\": \"prefix\",\n \"snippet\": {\n \"content\": \"IyBUZXN0IFNOSVBQRVQK\"\n },\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://raw.githubusercontent.com/adampax/ergast-f1-openapi-doc/e558eea18e176e4f78a8765ac7eccc804b5157ff/ergast-openapi-doc.yaml\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"uri\": \"/ergast-devportal.html\"\n },\n \"rate_limit\": [\n {\n \"profile\": \"ergast_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 0,\n \"delay\": 0\n }\n ],\n \"log\": {\n \"access\": \"/var/log/nginx/ergast-access_log\",\n \"error\": \"/var/log/nginx/ergast-error_log\"\n }\n }\n }\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"ergast_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"1r/s\"\n },\n {\n \"name\": \"petstore_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"2r/s\"\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"Petstore JWT Authentication\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"Petstore Authentication\",\n \"key\": \"{\\\"keys\\\": [{\\\"k\\\":\\\"ZmFudGFzdGljand0\\\",\\\"kty\\\":\\\"oct\\\",\\\"kid\\\":\\\"0001\\\"}]}\",\n \"cachetime\": 5\n }\n }\n ]\n }\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
+ "name": "Modify and add HTTP server and upstream",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
}
- }
- },
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config"
- ]
- }
- },
- "response": []
- }
- ]
- },
- {
- "name": "CRUD automation",
- "item": [
- {
- "name": "Create initial NGINX configuration",
- "event": [
- {
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript",
- "packages": {}
- }
- }
- ],
- "request": {
- "method": "POST",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"HTTP test application\",\n \"names\": [\n \"patched_server.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"127.0.0.1:8080\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/access_log\",\n \"error\": \"/var/log/nginx/error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:80\"\n },\n {\n \"server\": \"10.0.0.2:80\"\n }\n ]\n }\n ]\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
- }
- }
- },
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
- ],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config"
- ]
- }
- },
- "response": []
- },
- {
- "name": "Update HTTP upstream",
- "event": [
- {
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript",
- "packages": {}
- }
- }
- ],
- "request": {
- "method": "PATCH",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:80\"\n },\n {\n \"server\": \"10.0.0.2:80\"\n },\n {\n \"server\": \"10.0.0.3:80\"\n },\n {\n \"server\": \"10.0.0.4:80\"\n },\n {\n \"server\": \"10.0.0.5:80\"\n }\n ]\n }\n ]\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
- }
- }
- },
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
- ],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config",
- "{{configUid}}"
- ]
- }
- },
- "response": []
- },
- {
- "name": "Modify and add HTTP upstream",
- "event": [
- {
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript",
- "packages": {}
- }
- }
- ],
- "request": {
- "method": "PATCH",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:80\"\n },\n {\n \"server\": \"10.0.0.2:80\"\n }\n ]\n },\n {\n \"name\": \"test_upstream_added\",\n \"origin\": [\n {\n \"server\": \"192.168.1.1:80\"\n },\n {\n \"server\": \"192.168.1.2:80\"\n }\n ]\n }\n ]\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
- }
- }
- },
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
- ],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config",
- "{{configUid}}"
- ]
- }
- },
- "response": []
- },
- {
- "name": "Modify and add HTTP server and upstream",
- "event": [
- {
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript",
- "packages": {}
- }
- }
- ],
- "request": {
- "method": "PATCH",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"HTTP test application\",\n \"names\": [\n \"patched_server_v2.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"127.0.0.1:8080\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/access_v2_log\",\n \"error\": \"/var/log/nginx/error_v2_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream_added\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream_added\",\n \"origin\": [\n {\n \"server\": \"192.168.1.100:80\",\n \"weight\": 5,\n \"max_fails\": 2,\n \"fail_timeout\": \"30s\",\n \"max_conns\": 3,\n \"slow_start\": \"30s\"\n },\n {\n \"server\": \"192.168.1.101:80\"\n },\n {\n \"server\": \"192.168.1.102:80\"\n },\n {\n \"server\": \"192.168.1.103:80\"\n }\n ]\n }\n ]\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
- }
- }
- },
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
- ],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config",
- "{{configUid}}"
- ]
- }
- },
- "response": []
- },
- {
- "name": "Remove HTTP server and upstream",
- "event": [
- {
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript",
- "packages": {}
- }
- }
- ],
- "request": {
- "method": "PATCH",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"HTTP test application\"\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream_added\"\n }\n ]\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
- }
- }
- },
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
- ],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config",
- "{{configUid}}"
- ]
- }
- },
- "response": []
- },
- {
- "name": "Modify Stream server and upstream",
- "event": [
- {
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript",
- "packages": {}
- }
- }
- ],
- "request": {
- "method": "PATCH",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"layer4\": {\n \"servers\": [\n {\n \"name\": \"TCP_10053_service\",\n \"listen\": {\n \"address\": \"10053\",\n \"protocol\": \"tcp\"\n },\n \"upstream\": \"TCP_10053_upstream\"\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"TCP_10053_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:53\"\n },\n {\n \"server\": \"10.0.0.2:53\"\n },\n {\n \"server\": \"10.0.0.3:53\"\n },\n {\n \"server\": \"10.0.0.4:53\"\n }\n ]\n }\n ]\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
- }
- }
- },
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
- ],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config",
- "{{configUid}}"
- ]
- }
- },
- "response": []
- },
- {
- "name": "Add stream server and upstream",
- "event": [
- {
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript",
- "packages": {}
- }
- }
- ],
- "request": {
- "method": "PATCH",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"layer4\": {\n \"servers\": [\n {\n \"name\": \"TCP_15432_service\",\n \"listen\": {\n \"address\": \"15432\",\n \"protocol\": \"tcp\"\n },\n \"upstream\": \"TCP_15432_upstream\"\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"TCP_15432_upstream\",\n \"origin\": [\n {\n \"server\": \"172.16.10.1:5432\"\n },\n {\n \"server\": \"172.16.10.1:5432\"\n }\n ]\n }\n ]\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
- }
- }
- },
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
- ],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config",
- "{{configUid}}"
- ]
- }
- },
- "response": []
- },
- {
- "name": "Remove stream server and upstream #1",
- "event": [
- {
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript",
- "packages": {}
- }
- }
- ],
- "request": {
- "method": "PATCH",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"layer4\": {\n \"servers\": [\n {\n \"name\": \"TCP_10053_service\"\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"TCP_10053_upstream\"\n }\n ]\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
- }
- }
- },
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
- ],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config",
- "{{configUid}}"
- ]
- }
- },
- "response": []
- },
- {
- "name": "Remove stream server and upstream #2",
- "event": [
- {
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript",
- "packages": {}
- }
- }
- ],
- "request": {
- "method": "PATCH",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"layer4\": {\n \"servers\": [\n {\n \"name\": \"TCP_15432_service\"\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"TCP_15432_upstream\"\n }\n ]\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
- }
- }
- },
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
- ],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config",
- "{{configUid}}"
- ]
- }
- },
- "response": []
- }
- ]
- },
- {
- "name": "GitOps autosync",
- "item": [
- {
- "name": "NGINX Plus and GitOps",
- "event": [
- {
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript"
- }
- }
- ],
- "request": {
- "method": "POST",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 5,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.1/www.online-boutique.local.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.1/www.online-boutique.local.key\"\n }\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online_boutique_https_access_log\",\n \"error\": \"/var/log/nginx/online_boutique_https_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://upstream_boutique\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"upstream_boutique\",\n \"origin\": [\n {\n \"server\": \"192.168.2.200:80\"\n }\n ]\n }\n ]\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
- }
- }
- },
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
- ],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config"
- ]
- }
- },
- "response": []
- },
- {
- "name": "NGINX App Protect WAF and GitOps",
- "event": [
- {
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript"
- }
- }
- ],
- "request": {
- "method": "POST",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 5,\n \"modules\": [\n \"ngx_http_app_protect_module\",\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v2/www.online-boutique.local.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v2/www.online-boutique.local.key\"\n }\n }\n ],\n \"policies\": [\n {\n \"type\": \"app_protect\",\n \"name\": \"production-policy\",\n \"active_tag\": \"gitops\",\n \"versions\": [\n {\n \"tag\": \"gitops\",\n \"displayName\": \"Production Policy - GitOps\",\n \"description\": \"This is a production-ready policy - Managed by GitOps\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v2/nap-policy-gitops.json\"\n }\n }\n ]\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online_boutique_https_access_log\",\n \"error\": \"/var/log/nginx/online_boutique_https_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://upstream_boutique\"\n }\n ],\n \"app_protect\": {\n \"enabled\": true,\n \"policy\": \"production-policy\",\n \"log\": {\n \"profile_name\": \"secops_dashboard\",\n \"enabled\": true,\n \"destination\": \"127.0.0.1:514\"\n }\n }\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"upstream_boutique\",\n \"origin\": [\n {\n \"server\": \"192.168.1.200:80\"\n }\n ]\n }\n ]\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
+ "request": {
+ "method": "PATCH",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"HTTP test application\",\n \"names\": [\n \"patched_server_v2.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"127.0.0.1:8080\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/access_v2_log\",\n \"error\": \"/var/log/nginx/error_v2_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream_added\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream_added\",\n \"origin\": [\n {\n \"server\": \"192.168.1.100:80\",\n \"weight\": 5,\n \"max_fails\": 2,\n \"fail_timeout\": \"30s\",\n \"max_conns\": 3,\n \"slow_start\": \"30s\"\n },\n {\n \"server\": \"192.168.1.101:80\"\n },\n {\n \"server\": \"192.168.1.102:80\"\n },\n {\n \"server\": \"192.168.1.103:80\"\n }\n ]\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config",
+ "{{configUid}}"
+ ]
}
- }
+ },
+ "response": []
},
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
- ],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config"
- ]
- }
- },
- "response": []
- },
- {
- "name": "Get declaration status",
- "event": [
{
- "listen": "test",
- "script": {
- "exec": [
- ""
- ],
- "type": "text/javascript"
- }
- }
- ],
- "protocolProfileBehavior": {
- "disableBodyPruning": true
- },
- "request": {
- "method": "GET",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "",
- "options": {
- "raw": {
- "language": "json"
+ "name": "Remove HTTP server and upstream",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
}
- }
- },
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}/status",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config",
- "{{configUid}}",
- "status"
- ]
- }
- },
- "response": []
- },
- {
- "name": "Get declaration",
- "event": [
- {
- "listen": "test",
- "script": {
- "exec": [
- ""
- ],
- "type": "text/javascript"
- }
- }
- ],
- "protocolProfileBehavior": {
- "disableBodyPruning": true
- },
- "request": {
- "method": "GET",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "",
- "options": {
- "raw": {
- "language": "json"
+ "request": {
+ "method": "PATCH",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"HTTP test application\"\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream_added\"\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config",
+ "{{configUid}}"
+ ]
}
- }
+ },
+ "response": []
},
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
- ],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config",
- "{{configUid}}"
- ]
- }
- },
- "response": []
- },
- {
- "name": "Delete declaration",
- "event": [
{
- "listen": "test",
- "script": {
- "exec": [
- ""
- ],
- "type": "text/javascript"
- }
- }
- ],
- "request": {
- "method": "DELETE",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "",
- "options": {
- "raw": {
- "language": "json"
+ "name": "Modify Stream server and upstream",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
}
- }
- },
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config",
- "{{configUid}}"
- ]
- }
- },
- "response": []
- }
- ]
- },
- {
- "name": "Housekeeping - common endpoints",
- "item": [
- {
- "name": "Clean NGINX configuration",
- "event": [
- {
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript",
- "packages": {}
- }
- }
- ],
- "request": {
- "method": "POST",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\"\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
+ "request": {
+ "method": "PATCH",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"layer4\": {\n \"servers\": [\n {\n \"name\": \"TCP_10053_service\",\n \"listen\": {\n \"address\": \"10053\",\n \"protocol\": \"tcp\"\n },\n \"upstream\": \"TCP_10053_upstream\"\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"TCP_10053_upstream\",\n \"origin\": [\n {\n \"server\": \"10.0.0.1:53\"\n },\n {\n \"server\": \"10.0.0.2:53\"\n },\n {\n \"server\": \"10.0.0.3:53\"\n },\n {\n \"server\": \"10.0.0.4:53\"\n }\n ]\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config",
+ "{{configUid}}"
+ ]
}
- }
+ },
+ "response": []
},
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
- ],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config"
- ]
- }
- },
- "response": []
- },
- {
- "name": "Get declaration status",
- "event": [
{
- "listen": "test",
- "script": {
- "exec": [
- ""
- ],
- "type": "text/javascript"
- }
- }
- ],
- "protocolProfileBehavior": {
- "disableBodyPruning": true
- },
- "request": {
- "method": "GET",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "",
- "options": {
- "raw": {
- "language": "json"
+ "name": "Add stream server and upstream",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
}
- }
- },
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}/status",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config",
- "{{configUid}}",
- "status"
- ]
- }
- },
- "response": []
- },
- {
- "name": "Get declaration",
- "event": [
- {
- "listen": "test",
- "script": {
- "exec": [
- ""
- ],
- "type": "text/javascript"
- }
- }
- ],
- "protocolProfileBehavior": {
- "disableBodyPruning": true
- },
- "request": {
- "method": "GET",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "",
- "options": {
- "raw": {
- "language": "json"
+ "request": {
+ "method": "PATCH",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"layer4\": {\n \"servers\": [\n {\n \"name\": \"TCP_15432_service\",\n \"listen\": {\n \"address\": \"15432\",\n \"protocol\": \"tcp\"\n },\n \"upstream\": \"TCP_15432_upstream\"\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"TCP_15432_upstream\",\n \"origin\": [\n {\n \"server\": \"172.16.10.1:5432\"\n },\n {\n \"server\": \"172.16.10.1:5432\"\n }\n ]\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config",
+ "{{configUid}}"
+ ]
}
- }
+ },
+ "response": []
},
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
- ],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config",
- "{{configUid}}"
- ]
- }
- },
- "response": []
- },
- {
- "name": "Delete declaration",
- "event": [
{
- "listen": "test",
- "script": {
- "exec": [
- ""
- ],
- "type": "text/javascript"
- }
- }
- ],
- "request": {
- "method": "DELETE",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "",
- "options": {
- "raw": {
- "language": "json"
+ "name": "Remove stream server and upstream #1",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
}
- }
- },
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config",
- "{{configUid}}"
- ]
- }
- },
- "response": []
- }
- ]
- },
- {
- "name": "HTTP Headers Manipulation",
- "item": [
- {
- "name": "Create test echo service",
- "event": [
+ "request": {
+ "method": "PATCH",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"layer4\": {\n \"servers\": [\n {\n \"name\": \"TCP_10053_service\"\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"TCP_10053_upstream\"\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config",
+ "{{configUid}}"
+ ]
+ }
+ },
+ "response": []
+ },
{
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript"
- }
- }
- ],
- "request": {
- "method": "POST",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test echo app\",\n \"names\": [\n \"echo.vm-test.ie.ff.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:80\"\n },\n \"resolver\": \"8.8.8.8\",\n \"log\": {\n \"access\": \"/var/log/nginx/test-echo-access_log\",\n \"error\": \"/var/log/nginx/test-echo-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test-echo-upstream\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test-echo-upstream\",\n \"origin\": [\n {\n \"server\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n ]\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
+ "name": "Remove stream server and upstream #2",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
}
- }
- },
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config"
- ]
+ "request": {
+ "method": "PATCH",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"layer4\": {\n \"servers\": [\n {\n \"name\": \"TCP_15432_service\"\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"TCP_15432_upstream\"\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config",
+ "{{configUid}}"
+ ]
+ }
+ },
+ "response": []
}
- },
- "response": []
+ ]
},
{
- "name": "Manipulate headers - server level",
- "event": [
+ "name": "GitOps autosync",
+ "item": [
{
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript"
- }
- }
- ],
- "request": {
- "method": "PATCH",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test echo app\",\n \"names\": [\n \"echo.vm-test.ie.ff.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:80\"\n },\n \"resolver\": \"8.8.8.8\",\n \"log\": {\n \"access\": \"/var/log/nginx/test-echo-access_log\",\n \"error\": \"/var/log/nginx/test-echo-error_log\"\n },\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"X-Injected-Client-IP\",\n \"value\": \"$remote_addr\"\n },\n {\n \"name\": \"X-Injected-Echo-Test-Version\",\n \"value\": \"v1\"\n },\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ],\n \"delete\": [\n \"User-Agent\"\n ]\n },\n \"to_client\": {\n \"add\": [\n {\n \"name\": \"X-Injected-Response-Status\",\n \"value\": \"$status\"\n }\n ],\n \"delete\": [\n \"vary\"\n ],\n \"replace\": [\n {\n \"name\": \"Server\",\n \"value\": \"Echo Test Server\"\n }\n ]\n }\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test-echo-upstream\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test-echo-upstream\",\n \"origin\": [\n {\n \"server\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n ]\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
+ "name": "NGINX Plus and GitOps",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript"
+ }
}
- }
- },
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config",
- "{{configUid}}"
- ]
- }
- },
- "response": []
- },
- {
- "name": "Manipulate headers - location level",
- "event": [
- {
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript"
- }
- }
- ],
- "request": {
- "method": "PATCH",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test echo app\",\n \"names\": [\n \"echo.vm-test.ie.ff.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:80\"\n },\n \"resolver\": \"8.8.8.8\",\n \"log\": {\n \"access\": \"/var/log/nginx/test-echo-access_log\",\n \"error\": \"/var/log/nginx/test-echo-error_log\"\n },\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"X-Injected-Client-IP\",\n \"value\": \"$remote_addr\"\n },\n {\n \"name\": \"X-Injected-Echo-Test-Version\",\n \"value\": \"v1\"\n },\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ],\n \"delete\": [\n \"User-Agent\"\n ]\n },\n \"to_client\": {\n \"add\": [\n {\n \"name\": \"X-Injected-Response-Status\",\n \"value\": \"$status\"\n }\n ],\n \"delete\": [\n \"vary\"\n ],\n \"replace\": [\n {\n \"name\": \"Server\",\n \"value\": \"Echo Test Server\"\n }\n ]\n }\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test-echo-upstream\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test-echo-upstream\",\n \"origin\": [\n {\n \"server\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n ]\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 5,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.1/www.online-boutique.local.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.1/www.online-boutique.local.key\"\n }\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online_boutique_https_access_log\",\n \"error\": \"/var/log/nginx/online_boutique_https_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://upstream_boutique\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"upstream_boutique\",\n \"origin\": [\n {\n \"server\": \"192.168.2.200:80\"\n }\n ]\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config"
+ ]
}
- }
+ },
+ "response": []
},
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
+ {
+ "name": "NGINX App Protect WAF and GitOps",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript"
+ }
+ }
],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config",
- "{{configUid}}"
- ]
- }
- },
- "response": []
- }
- ],
- "description": "Test using:\n\n`curl -i echo.vm-test.ie.ff.lan`\n\nThe actual FQDN can be modified in the request JSON body"
- },
- {
- "name": "HTTPS server",
- "item": [
- {
- "name": "TLS Offload",
- "event": [
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 5,\n \"modules\": [\n \"ngx_http_app_protect_module\",\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v2/www.online-boutique.local.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v2/www.online-boutique.local.key\"\n }\n }\n ],\n \"policies\": [\n {\n \"type\": \"app_protect\",\n \"name\": \"production-policy\",\n \"active_tag\": \"gitops\",\n \"versions\": [\n {\n \"tag\": \"gitops\",\n \"displayName\": \"Production Policy - GitOps\",\n \"description\": \"This is a production-ready policy - Managed by GitOps\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v2/nap-policy-gitops.json\"\n }\n }\n ]\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online_boutique_https_access_log\",\n \"error\": \"/var/log/nginx/online_boutique_https_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://upstream_boutique\"\n }\n ],\n \"app_protect\": {\n \"enabled\": true,\n \"policy\": \"production-policy\",\n \"log\": {\n \"profile_name\": \"secops_dashboard\",\n \"enabled\": true,\n \"destination\": \"127.0.0.1:514\"\n }\n }\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"upstream_boutique\",\n \"origin\": [\n {\n \"server\": \"192.168.1.200:80\"\n }\n ]\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config"
+ ]
+ }
+ },
+ "response": []
+ },
{
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript",
- "packages": {}
- }
- }
- ],
- "request": {
- "method": "POST",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert.key\"\n }\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online_boutique_https_access_log\",\n \"error\": \"/var/log/nginx/online_boutique_https_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://upstream_boutique\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"upstream_boutique\",\n \"origin\": [\n {\n \"server\": \"192.168.2.200:80\"\n }\n ]\n }\n ]\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
+ "name": "Get declaration status",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ ""
+ ],
+ "type": "text/javascript"
+ }
+ }
+ ],
+ "protocolProfileBehavior": {
+ "disableBodyPruning": true
+ },
+ "request": {
+ "method": "GET",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}/status",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config",
+ "{{configUid}}",
+ "status"
+ ]
}
- }
+ },
+ "response": []
},
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
+ {
+ "name": "Get declaration",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ ""
+ ],
+ "type": "text/javascript"
+ }
+ }
],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config"
- ]
+ "protocolProfileBehavior": {
+ "disableBodyPruning": true
+ },
+ "request": {
+ "method": "GET",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config",
+ "{{configUid}}"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Delete declaration",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ ""
+ ],
+ "type": "text/javascript"
+ }
+ }
+ ],
+ "request": {
+ "method": "DELETE",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config",
+ "{{configUid}}"
+ ]
+ }
+ },
+ "response": []
}
- },
- "response": []
+ ]
},
{
- "name": "TLS Offload and NGINX App Protect",
- "event": [
+ "name": "Housekeeping - common endpoints",
+ "item": [
{
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript",
- "packages": {}
- }
- }
- ],
- "request": {
- "method": "POST",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert.key\"\n }\n }\n ],\n \"policies\": [\n {\n \"type\": \"app_protect\",\n \"name\": \"production-policy\",\n \"active_tag\": \"xss-blocked\",\n \"versions\": [\n {\n \"tag\": \"xss-blocked\",\n \"displayName\": \"Production Policy - GitOps\",\n \"description\": \"This is a production-ready policy - Managed by GitOps\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/nap-policy-xss-blocked.json\"\n }\n }\n ]\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online_boutique_https_access_log\",\n \"error\": \"/var/log/nginx/online_boutique_https_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://upstream_boutique\"\n }\n ],\n \"app_protect\": {\n \"enabled\": true,\n \"policy\": \"production-policy\",\n \"log\": {\n \"profile_name\": \"secops_dashboard\",\n \"enabled\": true,\n \"destination\": \"127.0.0.1:514\"\n }\n }\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"upstream_boutique\",\n \"origin\": [\n {\n \"server\": \"192.168.1.200:80\"\n }\n ]\n }\n ]\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
+ "name": "Clean NGINX configuration",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
}
- }
+ ],
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\"\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config"
+ ]
+ }
+ },
+ "response": []
},
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
+ {
+ "name": "Get declaration status",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ ""
+ ],
+ "type": "text/javascript"
+ }
+ }
],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config"
- ]
- }
- },
- "response": []
- }
- ]
- },
- {
- "name": "JWT Client Authentication",
- "item": [
- {
- "name": "JWT Client Authentication - local JWT key and Bearer token",
- "event": [
+ "protocolProfileBehavior": {
+ "disableBodyPruning": true
+ },
+ "request": {
+ "method": "GET",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}/status",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config",
+ "{{configUid}}",
+ "status"
+ ]
+ }
+ },
+ "response": []
+ },
{
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript"
- }
- }
- ],
- "request": {
- "method": "POST",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test service\",\n \"resolver\": \"8.8.8.8\",\n \"names\": [\n \"test.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/test.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/test.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream\",\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"JWT Auth with hardwired key and Bearer token\"\n }\n ]\n },\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n }\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"JWT Auth with hardwired key and Bearer token\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"JWT Authentication\",\n \"key\": \"{\\\"keys\\\": [{\\\"k\\\":\\\"ZmFudGFzdGljand0\\\",\\\"kty\\\":\\\"oct\\\",\\\"kid\\\":\\\"0001\\\"}]}\"\n }\n },\n {\n \"name\": \"JWT Auth with external key and Bearer token\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"JWT Authentication GitOps\",\n \"key\": \"http://192.168.2.5:20080/jwks.json\",\n \"cachetime\": 5\n }\n },\n {\n \"name\": \"JWT Auth with hardwired key and token in auth_token query string parameter\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"JWT Authentication\",\n \"key\": \"{\\\"keys\\\": [{\\\"k\\\":\\\"ZmFudGFzdGljand0\\\",\\\"kty\\\":\\\"oct\\\",\\\"kid\\\":\\\"0001\\\"}]}\",\n \"token_location\": \"$arg_auth_token\"\n }\n },\n {\n \"name\": \"JWT Auth with hardwired key and token in X-Auth-Token HTTP header\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"JWT Authentication\",\n \"key\": \"{\\\"keys\\\": [{\\\"k\\\":\\\"ZmFudGFzdGljand0\\\",\\\"kty\\\":\\\"oct\\\",\\\"kid\\\":\\\"0001\\\"}]}\",\n \"token_location\": \"$http_x_auth_token\"\n }\n }\n ]\n }\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
+ "name": "Get declaration",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ ""
+ ],
+ "type": "text/javascript"
+ }
+ }
+ ],
+ "protocolProfileBehavior": {
+ "disableBodyPruning": true
+ },
+ "request": {
+ "method": "GET",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config",
+ "{{configUid}}"
+ ]
}
- }
+ },
+ "response": []
},
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
+ {
+ "name": "Delete declaration",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ ""
+ ],
+ "type": "text/javascript"
+ }
+ }
],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config"
- ]
+ "request": {
+ "method": "DELETE",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config",
+ "{{configUid}}"
+ ]
+ }
+ },
+ "response": []
}
- },
- "response": []
+ ]
},
{
- "name": "JWT secret fetched from URL",
- "event": [
+ "name": "HTTP Headers Manipulation",
+ "item": [
{
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript"
- }
- }
- ],
- "request": {
- "method": "PATCH",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test service\",\n \"resolver\": \"8.8.8.8\",\n \"names\": [\n \"test.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/test.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/test.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream\",\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"JWT Auth with external key and Bearer token\"\n }\n ]\n },\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n }\n }\n ]\n }\n ]\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
+ "name": "Create test echo service",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript"
+ }
}
- }
+ ],
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test echo app\",\n \"names\": [\n \"echo.vm-test.ie.ff.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:80\"\n },\n \"resolver\": \"8.8.8.8\",\n \"log\": {\n \"access\": \"/var/log/nginx/test-echo-access_log\",\n \"error\": \"/var/log/nginx/test-echo-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test-echo-upstream\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test-echo-upstream\",\n \"origin\": [\n {\n \"server\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config"
+ ]
+ }
+ },
+ "response": []
},
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
+ {
+ "name": "Manipulate headers - server level",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript"
+ }
+ }
],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config",
- "{{configUid}}"
- ]
+ "request": {
+ "method": "PATCH",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test echo app\",\n \"names\": [\n \"echo.vm-test.ie.ff.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:80\"\n },\n \"resolver\": \"8.8.8.8\",\n \"log\": {\n \"access\": \"/var/log/nginx/test-echo-access_log\",\n \"error\": \"/var/log/nginx/test-echo-error_log\"\n },\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"X-Injected-Client-IP\",\n \"value\": \"$remote_addr\"\n },\n {\n \"name\": \"X-Injected-Echo-Test-Version\",\n \"value\": \"v1\"\n },\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ],\n \"delete\": [\n \"User-Agent\"\n ]\n },\n \"to_client\": {\n \"add\": [\n {\n \"name\": \"X-Injected-Response-Status\",\n \"value\": \"$status\"\n }\n ],\n \"delete\": [\n \"vary\"\n ],\n \"replace\": [\n {\n \"name\": \"Server\",\n \"value\": \"Echo Test Server\"\n }\n ]\n }\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test-echo-upstream\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test-echo-upstream\",\n \"origin\": [\n {\n \"server\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config",
+ "{{configUid}}"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Manipulate headers - location level",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript"
+ }
+ }
+ ],
+ "request": {
+ "method": "PATCH",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test echo app\",\n \"names\": [\n \"echo.vm-test.ie.ff.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:80\"\n },\n \"resolver\": \"8.8.8.8\",\n \"log\": {\n \"access\": \"/var/log/nginx/test-echo-access_log\",\n \"error\": \"/var/log/nginx/test-echo-error_log\"\n },\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"X-Injected-Client-IP\",\n \"value\": \"$remote_addr\"\n },\n {\n \"name\": \"X-Injected-Echo-Test-Version\",\n \"value\": \"v1\"\n },\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ],\n \"delete\": [\n \"User-Agent\"\n ]\n },\n \"to_client\": {\n \"add\": [\n {\n \"name\": \"X-Injected-Response-Status\",\n \"value\": \"$status\"\n }\n ],\n \"delete\": [\n \"vary\"\n ],\n \"replace\": [\n {\n \"name\": \"Server\",\n \"value\": \"Echo Test Server\"\n }\n ]\n }\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test-echo-upstream\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test-echo-upstream\",\n \"origin\": [\n {\n \"server\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config",
+ "{{configUid}}"
+ ]
+ }
+ },
+ "response": []
}
- },
- "response": []
+ ],
+ "description": "Test using:\n\n`curl -i echo.vm-test.ie.ff.lan`\n\nThe actual FQDN can be modified in the request JSON body"
},
{
- "name": "JWT token in auth_token query string parameter",
- "event": [
+ "name": "HTTPS server",
+ "item": [
{
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript"
- }
- }
- ],
- "request": {
- "method": "PATCH",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test service\",\n \"resolver\": \"8.8.8.8\",\n \"names\": [\n \"test.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/test.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/test.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream\",\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"JWT Auth with hardwired key and token in auth_token query string parameter\"\n }\n ]\n },\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n }\n }\n ]\n }\n ]\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
+ "name": "TLS Offload",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
+ }
+ ],
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert.key\"\n }\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online_boutique_https_access_log\",\n \"error\": \"/var/log/nginx/online_boutique_https_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://upstream_boutique\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"upstream_boutique\",\n \"origin\": [\n {\n \"server\": \"192.168.2.200:80\"\n }\n ]\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config"
+ ]
}
- }
+ },
+ "response": []
},
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
+ {
+ "name": "TLS Offload and NGINX App Protect",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
+ }
],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config",
- "{{configUid}}"
- ]
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert.key\"\n }\n }\n ],\n \"policies\": [\n {\n \"type\": \"app_protect\",\n \"name\": \"production-policy\",\n \"active_tag\": \"xss-blocked\",\n \"versions\": [\n {\n \"tag\": \"xss-blocked\",\n \"displayName\": \"Production Policy - GitOps\",\n \"description\": \"This is a production-ready policy - Managed by GitOps\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/nap-policy-xss-blocked.json\"\n }\n }\n ]\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online_boutique_https_access_log\",\n \"error\": \"/var/log/nginx/online_boutique_https_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://upstream_boutique\"\n }\n ],\n \"app_protect\": {\n \"enabled\": true,\n \"policy\": \"production-policy\",\n \"log\": {\n \"profile_name\": \"secops_dashboard\",\n \"enabled\": true,\n \"destination\": \"127.0.0.1:514\"\n }\n }\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"upstream_boutique\",\n \"origin\": [\n {\n \"server\": \"192.168.1.200:80\"\n }\n ]\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config"
+ ]
+ }
+ },
+ "response": []
}
- },
- "response": []
+ ]
},
{
- "name": "JWT token in HTTP X-Auth-Token header",
- "event": [
+ "name": "JWT Client Authentication",
+ "item": [
{
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript"
- }
- }
- ],
- "request": {
- "method": "PATCH",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test service\",\n \"resolver\": \"8.8.8.8\",\n \"names\": [\n \"test.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/test.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/test.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream\",\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"JWT Auth with hardwired key and token in X-Auth-Token HTTP header\"\n }\n ]\n },\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n }\n }\n ]\n }\n ]\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
+ "name": "JWT Client Authentication - local JWT key and Bearer token",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript"
+ }
}
- }
- },
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config",
- "{{configUid}}"
- ]
- }
- },
- "response": []
- }
- ]
- },
- {
- "name": "JWT Client Authentication and Authorization",
- "item": [
- {
- "name": "JWT Client Authentication and Authorization",
- "event": [
- {
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript"
- }
- }
- ],
- "request": {
- "method": "POST",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"JWT AuthN and AuthZ test server\",\n \"resolver\": \"8.8.8.8\",\n \"names\": [\n \"test.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/auth-test.nginx.lab_access_log\",\n \"error\": \"/var/log/nginx/auth-test.nginx.lab_error_log\"\n },\n \"headers\": {\n \"to_client\": {\n \"add\": [\n {\n \"name\": \"X-Injected-JWT-Group\",\n \"value\": \"$jwt_claim_roles\"\n }\n ]\n }\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream\",\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n },\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"jwt_authentication_local\"\n }\n ]\n },\n \"authorization\": {\n \"profile\": \"jwt role based authorization\"\n }\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"jwt_authentication_local\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"JWT Client Authentication\",\n \"key\": \"{\\\"keys\\\": [{\\\"k\\\":\\\"ZmFudGFzdGljand0\\\",\\\"kty\\\":\\\"oct\\\",\\\"kid\\\":\\\"0001\\\"}]}\",\n \"jwt_type\": \"signed\"\n }\n }\n ]\n },\n \"authorization\": [\n {\n \"name\": \"jwt role based authorization\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"claims\": [\n {\n \"name\": \"roles\",\n \"value\": [\n \"~(devops)\"\n ]\n }\n ]\n }\n }\n ]\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test service\",\n \"resolver\": \"8.8.8.8\",\n \"names\": [\n \"test.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/test.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/test.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream\",\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"JWT Auth with hardwired key and Bearer token\"\n }\n ]\n },\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n }\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"JWT Auth with hardwired key and Bearer token\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"JWT Authentication\",\n \"key\": \"{\\\"keys\\\": [{\\\"k\\\":\\\"ZmFudGFzdGljand0\\\",\\\"kty\\\":\\\"oct\\\",\\\"kid\\\":\\\"0001\\\"}]}\"\n }\n },\n {\n \"name\": \"JWT Auth with external key and Bearer token\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"JWT Authentication GitOps\",\n \"key\": \"http://192.168.2.5:20080/jwks.json\",\n \"cachetime\": 5\n }\n },\n {\n \"name\": \"JWT Auth with hardwired key and token in auth_token query string parameter\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"JWT Authentication\",\n \"key\": \"{\\\"keys\\\": [{\\\"k\\\":\\\"ZmFudGFzdGljand0\\\",\\\"kty\\\":\\\"oct\\\",\\\"kid\\\":\\\"0001\\\"}]}\",\n \"token_location\": \"$arg_auth_token\"\n }\n },\n {\n \"name\": \"JWT Auth with hardwired key and token in X-Auth-Token HTTP header\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"JWT Authentication\",\n \"key\": \"{\\\"keys\\\": [{\\\"k\\\":\\\"ZmFudGFzdGljand0\\\",\\\"kty\\\":\\\"oct\\\",\\\"kid\\\":\\\"0001\\\"}]}\",\n \"token_location\": \"$http_x_auth_token\"\n }\n }\n ]\n }\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config"
+ ]
}
- }
+ },
+ "response": []
},
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
- ],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config"
- ]
- }
- },
- "response": []
- }
- ]
- },
- {
- "name": "mTLS Client Authentication",
- "item": [
- {
- "name": "HTTPS server with mTLS, OCSP, SSL Stapling",
- "event": [
{
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript",
- "packages": {}
- }
- }
- ],
- "request": {
- "method": "POST",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"server_cert\",\n \"contents\": {\n \"content\": \"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUdSRENDQkN5Z0F3SUJBZ0lVTTNJQVZIRmxhSTVsY1d0TjZxOUVhcnlka0w4d0RRWUpLb1pJaHZjTkFRRUwKQlFBd1NURUxNQWtHQTFVRUJoTUNTVlF4RFRBTEJnTlZCQWdNQkVGemRHa3hFVEFQQmdOVkJBb01DRlJsYzNRZwpUR0ZpTVJnd0ZnWURWUVFEREE5MmJTMWliR0Z1YXk1bVppNXNZVzR3SGhjTk1qTXdOakE0TVRBd01qTTVXaGNOCk1qUXdOakEzTVRBd01qTTVXakJKTVFzd0NRWURWUVFHRXdKSlZERU5NQXNHQTFVRUNBd0VRWE4wYVRFUk1BOEcKQTFVRUNnd0lWR1Z6ZENCTVlXSXhHREFXQmdOVkJBTU1EM1p0TFdKc1lXNXJMbVptTG14aGJqQ0NBaUl3RFFZSgpLb1pJaHZjTkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFMRFQ2bnZleVZlNi9VZlk2aUtHVC9oV1A0cktDSGR0ClloZWU3RGVZR29QWGhGVjB6a3grVWExanBEZ21WUE1kVEJBdnoxODg5NzlEcHBqdmNYeFhsRmpnaUhjWDhpWVgKSXovSUVMc3dKRUNITWNsNkxmelA5eDVUY1gxTEdFblFOTWhHRzA2MjlxU2NCQmQyUUNiWlY0UWE1TkxlQnQ4cQpHQ2lXY3JiQnR3YlpiSGo1dk9aenJrdHBtRFBGS1V4bXR5b2dBQnNaTllnL0F3Y1l2RXdBOEQ0QTN0VEgxcGhvCkdYY3ZvZWpJelhRMUdmYys5azR3OFhHYWFQOGd2bTdOMXN2MnU2Yld4SHRGZHpWQk9udzJyaHUvWGYyY0N0dW4KUnIxSENKQXRRSDlkbDhzZks1czBSRlVuTlVYbFBiNTFBTjBjVFVGbEYrZlVUVmVON3dNMTdmeVZVY3IydTltSwo0UGdoWjkvMml0ZUpZV3hjK3k4V2NEQzBUV3hwZ2paVEw5Tk1GK2t6SXV2TjJOWFFybjcvSU5UQTMvNFlmWGRPCloxelpTdTlkclRMcG5DZHRpOWxuRHBKODd3bW41cVZSTlZiTlZRbldEeW5yZnoyTU1DY21jLzcvdkJFN2dDemQKNFJLWHJLdHloenlQSitycmh3NmpxYVA4QytaZGRvKzkvak9QVDFTSnUxZ21VbzFuZ2hBMWh2N0M5RUYrM2xQVApYSk5WV3dtYkdWK0p4cUdKSjJSa2toMlIrZTVIREdRY2hGWjJIcXBGTGVQN0trTHJBR2RkZFZQWEZhQ0RiU0R6ClJQd0I5WFlhakg5Zm5QWEtFT3ZpVEJhQVNjWUZwTXB5cm02UkxHUGRSVnE2RUNYVlB4MDdHdGFCaEVvVWIwK2YKVkZnNExtQkx4MldQQWdNQkFBR2pnZ0VpTUlJQkhqQUpCZ05WSFJNRUFqQUFNQkVHQ1dDR1NBR0crRUlCQVFRRQpBd0lHUURBekJnbGdoa2dCaHZoQ0FRMEVKaFlrVDNCbGJsTlRUQ0JIWlc1bGNtRjBaV1FnVTJWeWRtVnlJRU5sCmNuUnBabWxqWVhSbE1CMEdBMVVkRGdRV0JCVHZFZWJGK1JDV0JhcGVPWUdpQ0YyVHZxbExYekNCaEFZRFZSMGoKQkgwd2U0QVVFdW9Db3kvcmhMQmxzcm5KdXE2QzFJczQxbFNoVGFSTE1Fa3hDekFKQmdOVkJBWVRBa2xVTVEwdwpDd1lEVlFRSURBUkJjM1JwTVJFd0R3WURWUVFLREFoVVpYTjBJRXhoWWpFWU1CWUdBMVVFQXd3UGRtMHRZbXhoCmJtc3VabVl1YkdGdWdoUld4QjhCa3lmK1RkQXc2Q3dPZE1aT0k0NlZ2REFPQmdOVkhROEJBZjhFQkFNQ0JhQXcKRXdZRFZSMGxCQXd3Q2dZSUt3WUJCUVVIQXdFd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dJQkFHUDR6ZkdseTI1RwpneTBSeC9SSTNpNzJDVlIrSXY3SW5WTUVGWDZqRHRNV3hSblFtRGZsMWtTOVF1Y3hNb0tnOE9URStMcnlzdGJsClF4WGZiakZQekNoNHB1UGtGTmNBeG1mVmR4b20xR1lodWpoYTBQOUswUURZSDZycGlUaFdSQ2greUovQm1qZ2wKTlJabks4WGRqME85Ui9XKzJrTFRac2VFbS9hZHFVQ3dkYzNBWWlNWGh4QXkvQlh3bFRQeDMyMHZCcXYxZGFyVgp5ZlVoRlM1Rkg3enV2bGtGQ1p6M3lpOGYvYXMwbkRTUkFrY3dPRFQvN1diQlN4QTk3ZzJmRk1EMEI3WlUvbndGCmU4VnRzNDl3YmZ6QWJRMk40RUc2OEVhODE1VlFRM2N6YWthdjBCdkxHL2UwT0habGxYcUVhV1ZlWFJtSWFFOHcKWko5OEhUaDJMbUlFV2Jpdm94Kyt2UXd3bVhKTm1DRFVXNnVmcHdBOVdKQ0VhYmhxeXdGVzh1dFVENzRTVXE3SApEUDhNamtJZ0o3ekl2Tkd1RkFsSzd6c2xpV2pzeUN1OGVNamhvN2pVRFhGR1R0R0ZMUGtVa08vSysrSGVVRFg0Cm1OWDJ2aHI3NGRqRkNBTTEvOTYxWnB5NUFYUzZkd2g3MFlJL2dMdldSL0J1ejBnNEp6YUI2UFo4M1ErYm9QVHYKM1ZIS2xOWjlKQlhRTmtSc3N6U0dYWG5MYmtOTmNwVFg2cnAyZ1pUSS9NNDhGTnBxanAxOXRpQVg3bWN0cTl2SgpNejhvemhEcHZmSTlnMjFsNFZlRGdpbWEwTDVBc1pQbFdIQlZjcy9yL3dMU2YzWFVYZEs0UHpCQUdIRFBidXYrCnpKOVNqS0NFVll2bHRhMHlUUVBCSFJPa2Y2MG1sVmh6Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"server_key\",\n \"contents\": {\n \"content\": \"LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlKS0FJQkFBS0NBZ0VBc05QcWU5N0pWN3I5UjlqcUlvWlArRlkvaXNvSWQyMWlGNTdzTjVnYWc5ZUVWWFRPClRINVJyV09rT0NaVTh4MU1FQy9QWHp6M3YwT21tTzl4ZkZlVVdPQ0lkeGZ5SmhjalA4Z1F1ekFrUUljeHlYb3QKL00vM0hsTnhmVXNZU2RBMHlFWWJUcmIycEp3RUYzWkFKdGxYaEJyazB0NEczeW9ZS0paeXRzRzNCdGxzZVBtOAo1bk91UzJtWU04VXBUR2EzS2lBQUd4azFpRDhEQnhpOFRBRHdQZ0RlMU1mV21HZ1pkeStoNk1qTmREVVo5ejcyClRqRHhjWnBvL3lDK2JzM1d5L2E3cHRiRWUwVjNOVUU2ZkRhdUc3OWQvWndLMjZkR3ZVY0lrQzFBZjEyWHl4OHIKbXpSRVZTYzFSZVU5dm5VQTNSeE5RV1VYNTlSTlY0M3ZBelh0L0pWUnl2YTcyWXJnK0NGbjMvYUsxNGxoYkZ6NwpMeFp3TUxSTmJHbUNObE12MDB3WDZUTWk2ODNZMWRDdWZ2OGcxTURmL2hoOWQwNW5YTmxLNzEydE11bWNKMjJMCjJXY09rbnp2Q2FmbXBWRTFWczFWQ2RZUEtldC9QWXd3Snlaei92KzhFVHVBTE4zaEVwZXNxM0tIUEk4bjZ1dUgKRHFPcG8vd0w1bDEyajczK000OVBWSW03V0NaU2pXZUNFRFdHL3NMMFFYN2VVOU5jazFWYkNac1pYNG5Hb1lrbgpaR1NTSFpINTdrY01aQnlFVm5ZZXFrVXQ0L3NxUXVzQVoxMTFVOWNWb0lOdElQTkUvQUgxZGhxTWYxK2M5Y29RCjYrSk1Gb0JKeGdXa3luS3VicEVzWTkxRldyb1FKZFUvSFRzYTFvR0VTaFJ2VDU5VVdEZ3VZRXZIWlk4Q0F3RUEKQVFLQ0FnQVBUR1pQRFRsU004VlIvL3hSdkZrUzNUTm1LSkNPOUpHMkJYUGVZM1IzejUrTlhTdTBCb0craEk1aQpwVDVZUWtLZ2ErSi9GT0ZDVlBJRzdVQmVSNTE0Q3dVRGVMamtmci8zOXJFcjRNQmlMTkFyNUR3eVVUUEtGZUlOCnV2K0E4MWg5czBNTmpsck1ad3NibElsOFV2VjFZblpGb0J2c0Z0SThRTGZ3QTlaMzZ6dXRRNzRLR2h3TVBqaUMKMGgzK2xDeG9vcGdmd0JDWGx3d0dBeWZYVTRWMWQ5SFBpdktRQVFHakJDWDM0OWVTcEQxNDNLT21wQ2xmY01LQQp3QzU1bTZsbndCTUFIamlsaVo4RXBuNE8zUlEzSmxsVlpiaXl4RWdrZkE3TG1uNm9Ca3Jwc2VxdDVObThuRVhKCnBFbXhQcUl5Znc1WUNBMEhhNkM5WUhRN1RPRW9BbHBmWld4azAxSnpoVi9aK3FmVHM1YlMwQWNaTzFOVDRaeDgKWlF2eHQ0TDJINVcrK2R6RjhReTlidzQ2M3lKb1dydWxtNy9uQ3YvL1FpNGl0eHRnYyt0N2lwVXZzaUdTVktVWQpPelhCSXNWTUlnd0F6eUtTSEhPL21rMkEwVkgxaHB3emY2L0RzR2wxSjM4TU9pVGo4dEx1RWt3cFY4WGh5MnZwCkd0cXpsT21DS1hodlVDam9iZWlYSWJwSlIzeEM1NmliRjVadk0vQUdONzI5K0xKRFNwbHJtWVJRVHh1UTJWSE8KQWFXQ01SQWFBdUtCVnBxYTRjd25WRy9POEpkN2ZPSi9tMFlIN3FpRlJHREdvdVNOdHZJUUVtaXVkK3dRWjJ6dwpUcmFNVWk0SENtNEFPa0ZNVXBsRmt1ajA2ZHRqM2RIWUtPQkdMK25vaUp4WmJxb3kwUUtDQVFFQTFiZUl6WHh6CnRFRlp2OGRlOXljOWdCUUtNNUNIbHp6NUNMZXVkTitvemxxeDNCMW1PRStxbFkyaEd3RklIWVBJajFLYS83RlkKbExmNFpiUEJRMFhiNUo5VzQzSGIyTnEydXdRQ3ZiSXhVMW9zaGJVWlhZc2FUaE15azc2VzQ5YjU3UC9HdFE3NwpTbkVZTXNrTzRUQndyS3lBdVhDVHRtTk1Qa2J1NFBxT05PeVFQY3o3Yi92VEU1eERjMENMVS9oUXM3NWFHeCs1Citld2VjeEZNa0JKTVo2c2N5TzcySEdSNHZwTHduRXUvcU5uN2JmUElSaUx1T3BwTTdHNlUwQlBPL2todHJ5ZmQKV3U3MHJYZGJSdGRJUHlsQWxSOG9zczJqWWsrRHNPUnNESm9pbkk5WU1Va3dmdHdCNTRQbytGRGtGOHBzV202RQpSaklpenFBK0piWDlTd0tDQVFFQTA4Ly9oM0NabDg2M2xUZHNrU1JKRUZKc0RtdkZkUStzMWtlNUFwMjdnWTBXCmZJbEFGZFlRR3RORUVlTk9xS3EwdTFtS0lqWHFacWNTdU9DNzZIYTE5Tk9waHVoK1dwV0t2Ni9BTWtQSjE5SUIKQ3RqS0lkc2s0U2M3WG02MnNOV1pnQm5XT1Z3QVdzU0VzTHRac1NvWUJUVTJJS1pBOVJOWHhkSEQreGZ2SWJkNApZYngzTzk4WklNQzNlVFFiOW9jVHZab0RNWGdLaHRtTy9iMnlSeEVDSGpGRmxzYlhhc1RPeG5XOWZSVXJtdGVqCk9pdVlXaEZOM2R6dmpuVEdLY0xieWY0MWpHaUVUeFViUHVpei9ZMmk5NldCNVN6MW9zaGorRU1OaFhtRzZSYXUKQUIvelhwNldtSUJ2bDNpU0lzOGJRNkh3Qm1DTjc1R2VVVG1GUUlyaVRRS0NBUUVBbTkzWVN5MXA0VndNRGI5bApObElMRzM4Q0ZhdGlDRjR5cmpYd2FWSzVkWTVWeTFneHRmMzhSa2hkNkNrZUpGQjVsSFhGajVnVEo1dW84TnVSCnB2T3JOT2swNEhxb3dWWjZFSmtUT3JCY0l4TlFCMUFXS05BTHBrZUFDcHJreDFTQlFHVW0wZVFVUjYyRjNYd2YKZXdMdUdqRlJURzJiZlZpY1FZdFFLd3J4YmczZUFRU2ZtSU9MNVBDQmpPdlU4YS9YZzgvZlBZcjlBeFkrK3VMeAorTjB2bGlnSXZVN3lkYkNkRXpodGZVQU5qeU16cVhRemExdU1iWGNkaFEzOVFHaEIvZGhyRG1TL250Tko1YjEzCjk0bUpLbTkycDR0ckRrVEYxU3h5dWk5TjBqOFQ0U1QyU0RPOXg3ZkROOHRQdk5LYUYvUE01SU5YdXk1VGptajIKQ21EWlV3S0NBUUFOUVJYSFh1ZHRsWFR0ZEhOcHZiQ0l3ZStiRTJsZXd1VlkzMUlYZE5GWDhRRTROOHAzMDFaYwpwMTI2Rk5SR1A3QmhqTi9VOWpTOXliU2xOd0xyTUFxQTBJSHFQRUF6NE9tMnh3T3E0WTBPNFVoSmFubHpsdWYrCjR0cVhOU3hmY201UmtzeFIrSXpaSVRVQWJpalZxa0dvaWNUaVZDVDZjUVJzRDQxSStCMXhxYTV4eHo1YTA4SVoKeDVWemt5d3d5QkVYS3owSjZtNFdOQ1Q3Z2RSWEdCeGUwVXgrZStEZEFJWEQ2M2c1RElzVy9HbHRhVzcySytFSQpnaHZIZVUweExjMWRIWGd5V2hQMWN1ZXFqeHM4UVpHeUYzeENZQWJhOGRrM250S0l5S3NGaVBMSWRUZGdjMklQCkZ2SmtzeG5KN2RYUjdKODlkdXRLMDN6cHJrVEZYaXQ5QW9JQkFDcjhkb2ZCcFlFL1JuTlFwbVNET29DRm1sdTkKQlozN3h5K0puZ2FrQ2RSdHFyR1lDdkZMSnI2QnpGdXE0SHpsM0piTkRCM1BkYSs4Z2VNd2cxU1htTEhrRVFrTQpXV2ptNHpmU3hiTUtKamx3REdoeUlwSU9nQ2FQL1hyT2hxTGl4bnJ6UHFHZmM4R0FZTDE2Rm1PeGVqbVk5aERtCmNibkFqZlNwUjF1WEt2S2d6d1NLQ0VWdzc0VjJSRmRqQXBLVDl3bkpOQTZiWHQ5SXFkaS96d3BYbDQ0OVczdVMKNjRjVVpaK3luYnQ5QUlxbFNjMDdNRHl1TUtueExMbDFLeEJYenNxZlVsYWtlRGVoVmdGS05OOTNXQWJJc09ieAp1d1hTd0hXa1B6RGFHeE9wdzlSMHo2S2t2N25YZnBIYW1RWENBZEdsRjkyc1QwYW80Y3FuejFJSmJ2bz0KLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0K\"\n }\n },\n {\n \"type\": \"certificate\",\n \"name\": \"cacert\",\n \"contents\": {\n \"content\": \"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZjekNDQTF1Z0F3SUJBZ0lVVnNRZkFaTW4vazNRTU9nc0RuVEdUaU9PbGJ3d0RRWUpLb1pJaHZjTkFRRUwKQlFBd1NURUxNQWtHQTFVRUJoTUNTVlF4RFRBTEJnTlZCQWdNQkVGemRHa3hFVEFQQmdOVkJBb01DRlJsYzNRZwpUR0ZpTVJnd0ZnWURWUVFEREE5MmJTMWliR0Z1YXk1bVppNXNZVzR3SGhjTk1qTXdOakE0TURrMU5EQTRXaGNOCk1qUXdOakEzTURrMU5EQTRXakJKTVFzd0NRWURWUVFHRXdKSlZERU5NQXNHQTFVRUNBd0VRWE4wYVRFUk1BOEcKQTFVRUNnd0lWR1Z6ZENCTVlXSXhHREFXQmdOVkJBTU1EM1p0TFdKc1lXNXJMbVptTG14aGJqQ0NBaUl3RFFZSgpLb1pJaHZjTkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFLMlQwWXpkcjB0dWQzaVJRNGNzaGNhRVJTRzVjTDE2CkhRblhoYWw4emlUL1VRQUNIUGdzZDYwcWlEaldvQTJXb0lGWFFpUHkzOG1vZGtWRlR4Qmt5U2VldndOOFJiLzEKOFhaMS8yS1RnVmRDcHkvNm11WE15bXZYODJad05CVkV3QnoxUk5kbklUSk44cVh3a0d4bHozbDBib1loRkFyUQpNdmkxcW1RaHpDa2Zpb041MVkrYlBXOXpTQlFQdXNrcXJYYzRqTTJ0VENNQ2pTcFlvd1hXM1ppRmc5WEJ1Z09aCjFmdWd1Zmw4K1FJYzNZSEFoL1Z1NloraXFEOGxQeGRKODlBeDZaazVtOGdkVG9JdUhBbUNWaHFpUXBGRjkzSTgKbkYrSnRuYnBaNTRJUTZBbWYrYiswakMxdmY4Kzg0WUppaEVzWExyaGMxZTRTZ2dwdzEvcWpDb21QblhGVjEzUwpsUG5kVlhVR0taa1ZKdXdZTjJyZElmd3YrdCs5MGhwUVBmNmFBTjRCamRxOXdkdkQzSXVnS2JYZG5CQ0FUTEY4ClYyRTFTSE9VZGdRY3duK1d1WDVVOGdPa3B2b2VFN0g1REJ6Rks1WTZ2SHZlaTRlNkp3RTRDK3FJL1BmbTgreTEKNEpsOFBSOW5JQmdGQ3hrZWpwa2tRQ0I5U0dvMVZidzZhWmdZd0VQNHh6YXFYYXV3L3F4c0oxNUkrRTBndEs1OApuWUtkM0hqelk5Slh6V0NVNTdXbmc2SzNvTTIzNXpyRzJnNm1FaHQ4SStDckVMUFNuZURjZU8zVlJkc2dlblBCCis4U1JxVU8vWG9LWHNEU3I5amoxdWluVzYwTG5MZ0Zmc3JQeGlQVlZlMFh1TFZESlhCSlNoRDZDeGRyMnBSOGQKS25SRDZrTFpZZEtMQWdNQkFBR2pVekJSTUIwR0ExVWREZ1FXQkJRUzZnS2pMK3VFc0dXeXVjbTZyb0xVaXpqVwpWREFmQmdOVkhTTUVHREFXZ0JRUzZnS2pMK3VFc0dXeXVjbTZyb0xVaXpqV1ZEQVBCZ05WSFJNQkFmOEVCVEFECkFRSC9NQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUNBUUJad3B4Z2Z4N2thZFhvRHNyT1hUVXJ6dEFPMkFQRVJNaTAKaTkyNk9DTGFPbVVYZW1uKytXSUU1K2tUSE0wcS8vbUZCTURzSmdZSFVLUlNvRGNsNmh4TnVFNUNzS2trRVFTSgpMTHZrWlB0S2J5NGlxMitLZ1JtdVZxbXJNVTBYQzZMZDl3WmttL2huUjNtT3V6bko4MGZmV1JDQ0xGWDEwY2EzCnc5TGM1d1JLTFBZZXQvcEs5SitOYWN3TFJRYTczVFovMUpQNW9BU3czVjNoYkxlLy9UeWpnOURqUlZGY3FYWnEKWWs2Mm5qSkhZVzh3WmlhZzc0QXU4dHE5OG5KandBV1ROMFV5L2w1Q2VpWnV5bzZlU0RHVDNJNm1BdGU1VXBvWAppNXBkYlZ6VDdOZC9IOEwwZHZNdVZ2N0FmakZlcU91cUZNNkkzTnlvbStLWENxNmJQdGxBWEkzeVFZc0t4ZlRkCkw3SnRaTmx6MGJ6eHJhcHI4RmpYcjhML1ZkeHQza00xMnJwb2kzL3hsckR6Q2Q2b2YrQ1MxelBocUdpOUhvcUoKZEU5VGhYMklTdkd2akVSYzVVNFRsNjJBNHNyeGJQbUt0eWx3dGNGVEJacUJiRGY3ZjBBc2cveWhndXdTcktsQQpBNkRWVXVCRFErdGpwZ0N0b0ZlOEhLVDJ6UFVlaEQ2ZjVNQkhmU2ZUZ1crTlhFSXNvVDNsampjY1hsYXhPcFJWCkNQNWxCczNmekxyYnBxbUlLaWZhdWlTNWM4TzlSUjhjQTVzeWlBOTBmbmJIdDlmdGxpRG9jcFRzNUtrbjk2NkIKZUxMM1dXVldCYUtvanJzY1RkVXJoalNnVVBmam5FTXpnVzR2eEc3d3BVNHR2ME4yaEtHUWc0bVhhcDV0SU5Pcwp4WktnZXRHUldnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=\"\n }\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"vm-blank.ff.lan\"\n ],\n \"resolver\": \"192.168.1.13\",\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"server_cert\",\n \"key\": \"server_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ],\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"mTLS-client-profile\"\n }\n ]\n }\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/vm-blank.ff.lan_access_log\",\n \"error\": \"/var/log/nginx/vm-blank.ff.lan_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://origin_server\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"origin_server\",\n \"origin\": [\n {\n \"server\": \"192.168.1.200:80\"\n }\n ]\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"mTLS-client-profile\",\n \"type\": \"mtls\",\n \"mtls\": {\n \"enabled\": \"on\",\n \"client_certificates\": \"cacert\",\n \"trusted_ca_certificates\": \"cacert\",\n \"ocsp\": {\n \"enabled\": \"on\",\n \"responder\": \"http://ocsp.k8s.ie.ff.lan\"\n },\n \"stapling\": {\n \"enabled\": true,\n \"verify\": true,\n \"responder\": \"http://ocsp.k8s.ie.ff.lan\"\n }\n }\n }\n ]\n }\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
+ "name": "JWT secret fetched from URL",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript"
+ }
+ }
+ ],
+ "request": {
+ "method": "PATCH",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test service\",\n \"resolver\": \"8.8.8.8\",\n \"names\": [\n \"test.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/test.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/test.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream\",\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"JWT Auth with external key and Bearer token\"\n }\n ]\n },\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n }\n }\n ]\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config",
+ "{{configUid}}"
+ ]
}
- }
+ },
+ "response": []
},
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
- ],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config"
- ]
- }
- },
- "response": []
- }
- ]
- },
- {
- "name": "NGINX App Protect WAF",
- "item": [
- {
- "name": "Create initial NGINX configuration with NGINX App Protect WAF",
- "event": [
{
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript",
- "packages": {}
- }
- }
- ],
- "request": {
- "method": "POST",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert.key\"\n }\n }\n ],\n \"policies\": [\n {\n \"type\": \"app_protect\",\n \"name\": \"production-policy\",\n \"active_tag\": \"xss-blocked\",\n \"versions\": [\n {\n \"tag\": \"xss-blocked\",\n \"displayName\": \"Production Policy - XSS blocked\",\n \"description\": \"This is a production-ready policy - XSS blocked\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/nap-policy-xss-blocked.json\"\n }\n },\n {\n \"tag\": \"xss-allowed\",\n \"displayName\": \"Production Policy - XSS allowed\",\n \"description\": \"This is a production-ready policy - XSS allowed\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online_boutique_https_access_log\",\n \"error\": \"/var/log/nginx/online_boutique_https_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://upstream_boutique\"\n }\n ],\n \"app_protect\": {\n \"enabled\": true,\n \"policy\": \"production-policy\",\n \"log\": {\n \"profile_name\": \"secops_dashboard\",\n \"enabled\": true,\n \"destination\": \"127.0.0.1:514\"\n }\n }\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"upstream_boutique\",\n \"origin\": [\n {\n \"server\": \"192.168.1.200:80\"\n }\n ]\n }\n ]\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
+ "name": "JWT token in auth_token query string parameter",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript"
+ }
}
- }
+ ],
+ "request": {
+ "method": "PATCH",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test service\",\n \"resolver\": \"8.8.8.8\",\n \"names\": [\n \"test.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/test.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/test.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream\",\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"JWT Auth with hardwired key and token in auth_token query string parameter\"\n }\n ]\n },\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n }\n }\n ]\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config",
+ "{{configUid}}"
+ ]
+ }
+ },
+ "response": []
},
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
+ {
+ "name": "JWT token in HTTP X-Auth-Token header",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript"
+ }
+ }
],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config"
- ]
+ "request": {
+ "method": "PATCH",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test service\",\n \"resolver\": \"8.8.8.8\",\n \"names\": [\n \"test.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/test.nginx.lab-access_log\",\n \"error\": \"/var/log/nginx/test.nginx.lab-error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream\",\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"JWT Auth with hardwired key and token in X-Auth-Token HTTP header\"\n }\n ]\n },\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n }\n }\n ]\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config",
+ "{{configUid}}"
+ ]
+ }
+ },
+ "response": []
}
- },
- "response": []
+ ]
},
{
- "name": "Change active NGINX App Protect policy",
- "event": [
+ "name": "JWT Client Authentication and Authorization",
+ "item": [
{
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript",
- "packages": {}
- }
- }
- ],
- "request": {
- "method": "PATCH",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\"\n ],\n \"policies\": [\n {\n \"type\": \"app_protect\",\n \"name\": \"production-policy\",\n \"active_tag\": \"xss-allowed\",\n \"versions\": [\n {\n \"tag\": \"xss-blocked\",\n \"displayName\": \"Production Policy - XSS blocked\",\n \"description\": \"Production-ready policy - XSS blocked\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/nap-policy-xss-blocked.json\"\n }\n },\n {\n \"tag\": \"xss-allowed\",\n \"displayName\": \"Production Policy - XSS allowed\",\n \"description\": \"Production-ready policy - XSS allowed\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
+ "name": "JWT Client Authentication and Authorization",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript"
+ }
}
- }
- },
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config",
- "{{configUid}}"
- ]
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"JWT AuthN and AuthZ test server\",\n \"resolver\": \"8.8.8.8\",\n \"names\": [\n \"test.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/auth-test.nginx.lab_access_log\",\n \"error\": \"/var/log/nginx/auth-test.nginx.lab_error_log\"\n },\n \"headers\": {\n \"to_client\": {\n \"add\": [\n {\n \"name\": \"X-Injected-JWT-Group\",\n \"value\": \"$jwt_claim_roles\"\n }\n ]\n }\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream\",\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n },\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"jwt_authentication_local\"\n }\n ]\n },\n \"authorization\": {\n \"profile\": \"jwt role based authorization\"\n }\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"jwt_authentication_local\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"JWT Client Authentication\",\n \"key\": \"{\\\"keys\\\": [{\\\"k\\\":\\\"ZmFudGFzdGljand0\\\",\\\"kty\\\":\\\"oct\\\",\\\"kid\\\":\\\"0001\\\"}]}\",\n \"jwt_type\": \"signed\"\n }\n }\n ]\n },\n \"authorization\": [\n {\n \"name\": \"jwt role based authorization\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"claims\": [\n {\n \"name\": \"roles\",\n \"value\": [\n \"~(devops)\"\n ]\n }\n ]\n }\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config"
+ ]
+ }
+ },
+ "response": []
}
- },
- "response": []
+ ]
},
{
- "name": "Update TLS certificates",
- "event": [
+ "name": "mTLS Client Authentication",
+ "item": [
{
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript",
- "packages": {}
- }
- }
- ],
- "request": {
- "method": "PATCH",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert2.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert2.key\"\n }\n }\n ]\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
+ "name": "HTTPS server with mTLS, OCSP, SSL Stapling",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
}
- }
- },
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config",
- "{{configUid}}"
- ]
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"server_cert\",\n \"contents\": {\n \"content\": \"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUdSRENDQkN5Z0F3SUJBZ0lVTTNJQVZIRmxhSTVsY1d0TjZxOUVhcnlka0w4d0RRWUpLb1pJaHZjTkFRRUwKQlFBd1NURUxNQWtHQTFVRUJoTUNTVlF4RFRBTEJnTlZCQWdNQkVGemRHa3hFVEFQQmdOVkJBb01DRlJsYzNRZwpUR0ZpTVJnd0ZnWURWUVFEREE5MmJTMWliR0Z1YXk1bVppNXNZVzR3SGhjTk1qTXdOakE0TVRBd01qTTVXaGNOCk1qUXdOakEzTVRBd01qTTVXakJKTVFzd0NRWURWUVFHRXdKSlZERU5NQXNHQTFVRUNBd0VRWE4wYVRFUk1BOEcKQTFVRUNnd0lWR1Z6ZENCTVlXSXhHREFXQmdOVkJBTU1EM1p0TFdKc1lXNXJMbVptTG14aGJqQ0NBaUl3RFFZSgpLb1pJaHZjTkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFMRFQ2bnZleVZlNi9VZlk2aUtHVC9oV1A0cktDSGR0ClloZWU3RGVZR29QWGhGVjB6a3grVWExanBEZ21WUE1kVEJBdnoxODg5NzlEcHBqdmNYeFhsRmpnaUhjWDhpWVgKSXovSUVMc3dKRUNITWNsNkxmelA5eDVUY1gxTEdFblFOTWhHRzA2MjlxU2NCQmQyUUNiWlY0UWE1TkxlQnQ4cQpHQ2lXY3JiQnR3YlpiSGo1dk9aenJrdHBtRFBGS1V4bXR5b2dBQnNaTllnL0F3Y1l2RXdBOEQ0QTN0VEgxcGhvCkdYY3ZvZWpJelhRMUdmYys5azR3OFhHYWFQOGd2bTdOMXN2MnU2Yld4SHRGZHpWQk9udzJyaHUvWGYyY0N0dW4KUnIxSENKQXRRSDlkbDhzZks1czBSRlVuTlVYbFBiNTFBTjBjVFVGbEYrZlVUVmVON3dNMTdmeVZVY3IydTltSwo0UGdoWjkvMml0ZUpZV3hjK3k4V2NEQzBUV3hwZ2paVEw5Tk1GK2t6SXV2TjJOWFFybjcvSU5UQTMvNFlmWGRPCloxelpTdTlkclRMcG5DZHRpOWxuRHBKODd3bW41cVZSTlZiTlZRbldEeW5yZnoyTU1DY21jLzcvdkJFN2dDemQKNFJLWHJLdHloenlQSitycmh3NmpxYVA4QytaZGRvKzkvak9QVDFTSnUxZ21VbzFuZ2hBMWh2N0M5RUYrM2xQVApYSk5WV3dtYkdWK0p4cUdKSjJSa2toMlIrZTVIREdRY2hGWjJIcXBGTGVQN0trTHJBR2RkZFZQWEZhQ0RiU0R6ClJQd0I5WFlhakg5Zm5QWEtFT3ZpVEJhQVNjWUZwTXB5cm02UkxHUGRSVnE2RUNYVlB4MDdHdGFCaEVvVWIwK2YKVkZnNExtQkx4MldQQWdNQkFBR2pnZ0VpTUlJQkhqQUpCZ05WSFJNRUFqQUFNQkVHQ1dDR1NBR0crRUlCQVFRRQpBd0lHUURBekJnbGdoa2dCaHZoQ0FRMEVKaFlrVDNCbGJsTlRUQ0JIWlc1bGNtRjBaV1FnVTJWeWRtVnlJRU5sCmNuUnBabWxqWVhSbE1CMEdBMVVkRGdRV0JCVHZFZWJGK1JDV0JhcGVPWUdpQ0YyVHZxbExYekNCaEFZRFZSMGoKQkgwd2U0QVVFdW9Db3kvcmhMQmxzcm5KdXE2QzFJczQxbFNoVGFSTE1Fa3hDekFKQmdOVkJBWVRBa2xVTVEwdwpDd1lEVlFRSURBUkJjM1JwTVJFd0R3WURWUVFLREFoVVpYTjBJRXhoWWpFWU1CWUdBMVVFQXd3UGRtMHRZbXhoCmJtc3VabVl1YkdGdWdoUld4QjhCa3lmK1RkQXc2Q3dPZE1aT0k0NlZ2REFPQmdOVkhROEJBZjhFQkFNQ0JhQXcKRXdZRFZSMGxCQXd3Q2dZSUt3WUJCUVVIQXdFd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dJQkFHUDR6ZkdseTI1RwpneTBSeC9SSTNpNzJDVlIrSXY3SW5WTUVGWDZqRHRNV3hSblFtRGZsMWtTOVF1Y3hNb0tnOE9URStMcnlzdGJsClF4WGZiakZQekNoNHB1UGtGTmNBeG1mVmR4b20xR1lodWpoYTBQOUswUURZSDZycGlUaFdSQ2greUovQm1qZ2wKTlJabks4WGRqME85Ui9XKzJrTFRac2VFbS9hZHFVQ3dkYzNBWWlNWGh4QXkvQlh3bFRQeDMyMHZCcXYxZGFyVgp5ZlVoRlM1Rkg3enV2bGtGQ1p6M3lpOGYvYXMwbkRTUkFrY3dPRFQvN1diQlN4QTk3ZzJmRk1EMEI3WlUvbndGCmU4VnRzNDl3YmZ6QWJRMk40RUc2OEVhODE1VlFRM2N6YWthdjBCdkxHL2UwT0habGxYcUVhV1ZlWFJtSWFFOHcKWko5OEhUaDJMbUlFV2Jpdm94Kyt2UXd3bVhKTm1DRFVXNnVmcHdBOVdKQ0VhYmhxeXdGVzh1dFVENzRTVXE3SApEUDhNamtJZ0o3ekl2Tkd1RkFsSzd6c2xpV2pzeUN1OGVNamhvN2pVRFhGR1R0R0ZMUGtVa08vSysrSGVVRFg0Cm1OWDJ2aHI3NGRqRkNBTTEvOTYxWnB5NUFYUzZkd2g3MFlJL2dMdldSL0J1ejBnNEp6YUI2UFo4M1ErYm9QVHYKM1ZIS2xOWjlKQlhRTmtSc3N6U0dYWG5MYmtOTmNwVFg2cnAyZ1pUSS9NNDhGTnBxanAxOXRpQVg3bWN0cTl2SgpNejhvemhEcHZmSTlnMjFsNFZlRGdpbWEwTDVBc1pQbFdIQlZjcy9yL3dMU2YzWFVYZEs0UHpCQUdIRFBidXYrCnpKOVNqS0NFVll2bHRhMHlUUVBCSFJPa2Y2MG1sVmh6Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"server_key\",\n \"contents\": {\n \"content\": \"LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlKS0FJQkFBS0NBZ0VBc05QcWU5N0pWN3I5UjlqcUlvWlArRlkvaXNvSWQyMWlGNTdzTjVnYWc5ZUVWWFRPClRINVJyV09rT0NaVTh4MU1FQy9QWHp6M3YwT21tTzl4ZkZlVVdPQ0lkeGZ5SmhjalA4Z1F1ekFrUUljeHlYb3QKL00vM0hsTnhmVXNZU2RBMHlFWWJUcmIycEp3RUYzWkFKdGxYaEJyazB0NEczeW9ZS0paeXRzRzNCdGxzZVBtOAo1bk91UzJtWU04VXBUR2EzS2lBQUd4azFpRDhEQnhpOFRBRHdQZ0RlMU1mV21HZ1pkeStoNk1qTmREVVo5ejcyClRqRHhjWnBvL3lDK2JzM1d5L2E3cHRiRWUwVjNOVUU2ZkRhdUc3OWQvWndLMjZkR3ZVY0lrQzFBZjEyWHl4OHIKbXpSRVZTYzFSZVU5dm5VQTNSeE5RV1VYNTlSTlY0M3ZBelh0L0pWUnl2YTcyWXJnK0NGbjMvYUsxNGxoYkZ6NwpMeFp3TUxSTmJHbUNObE12MDB3WDZUTWk2ODNZMWRDdWZ2OGcxTURmL2hoOWQwNW5YTmxLNzEydE11bWNKMjJMCjJXY09rbnp2Q2FmbXBWRTFWczFWQ2RZUEtldC9QWXd3Snlaei92KzhFVHVBTE4zaEVwZXNxM0tIUEk4bjZ1dUgKRHFPcG8vd0w1bDEyajczK000OVBWSW03V0NaU2pXZUNFRFdHL3NMMFFYN2VVOU5jazFWYkNac1pYNG5Hb1lrbgpaR1NTSFpINTdrY01aQnlFVm5ZZXFrVXQ0L3NxUXVzQVoxMTFVOWNWb0lOdElQTkUvQUgxZGhxTWYxK2M5Y29RCjYrSk1Gb0JKeGdXa3luS3VicEVzWTkxRldyb1FKZFUvSFRzYTFvR0VTaFJ2VDU5VVdEZ3VZRXZIWlk4Q0F3RUEKQVFLQ0FnQVBUR1pQRFRsU004VlIvL3hSdkZrUzNUTm1LSkNPOUpHMkJYUGVZM1IzejUrTlhTdTBCb0craEk1aQpwVDVZUWtLZ2ErSi9GT0ZDVlBJRzdVQmVSNTE0Q3dVRGVMamtmci8zOXJFcjRNQmlMTkFyNUR3eVVUUEtGZUlOCnV2K0E4MWg5czBNTmpsck1ad3NibElsOFV2VjFZblpGb0J2c0Z0SThRTGZ3QTlaMzZ6dXRRNzRLR2h3TVBqaUMKMGgzK2xDeG9vcGdmd0JDWGx3d0dBeWZYVTRWMWQ5SFBpdktRQVFHakJDWDM0OWVTcEQxNDNLT21wQ2xmY01LQQp3QzU1bTZsbndCTUFIamlsaVo4RXBuNE8zUlEzSmxsVlpiaXl4RWdrZkE3TG1uNm9Ca3Jwc2VxdDVObThuRVhKCnBFbXhQcUl5Znc1WUNBMEhhNkM5WUhRN1RPRW9BbHBmWld4azAxSnpoVi9aK3FmVHM1YlMwQWNaTzFOVDRaeDgKWlF2eHQ0TDJINVcrK2R6RjhReTlidzQ2M3lKb1dydWxtNy9uQ3YvL1FpNGl0eHRnYyt0N2lwVXZzaUdTVktVWQpPelhCSXNWTUlnd0F6eUtTSEhPL21rMkEwVkgxaHB3emY2L0RzR2wxSjM4TU9pVGo4dEx1RWt3cFY4WGh5MnZwCkd0cXpsT21DS1hodlVDam9iZWlYSWJwSlIzeEM1NmliRjVadk0vQUdONzI5K0xKRFNwbHJtWVJRVHh1UTJWSE8KQWFXQ01SQWFBdUtCVnBxYTRjd25WRy9POEpkN2ZPSi9tMFlIN3FpRlJHREdvdVNOdHZJUUVtaXVkK3dRWjJ6dwpUcmFNVWk0SENtNEFPa0ZNVXBsRmt1ajA2ZHRqM2RIWUtPQkdMK25vaUp4WmJxb3kwUUtDQVFFQTFiZUl6WHh6CnRFRlp2OGRlOXljOWdCUUtNNUNIbHp6NUNMZXVkTitvemxxeDNCMW1PRStxbFkyaEd3RklIWVBJajFLYS83RlkKbExmNFpiUEJRMFhiNUo5VzQzSGIyTnEydXdRQ3ZiSXhVMW9zaGJVWlhZc2FUaE15azc2VzQ5YjU3UC9HdFE3NwpTbkVZTXNrTzRUQndyS3lBdVhDVHRtTk1Qa2J1NFBxT05PeVFQY3o3Yi92VEU1eERjMENMVS9oUXM3NWFHeCs1Citld2VjeEZNa0JKTVo2c2N5TzcySEdSNHZwTHduRXUvcU5uN2JmUElSaUx1T3BwTTdHNlUwQlBPL2todHJ5ZmQKV3U3MHJYZGJSdGRJUHlsQWxSOG9zczJqWWsrRHNPUnNESm9pbkk5WU1Va3dmdHdCNTRQbytGRGtGOHBzV202RQpSaklpenFBK0piWDlTd0tDQVFFQTA4Ly9oM0NabDg2M2xUZHNrU1JKRUZKc0RtdkZkUStzMWtlNUFwMjdnWTBXCmZJbEFGZFlRR3RORUVlTk9xS3EwdTFtS0lqWHFacWNTdU9DNzZIYTE5Tk9waHVoK1dwV0t2Ni9BTWtQSjE5SUIKQ3RqS0lkc2s0U2M3WG02MnNOV1pnQm5XT1Z3QVdzU0VzTHRac1NvWUJUVTJJS1pBOVJOWHhkSEQreGZ2SWJkNApZYngzTzk4WklNQzNlVFFiOW9jVHZab0RNWGdLaHRtTy9iMnlSeEVDSGpGRmxzYlhhc1RPeG5XOWZSVXJtdGVqCk9pdVlXaEZOM2R6dmpuVEdLY0xieWY0MWpHaUVUeFViUHVpei9ZMmk5NldCNVN6MW9zaGorRU1OaFhtRzZSYXUKQUIvelhwNldtSUJ2bDNpU0lzOGJRNkh3Qm1DTjc1R2VVVG1GUUlyaVRRS0NBUUVBbTkzWVN5MXA0VndNRGI5bApObElMRzM4Q0ZhdGlDRjR5cmpYd2FWSzVkWTVWeTFneHRmMzhSa2hkNkNrZUpGQjVsSFhGajVnVEo1dW84TnVSCnB2T3JOT2swNEhxb3dWWjZFSmtUT3JCY0l4TlFCMUFXS05BTHBrZUFDcHJreDFTQlFHVW0wZVFVUjYyRjNYd2YKZXdMdUdqRlJURzJiZlZpY1FZdFFLd3J4YmczZUFRU2ZtSU9MNVBDQmpPdlU4YS9YZzgvZlBZcjlBeFkrK3VMeAorTjB2bGlnSXZVN3lkYkNkRXpodGZVQU5qeU16cVhRemExdU1iWGNkaFEzOVFHaEIvZGhyRG1TL250Tko1YjEzCjk0bUpLbTkycDR0ckRrVEYxU3h5dWk5TjBqOFQ0U1QyU0RPOXg3ZkROOHRQdk5LYUYvUE01SU5YdXk1VGptajIKQ21EWlV3S0NBUUFOUVJYSFh1ZHRsWFR0ZEhOcHZiQ0l3ZStiRTJsZXd1VlkzMUlYZE5GWDhRRTROOHAzMDFaYwpwMTI2Rk5SR1A3QmhqTi9VOWpTOXliU2xOd0xyTUFxQTBJSHFQRUF6NE9tMnh3T3E0WTBPNFVoSmFubHpsdWYrCjR0cVhOU3hmY201UmtzeFIrSXpaSVRVQWJpalZxa0dvaWNUaVZDVDZjUVJzRDQxSStCMXhxYTV4eHo1YTA4SVoKeDVWemt5d3d5QkVYS3owSjZtNFdOQ1Q3Z2RSWEdCeGUwVXgrZStEZEFJWEQ2M2c1RElzVy9HbHRhVzcySytFSQpnaHZIZVUweExjMWRIWGd5V2hQMWN1ZXFqeHM4UVpHeUYzeENZQWJhOGRrM250S0l5S3NGaVBMSWRUZGdjMklQCkZ2SmtzeG5KN2RYUjdKODlkdXRLMDN6cHJrVEZYaXQ5QW9JQkFDcjhkb2ZCcFlFL1JuTlFwbVNET29DRm1sdTkKQlozN3h5K0puZ2FrQ2RSdHFyR1lDdkZMSnI2QnpGdXE0SHpsM0piTkRCM1BkYSs4Z2VNd2cxU1htTEhrRVFrTQpXV2ptNHpmU3hiTUtKamx3REdoeUlwSU9nQ2FQL1hyT2hxTGl4bnJ6UHFHZmM4R0FZTDE2Rm1PeGVqbVk5aERtCmNibkFqZlNwUjF1WEt2S2d6d1NLQ0VWdzc0VjJSRmRqQXBLVDl3bkpOQTZiWHQ5SXFkaS96d3BYbDQ0OVczdVMKNjRjVVpaK3luYnQ5QUlxbFNjMDdNRHl1TUtueExMbDFLeEJYenNxZlVsYWtlRGVoVmdGS05OOTNXQWJJc09ieAp1d1hTd0hXa1B6RGFHeE9wdzlSMHo2S2t2N25YZnBIYW1RWENBZEdsRjkyc1QwYW80Y3FuejFJSmJ2bz0KLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0K\"\n }\n },\n {\n \"type\": \"certificate\",\n \"name\": \"cacert\",\n \"contents\": {\n \"content\": \"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZjekNDQTF1Z0F3SUJBZ0lVVnNRZkFaTW4vazNRTU9nc0RuVEdUaU9PbGJ3d0RRWUpLb1pJaHZjTkFRRUwKQlFBd1NURUxNQWtHQTFVRUJoTUNTVlF4RFRBTEJnTlZCQWdNQkVGemRHa3hFVEFQQmdOVkJBb01DRlJsYzNRZwpUR0ZpTVJnd0ZnWURWUVFEREE5MmJTMWliR0Z1YXk1bVppNXNZVzR3SGhjTk1qTXdOakE0TURrMU5EQTRXaGNOCk1qUXdOakEzTURrMU5EQTRXakJKTVFzd0NRWURWUVFHRXdKSlZERU5NQXNHQTFVRUNBd0VRWE4wYVRFUk1BOEcKQTFVRUNnd0lWR1Z6ZENCTVlXSXhHREFXQmdOVkJBTU1EM1p0TFdKc1lXNXJMbVptTG14aGJqQ0NBaUl3RFFZSgpLb1pJaHZjTkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFLMlQwWXpkcjB0dWQzaVJRNGNzaGNhRVJTRzVjTDE2CkhRblhoYWw4emlUL1VRQUNIUGdzZDYwcWlEaldvQTJXb0lGWFFpUHkzOG1vZGtWRlR4Qmt5U2VldndOOFJiLzEKOFhaMS8yS1RnVmRDcHkvNm11WE15bXZYODJad05CVkV3QnoxUk5kbklUSk44cVh3a0d4bHozbDBib1loRkFyUQpNdmkxcW1RaHpDa2Zpb041MVkrYlBXOXpTQlFQdXNrcXJYYzRqTTJ0VENNQ2pTcFlvd1hXM1ppRmc5WEJ1Z09aCjFmdWd1Zmw4K1FJYzNZSEFoL1Z1NloraXFEOGxQeGRKODlBeDZaazVtOGdkVG9JdUhBbUNWaHFpUXBGRjkzSTgKbkYrSnRuYnBaNTRJUTZBbWYrYiswakMxdmY4Kzg0WUppaEVzWExyaGMxZTRTZ2dwdzEvcWpDb21QblhGVjEzUwpsUG5kVlhVR0taa1ZKdXdZTjJyZElmd3YrdCs5MGhwUVBmNmFBTjRCamRxOXdkdkQzSXVnS2JYZG5CQ0FUTEY4ClYyRTFTSE9VZGdRY3duK1d1WDVVOGdPa3B2b2VFN0g1REJ6Rks1WTZ2SHZlaTRlNkp3RTRDK3FJL1BmbTgreTEKNEpsOFBSOW5JQmdGQ3hrZWpwa2tRQ0I5U0dvMVZidzZhWmdZd0VQNHh6YXFYYXV3L3F4c0oxNUkrRTBndEs1OApuWUtkM0hqelk5Slh6V0NVNTdXbmc2SzNvTTIzNXpyRzJnNm1FaHQ4SStDckVMUFNuZURjZU8zVlJkc2dlblBCCis4U1JxVU8vWG9LWHNEU3I5amoxdWluVzYwTG5MZ0Zmc3JQeGlQVlZlMFh1TFZESlhCSlNoRDZDeGRyMnBSOGQKS25SRDZrTFpZZEtMQWdNQkFBR2pVekJSTUIwR0ExVWREZ1FXQkJRUzZnS2pMK3VFc0dXeXVjbTZyb0xVaXpqVwpWREFmQmdOVkhTTUVHREFXZ0JRUzZnS2pMK3VFc0dXeXVjbTZyb0xVaXpqV1ZEQVBCZ05WSFJNQkFmOEVCVEFECkFRSC9NQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUNBUUJad3B4Z2Z4N2thZFhvRHNyT1hUVXJ6dEFPMkFQRVJNaTAKaTkyNk9DTGFPbVVYZW1uKytXSUU1K2tUSE0wcS8vbUZCTURzSmdZSFVLUlNvRGNsNmh4TnVFNUNzS2trRVFTSgpMTHZrWlB0S2J5NGlxMitLZ1JtdVZxbXJNVTBYQzZMZDl3WmttL2huUjNtT3V6bko4MGZmV1JDQ0xGWDEwY2EzCnc5TGM1d1JLTFBZZXQvcEs5SitOYWN3TFJRYTczVFovMUpQNW9BU3czVjNoYkxlLy9UeWpnOURqUlZGY3FYWnEKWWs2Mm5qSkhZVzh3WmlhZzc0QXU4dHE5OG5KandBV1ROMFV5L2w1Q2VpWnV5bzZlU0RHVDNJNm1BdGU1VXBvWAppNXBkYlZ6VDdOZC9IOEwwZHZNdVZ2N0FmakZlcU91cUZNNkkzTnlvbStLWENxNmJQdGxBWEkzeVFZc0t4ZlRkCkw3SnRaTmx6MGJ6eHJhcHI4RmpYcjhML1ZkeHQza00xMnJwb2kzL3hsckR6Q2Q2b2YrQ1MxelBocUdpOUhvcUoKZEU5VGhYMklTdkd2akVSYzVVNFRsNjJBNHNyeGJQbUt0eWx3dGNGVEJacUJiRGY3ZjBBc2cveWhndXdTcktsQQpBNkRWVXVCRFErdGpwZ0N0b0ZlOEhLVDJ6UFVlaEQ2ZjVNQkhmU2ZUZ1crTlhFSXNvVDNsampjY1hsYXhPcFJWCkNQNWxCczNmekxyYnBxbUlLaWZhdWlTNWM4TzlSUjhjQTVzeWlBOTBmbmJIdDlmdGxpRG9jcFRzNUtrbjk2NkIKZUxMM1dXVldCYUtvanJzY1RkVXJoalNnVVBmam5FTXpnVzR2eEc3d3BVNHR2ME4yaEtHUWc0bVhhcDV0SU5Pcwp4WktnZXRHUldnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=\"\n }\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"vm-blank.ff.lan\"\n ],\n \"resolver\": \"192.168.1.13\",\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"server_cert\",\n \"key\": \"server_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ],\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"mTLS-client-profile\"\n }\n ]\n }\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/vm-blank.ff.lan_access_log\",\n \"error\": \"/var/log/nginx/vm-blank.ff.lan_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://origin_server\"\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"origin_server\",\n \"origin\": [\n {\n \"server\": \"192.168.1.200:80\"\n }\n ]\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"mTLS-client-profile\",\n \"type\": \"mtls\",\n \"mtls\": {\n \"enabled\": \"on\",\n \"client_certificates\": \"cacert\",\n \"trusted_ca_certificates\": \"cacert\",\n \"ocsp\": {\n \"enabled\": \"on\",\n \"responder\": \"http://ocsp.k8s.ie.ff.lan\"\n },\n \"stapling\": {\n \"enabled\": true,\n \"verify\": true,\n \"responder\": \"http://ocsp.k8s.ie.ff.lan\"\n }\n }\n }\n ]\n }\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config"
+ ]
+ }
+ },
+ "response": []
}
- },
- "response": []
+ ]
},
{
- "name": "Disable NGINX App Protect WAF",
- "event": [
+ "name": "NGINX App Protect WAF",
+ "item": [
{
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript",
- "packages": {}
- }
- }
- ],
- "request": {
- "method": "PATCH",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online_boutique_https_access_log\",\n \"error\": \"/var/log/nginx/online_boutique_https_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://upstream_boutique\"\n }\n ]\n }\n ]\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
+ "name": "Create initial NGINX configuration with NGINX App Protect WAF",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
}
- }
+ ],
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert.key\"\n }\n }\n ],\n \"policies\": [\n {\n \"type\": \"app_protect\",\n \"name\": \"production-policy\",\n \"active_tag\": \"xss-blocked\",\n \"versions\": [\n {\n \"tag\": \"xss-blocked\",\n \"displayName\": \"Production Policy - XSS blocked\",\n \"description\": \"This is a production-ready policy - XSS blocked\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/nap-policy-xss-blocked.json\"\n }\n },\n {\n \"tag\": \"xss-allowed\",\n \"displayName\": \"Production Policy - XSS allowed\",\n \"description\": \"This is a production-ready policy - XSS allowed\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online_boutique_https_access_log\",\n \"error\": \"/var/log/nginx/online_boutique_https_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://upstream_boutique\"\n }\n ],\n \"app_protect\": {\n \"enabled\": true,\n \"policy\": \"production-policy\",\n \"log\": {\n \"profile_name\": \"secops_dashboard\",\n \"enabled\": true,\n \"destination\": \"127.0.0.1:514\"\n }\n }\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"upstream_boutique\",\n \"origin\": [\n {\n \"server\": \"192.168.1.200:80\"\n }\n ]\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config"
+ ]
+ }
+ },
+ "response": []
},
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
+ {
+ "name": "Change active NGINX App Protect policy",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
+ }
],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config",
- "{{configUid}}"
- ]
- }
- },
- "response": []
- }
- ]
- },
- {
- "name": "NGINX Javascript",
- "item": [
- {
- "name": "NGINX Javascript test",
- "event": [
+ "request": {
+ "method": "PATCH",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\"\n ],\n \"policies\": [\n {\n \"type\": \"app_protect\",\n \"name\": \"production-policy\",\n \"active_tag\": \"xss-allowed\",\n \"versions\": [\n {\n \"tag\": \"xss-blocked\",\n \"displayName\": \"Production Policy - XSS blocked\",\n \"description\": \"Production-ready policy - XSS blocked\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/nap-policy-xss-blocked.json\"\n }\n },\n {\n \"tag\": \"xss-allowed\",\n \"displayName\": \"Production Policy - XSS allowed\",\n \"description\": \"Production-ready policy - XSS allowed\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config",
+ "{{configUid}}"
+ ]
+ }
+ },
+ "response": []
+ },
{
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript"
- }
- }
- ],
- "request": {
- "method": "POST",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Example HTTP server with Javascript\",\n \"resolver\": \"8.8.8.8\",\n \"names\": [\n \"njs-test.vm-test.ie.ff.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/njs-test.nginx.lab_access_log\",\n \"error\": \"/var/log/nginx/njs-test.nginx.lab_error_log\"\n },\n \"njs\": [\n {\n \"hook\": {\n \"type\": \"js_set\",\n \"js_set\": {\n \"variable\": \"$serverVarSetByNjs\"\n }\n },\n \"profile\": \"njs_set_variable\",\n \"function\": \"njsSetVariable\"\n }\n ],\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"X-Injected-Client-IP\",\n \"value\": \"$remote_addr\"\n },\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n },\n \"locations\": [\n {\n \"uri\": \"/echo\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream\",\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"X-Injected-Client-IP\",\n \"value\": \"$remote_addr\"\n },\n {\n \"name\": \"X-HTTP-Var-Set-By-Njs\",\n \"value\": \"$httpVarSetByNjs\"\n },\n {\n \"name\": \"X-Server-Var-Set-By-Njs\",\n \"value\": \"$serverVarSetByNjs\"\n },\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n }\n },\n {\n \"uri\": \"/generatecontent\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream\",\n \"njs\": [\n {\n \"hook\": {\n \"type\": \"js_content\"\n },\n \"profile\": \"njs_set_content\",\n \"function\": \"njsSetContent\"\n }\n ],\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"X-Injected-Client-IP\",\n \"value\": \"$remote_addr\"\n },\n {\n \"name\": \"X-HTTP-Var-Set-By-Njs\",\n \"value\": \"$httpVarSetByNjs\"\n },\n {\n \"name\": \"X-Server-Var-Set-By-Njs\",\n \"value\": \"$serverVarSetByNjs\"\n },\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n }\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n ],\n \"njs\": [\n {\n \"hook\": {\n \"type\": \"js_set\",\n \"js_set\": {\n \"variable\": \"$httpVarSetByNjs\"\n }\n },\n \"profile\": \"njs_set_variable\",\n \"function\": \"njsSetVariable\"\n }\n ],\n \"njs_profiles\": [\n {\n \"name\": \"njs_set_variable\",\n \"file\": {\n \"content\": \"ZnVuY3Rpb24gbmpzU2V0VmFyaWFibGUocikgewogICAgcmV0dXJuICJWYXJpYWJsZV9zZXRfYnlfamF2YXNjcmlwdCAtIFVSSSAiK3IudXJpOwp9CgpleHBvcnQgZGVmYXVsdCB7bmpzU2V0VmFyaWFibGV9Cgo=\"\n }\n },\n {\n \"name\": \"njs_set_content\",\n \"file\": {\n \"content\": \"ZnVuY3Rpb24gbmpzU2V0Q29udGVudChyKSB7CiAgci5yZXR1cm4oMjAwLCAiSGVsbG8gd29ybGQhXG4iKTsKfQoKZXhwb3J0IGRlZmF1bHQge25qc1NldENvbnRlbnR9Cg==\"\n }\n }\n ]\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
+ "name": "Update TLS certificates",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
}
- }
+ ],
+ "request": {
+ "method": "PATCH",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_app_protect_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert2.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v4.2/testcert2.key\"\n }\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config",
+ "{{configUid}}"
+ ]
+ }
+ },
+ "response": []
},
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
+ {
+ "name": "Disable NGINX App Protect WAF",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
+ }
],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config"
- ]
+ "request": {
+ "method": "PATCH",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": []\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online_boutique_https_access_log\",\n \"error\": \"/var/log/nginx/online_boutique_https_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://upstream_boutique\"\n }\n ]\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config",
+ "{{configUid}}"
+ ]
+ }
+ },
+ "response": []
}
- },
- "response": []
- }
- ]
- },
- {
- "name": "Server-side and source of truth authentication",
- "item": [
+ ]
+ },
{
- "name": "Bearer Token, Basic and HTTP header upstream authentication",
- "event": [
+ "name": "NGINX Javascript",
+ "item": [
{
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript"
- }
- }
- ],
- "request": {
- "method": "POST",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v2/www.online-boutique.local.crt\",\n \"authentication\": [\n {\n \"profile\": \"Basic authentication profile\"\n }\n ]\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v2/www.online-boutique.local.key\"\n }\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online_boutique_https_access_log\",\n \"error\": \"/var/log/nginx/online_boutique_https_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://upstream_boutique\",\n \"authentication\": {\n \"server\": [\n {\n \"profile\": \"Bearer token-based authentication profile\"\n }\n ]\n }\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"upstream_boutique\",\n \"origin\": [\n {\n \"server\": \"192.168.2.200:80\"\n }\n ]\n }\n ],\n \"authentication\": {\n \"server\": [\n {\n \"name\": \"Bearer token-based authentication profile\",\n \"type\": \"token\",\n \"token\": {\n \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDI0ODEzNjcsImV4cCI6MTcwMjQ4MTM2OH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIl19.SKA_7MszAypMEtX5NDQ0TcUbVYx_Wt0hrtmuyTmrVKU\",\n \"type\": \"bearer\"\n }\n },\n {\n \"name\": \"Header-based authentication profile\",\n \"type\": \"token\",\n \"token\": {\n \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDI0ODEzNjcsImV4cCI6MTcwMjQ4MTM2OH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIl19.SKA_7MszAypMEtX5NDQ0TcUbVYx_Wt0hrtmuyTmrVKU\",\n \"type\": \"header\",\n \"location\": \"X-AUTH-TOKEN\"\n }\n },\n {\n \"name\": \"Basic authentication profile\",\n \"type\": \"token\",\n \"token\": {\n \"type\": \"basic\",\n \"username\": \"authusername\",\n \"password\": \"YXV0aHBhc3N3b3Jk\"\n }\n }\n ]\n }\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
+ "name": "NGINX Javascript test",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript"
+ }
}
- }
- },
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config"
- ]
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Example HTTP server with Javascript\",\n \"resolver\": \"8.8.8.8\",\n \"names\": [\n \"njs-test.vm-test.ie.ff.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:80\"\n },\n \"log\": {\n \"access\": \"/var/log/nginx/njs-test.nginx.lab_access_log\",\n \"error\": \"/var/log/nginx/njs-test.nginx.lab_error_log\"\n },\n \"njs\": [\n {\n \"hook\": {\n \"type\": \"js_set\",\n \"js_set\": {\n \"variable\": \"$serverVarSetByNjs\"\n }\n },\n \"profile\": \"njs_set_variable\",\n \"function\": \"njsSetVariable\"\n }\n ],\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"X-Injected-Client-IP\",\n \"value\": \"$remote_addr\"\n },\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n },\n \"locations\": [\n {\n \"uri\": \"/echo\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream\",\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"X-Injected-Client-IP\",\n \"value\": \"$remote_addr\"\n },\n {\n \"name\": \"X-HTTP-Var-Set-By-Njs\",\n \"value\": \"$httpVarSetByNjs\"\n },\n {\n \"name\": \"X-Server-Var-Set-By-Njs\",\n \"value\": \"$serverVarSetByNjs\"\n },\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n }\n },\n {\n \"uri\": \"/generatecontent\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test_upstream\",\n \"njs\": [\n {\n \"hook\": {\n \"type\": \"js_content\"\n },\n \"profile\": \"njs_set_content\",\n \"function\": \"njsSetContent\"\n }\n ],\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"X-Injected-Client-IP\",\n \"value\": \"$remote_addr\"\n },\n {\n \"name\": \"X-HTTP-Var-Set-By-Njs\",\n \"value\": \"$httpVarSetByNjs\"\n },\n {\n \"name\": \"X-Server-Var-Set-By-Njs\",\n \"value\": \"$serverVarSetByNjs\"\n },\n {\n \"name\": \"Host\",\n \"value\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n }\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test_upstream\",\n \"origin\": [\n {\n \"server\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n ],\n \"njs\": [\n {\n \"hook\": {\n \"type\": \"js_set\",\n \"js_set\": {\n \"variable\": \"$httpVarSetByNjs\"\n }\n },\n \"profile\": \"njs_set_variable\",\n \"function\": \"njsSetVariable\"\n }\n ],\n \"njs_profiles\": [\n {\n \"name\": \"njs_set_variable\",\n \"file\": {\n \"content\": \"ZnVuY3Rpb24gbmpzU2V0VmFyaWFibGUocikgewogICAgcmV0dXJuICJWYXJpYWJsZV9zZXRfYnlfamF2YXNjcmlwdCAtIFVSSSAiK3IudXJpOwp9CgpleHBvcnQgZGVmYXVsdCB7bmpzU2V0VmFyaWFibGV9Cgo=\"\n }\n },\n {\n \"name\": \"njs_set_content\",\n \"file\": {\n \"content\": \"ZnVuY3Rpb24gbmpzU2V0Q29udGVudChyKSB7CiAgci5yZXR1cm4oMjAwLCAiSGVsbG8gd29ybGQhXG4iKTsKfQoKZXhwb3J0IGRlZmF1bHQge25qc1NldENvbnRlbnR9Cg==\"\n }\n }\n ]\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config"
+ ]
+ }
+ },
+ "response": []
}
- },
- "response": []
+ ]
},
{
- "name": "mTLS upstream authentication",
- "event": [
+ "name": "Server-side and source of truth authentication",
+ "item": [
{
- "listen": "test",
- "script": {
- "exec": [
- "var respData = JSON.parse(responseBody);",
- "",
- "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
- "",
- "pm.collectionVariables.set('configUid',respData.configUid);"
- ],
- "type": "text/javascript",
- "packages": {}
- }
- }
- ],
- "request": {
- "method": "POST",
- "header": [],
- "body": {
- "mode": "raw",
- "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v2/www.online-boutique.local.crt\",\n \"authentication\": [\n {\n \"profile\": \"Basic authentication profile\"\n }\n ]\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v2/www.online-boutique.local.key\"\n }\n },\n {\n \"type\": \"certificate\",\n \"name\": \"client_cert\",\n \"contents\": {\n \"content\": \"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZBakNDQStxZ0F3SUJBZ0lVYXZ1aFhBOWFLVFJlYmZ2Y1BFU2Z0MjBUQXhzd0RRWUpLb1pJaHZjTkFRRUwKQlFBd1ZqRUxNQWtHQTFVRUJoTUNTVVV4RFRBTEJnTlZCQWdNQkVOdmNtc3hEVEFMQmdOVkJBY01CRU52Y21zeApFVEFQQmdOVkJBb01DRUZqYldVZ1RIUmtNUll3RkFZRFZRUUREQTEwWlhOMExtRmpiV1F1YkdGdU1CNFhEVEkwCk1EUXhOVEUzTURnMU0xb1hEVEkxTURReE5URTNNRGcxTTFvd1dERUxNQWtHQTFVRUJoTUNTVVV4RFRBTEJnTlYKQkFnTUJFTnZjbXN4RFRBTEJnTlZCQWNNQkVOdmNtc3hFVEFQQmdOVkJBb01DRUZqYldVZ1RIUmtNUmd3RmdZRApWUVFEREE5amJHbGxiblF1WVdOdFpTNXNZV0l3Z2dJaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQ0R3QXdnZ0lLCkFvSUNBUURUQ2kydi8rc08rdTJTcFF5ZVBLM3hnb3RyRUlDZGJYMmN4N0xkcnRDbE82a0xTM3IybWpxV1ptWkQKUWkvL0dIZXhYS3NaelBURDUyN0ZMZlREcExIb2h1MldmeUErQy9HN2JycXlNT0dQZ3lVcEI2NWN2THU4V1BNOApPa3lxVFdma0xkRnF2akFGclU5czMxUnljT3BQSlB0cFloRWlhQXZRWDlwRnhjalM2NUJscUFCMjY1YnlncGs2CmpsV1E5NTVWUzlmZlNLU3hpQTRCQXAzMHV3Rm5YRWtMcGRCenI1TkFKeXJqdXhzbHJGVEs4SGxvRmQ2MndzQUMKRjYrRGZmQ2FNLzVockljRkswSVFheHBpaWUyWllKaVFmNXJMeVd6VG1xMVh1QmsyaEhBWDNvQUY2bW9hcnVNOAo5UlhxQmlaNnFWdGFPQXFEK0pRVGNpYmVzekQ2Z2xoSitGM0VFTEJOWVhETmFLbGprQXRxVWFwYStXZEdVUkU4CnZvczA4TSsvOUlhWTdQeGtQNXB6bDhmaS9RaS9ESW9WLzh0UUlydFBIYzJqSTFSRkZoL3BpeDFsR2lyTlRBK0QKbTlURDJKT0hTU3VmdkRkRnV1YjFwMnF5TW5Nd3FFNklHOGpmTEg2TGNxRGFSbmcveVpVUTBqa01LSFYrd1gwegpkZ1RsMDVVWjZtMFpFNUdlK1FRaG5nY0FUemdrSWp3WlJod1JLOEx1Nmtwb2Vnb0dMUkhkTVNqcUV0NkNWc25BCmFLZ0hTbTJROE9MS1lJdlhVN1RpME9DNm5OdU40RDlKdkxGQXdPMUVFU2tCUXFQeThGby8zRVNZWU1FazJ6RzQKc3I0UXJ4Q2xuY2pwbUMrdkRmdHJuR055SVJvditOeS9zd2FSdkcvcm15ZnhEYVdNL3dJREFRQUJvNEhGTUlIQwpNQWtHQTFVZEV3UUNNQUF3RVFZSllJWklBWWI0UWdFQkJBUURBZ1dnTURNR0NXQ0dTQUdHK0VJQkRRUW1GaVJQCmNHVnVVMU5NSUVkbGJtVnlZWFJsWkNCRGJHbGxiblFnUTJWeWRHbG1hV05oZEdVd0hRWURWUjBPQkJZRUZGQmIKdmltZDYxekxLdlA0U2RZRFRWbndYdFVwTUI4R0ExVWRJd1FZTUJhQUZLY29GRHpMVnc1QXBiMzB5UTM0c25MZQpHQ1FWTUE0R0ExVWREd0VCL3dRRUF3SUY0REFkQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQWdZSUt3WUJCUVVICkF3UXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBSmg0cm9kZEVGemJwWk5kSW5zUmdubWVnWVIxSWlzUUxRU0IKcmNydEZxVmtLb3Rsc09EUXBFMThIRjBsbVA4WE9IU0hqYytYUVF5YlFNd1ViZ2RNbnhBZE1WaGFaMXppWElnaQpiUHgwOEY0YXR5MElJY1hyOVpFVnZTd1pheURBZHErb2s5RGpoRjQwYU5iQmFBTXB2NTRCL2U3OUNMSWZ6REo4CnNZaWw3K09abWlOUTJtZUNreVBYdXdhd3hTeVRnNVhWS3Q4VEtKQVJ5aTFJeWRHWkZRMTJGWFJHTE1BSjdaYngKRzlPd1ZvazExenpWNkRQZHFuZU5ER3BQRU5WZ2VmVjI0ZU1JVXUrYzhnSThYTU1GMU9VVWR3MmlEQmU4Q01TQQppc2h2aDFWYVZPNC96czlma2dLV2FXejNwQWprN3pkbWdaUnpXRUVHR0JMekJoQk5FQTg9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"client_key\",\n \"contents\": {\n \"content\": \"LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUpRd0lCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQ1Mwd2dna3BBZ0VBQW9JQ0FRRFRDaTJ2LytzTyt1MlMKcFF5ZVBLM3hnb3RyRUlDZGJYMmN4N0xkcnRDbE82a0xTM3IybWpxV1ptWkRRaS8vR0hleFhLc1p6UFRENTI3RgpMZlREcExIb2h1MldmeUErQy9HN2JycXlNT0dQZ3lVcEI2NWN2THU4V1BNOE9reXFUV2ZrTGRGcXZqQUZyVTlzCjMxUnljT3BQSlB0cFloRWlhQXZRWDlwRnhjalM2NUJscUFCMjY1YnlncGs2amxXUTk1NVZTOWZmU0tTeGlBNEIKQXAzMHV3Rm5YRWtMcGRCenI1TkFKeXJqdXhzbHJGVEs4SGxvRmQ2MndzQUNGNitEZmZDYU0vNWhySWNGSzBJUQpheHBpaWUyWllKaVFmNXJMeVd6VG1xMVh1QmsyaEhBWDNvQUY2bW9hcnVNODlSWHFCaVo2cVZ0YU9BcUQrSlFUCmNpYmVzekQ2Z2xoSitGM0VFTEJOWVhETmFLbGprQXRxVWFwYStXZEdVUkU4dm9zMDhNKy85SWFZN1B4a1A1cHoKbDhmaS9RaS9ESW9WLzh0UUlydFBIYzJqSTFSRkZoL3BpeDFsR2lyTlRBK0RtOVREMkpPSFNTdWZ2RGRGdXViMQpwMnF5TW5Nd3FFNklHOGpmTEg2TGNxRGFSbmcveVpVUTBqa01LSFYrd1gwemRnVGwwNVVaNm0wWkU1R2UrUVFoCm5nY0FUemdrSWp3WlJod1JLOEx1Nmtwb2Vnb0dMUkhkTVNqcUV0NkNWc25BYUtnSFNtMlE4T0xLWUl2WFU3VGkKME9DNm5OdU40RDlKdkxGQXdPMUVFU2tCUXFQeThGby8zRVNZWU1FazJ6RzRzcjRRcnhDbG5janBtQyt2RGZ0cgpuR055SVJvditOeS9zd2FSdkcvcm15ZnhEYVdNL3dJREFRQUJBb0lDQUJzWEZBK2krRmVFbW5rdE9xdHRUL1FsCk5TUlozL05WYjJuRlcyUGRqRHhKcGtUTzV2VS9qYThVd2ZmTVIrdWxCbWhSWkVmOFBweVBMc2J5USszV29iSjAKUk9JQlprVjdYd2ZDWDdEVUJDc0VtS3ZscDlvN3JVQmJqV0w1SmpJNDhYeDI3VFR0NlFMY05uVXhUZDUxanRPagpXYXFJdzNqNU1Oc0tFdDRncWlET2RhQzIvMzJaekZkTHNHNWdnRmRnUElZOUpYUXN3bHk2VnZjdzVpU0RoTnRICkcyYWxYYXdiL2s1Sk9OWTIyY3RDT0kyUnhPUGtPc3lYRkoxYTBRQStGYmxBWExKenVubE5ZNU9iOXEwWTFpa2sKSHpGeXBUcENSdmY2dzY3em00NUYvZVdkS0MzdmpnM29JK29GUS9vMTJUdjhWV3Bhc0ptSmoraUJ5aFRpOGx4YQpMempXaHNrUFZJUGJDYjFDTmIzZHNQSWVWYTVQYmRORGh2bHBQZFV4cXhKRGI4ZUFhemxSQXJVdmtaQnpkTjZtCjVwekljNGtMQnd3Wno5eGg1MzdsQ0tlZ3ZJYmdEMlQvMEM4SVFsWmFIK1M3azlWaVU2Z1RWSGNzU1RsSm52NVYKN3VCMWczVzJZRVloZFJxNlJOUXRZaUFuTktUS2ZYb3d1UUJteWRwVWRYWUljTE5GcER6eHgvRGdQSEhnU0J1dQpQZXVMZzdpemhSSndKMTQ1eW5VTlloQnROVVJaOWlRL1cwWTJOa242UWFBZDNld1pLaVg0S3lZU2k3TTF1MFJWCmFDc1BmZWJrWkRTUnRnQ2Q5N3dGSVYyTVh0UnpXNlpKUUlDWkhHTDVkYkJrNU0xQTI2NnJSYmcvTWZJSE9mdTMKRUZBVjc2aXoyVmNtSDRzblNZUHhBb0lCQVFEc0pNWElhM3ZyRXdRSkh0alRWZE9ONk9rbEExRVN4aWtjSWdSOAo3aFRWQXk3dmtORlpFVUhYczQ1TXlYQzRxTWlvUnFhZHVtOXpQWnFBQ0tQMHRWcXdDMVdOcUFrbDBQc1pZYXcrCmpKNjRDQXA4ZnJ4UDUrOVpWREtiamRWK1ZrK1lrbC9UL0Q1djNFTnZIdkVxN3ZMSE56dE9VSmFWZXNFRERQSW8KaER5SHhjRXQwTHRXTFhoNGNMSDhIQk9Kc0wxYXcxRlhNTk1qdERzazlBMTlJRFlYTHcwaWpIeC81c3hHUGcxSQpmMXRIemhpTlN5NUU5RG9pTmJxVFQvWEEyYVdCdjJ1ZlQybmw2ekticHZHNVo0VGlOUE5ESU5MaUFXOVNNQnJnCkJtaXJFVHU4MnVSa3hnaWZTM01CZ0ZFdXVtaSt2cEhwNzhGaUNOcHpZZUFwTUxjN0FvSUJBUURreVFVT29HVjEKTzZaNXJ4KzhLbVh1S3dmbXNHNmh5cmkrNEw4MzRQakVhbHdkdFhFUmphUG8vSTVhOVFoYjNnLzF5SUdiMzdLSgpPaTFCcGVRZ1owUEVQdFgyRWI0QTNCSTA5SzExWWFybnJGM2d6WS9CVWgveEZoL1YvVEVzTTloZTZ4YlhtRm9WCktvMlY1b2NlNnQzNUJuNHVLL2xkSEJKMHJnUENQdXNKVU9JMEhtUzZkdXNQcHczRFpESkZ5SEU4anptSllwcUsKMnBEMlBBMVZ5aVBBM3MwOU12TWdNSmJXajJLQVBoYk4xQXJnTERaUTFuZ0VwaVFtM3hWdmxIVkMzN0JHM0IzcApWbmtSRE9UZnF1N1BXek40aHZnMDRaNkxBdEZuYzNnMFFxRGcvcXZlS0xuclZwOUJEUlhWb0pZZkNMaVBkajZCCmFiYnFXQ0lYTnMwTkFvSUJBUURFWllrQk9UT2t2UG44UStWOVRzSldJa0hWZ0w2cTZKaEVSNTZIOE5MdW5ta28KNGI3Ylh0anQ5dTRBdXdDKzg5Ris4dE9jRnZTZVdidm5oRWdvTzdTaSthbzcyR2RUUmsyd1BHV3UxL0VoaWI1Kwo4RURhREVJcWZ6WmYzVVNVZ0dCT3VsNXN4anQvZVNlMGdYMStnYUQxUXVCV0wvd3RjaHlZMXVtSC9RTUN3TnY3CnFNQkYyaWQ1cy9Demh2NVE0K2Q0VnoyTlVKUXArN204OENWUHpieHU1N2o2NVBDZXgydFplRDQvNzN3UmFqMU4KTmh2VFNYUVlBNnVhM1VPOUVzYnQ5REFrSFQ0cjlNTHdaWlpnNXRIRCtObmhHS21MUWpvOWxyaWpYWEVyNVhkVAppSkd2cG15Qlg1VFV5TTI4R1ZrSVd5S3I5N1ZVUFp6Qm5jTjdQb01GQW9JQkFDSWRCekFESXAyMFkwSkpwb1c4CkhLN0NvODcyQjhrQUhVUDQ1d3BCOVZYME5nQUlDZkFBR3F5bTIrTWNIajcwZ1pTNGJQcjlBL1lLUXExRE94ekoKeVFUK0NaRkRXLzFzMHhvcVVhTHJDVHk2S3RWV1VWVVdGY1V3ODFaSkJvZjh3d3FFSzBmQ1k4dzhLQmh0NHovcwo3V1F3WDZncXptZmZ3N0M2TWIxSS9HckxNSzlzeU1BMDh4L0dYUHNCZWEyR0VieGg3c1paZVlteXhXS3gyWnN0CkpOK2hXU0VDODlXYzZTRGRDR2J1MngrZHVuRnFwajZ2ZS8zVmVCYUR0UUtLTkdIZ1VMeUFIY1dwS3l3cnJBVGQKeS9ZSE4wbUZkb1VNRDBQVEM3NU5MV005ZkJlUVliZ2lnblpnMkNZdStVNTlQMlVwTzd2SWVkRjZIZGdiaEJuSwpCaEVDZ2dFQkFNZmQ2Zi90RThTQlNFUnd5YW80SThuZkhTZUlMUklvM3pqRE5vWHZ6VHlwbG00a3ovYW9QeEF0CmhPYVNmZU41bFljMXFFUkRxZzRIVGRNTUkyenZPaVFuMHNGTEJFZ0UwT0VIOEZxZVZlZGgycUJucFdXWEhwTW8KREd4TnhpUnVpSDZpOEVMVWFoaU1NQkdQVi9ONjI5MDREbnUyYVVHcHlMTzZxems3SmM5VXlITC90QVNRTFIzagp6NFBhb2xTRE5rNzJSUks0VjIyZUprM2EwYVhjRU5vM1R0OUlTUTliMG5DYVVKbFJsZTA0d2QrOWUyN0FRNUNaCkVWbUtZT1JYcW9VTGNQOEcxRm1VUGhDRkU2aEI3L1hSVWpQdmJFdm5rS05Cdko2UHppT0RMdktRK3I4TzR0WkMKQi9LTDlCdjNmdUkvQlJLeU9WZVU1VnZ5MzUveUFxVT0KLS0tLS1FTkQgUFJJVkFURSBLRVktLS0tLQo=\"\n }\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online_boutique_https_access_log\",\n \"error\": \"/var/log/nginx/online_boutique_https_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://upstream_boutique\",\n \"authentication\": {\n \"server\": [\n {\n \"profile\": \"mTLS authentication profile\"\n }\n ]\n }\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"upstream_boutique\",\n \"origin\": [\n {\n \"server\": \"192.168.2.200:80\"\n }\n ]\n }\n ],\n \"authentication\": {\n \"server\": [\n {\n \"name\": \"mTLS authentication profile\",\n \"type\": \"mtls\",\n \"mtls\": {\n \"certificate\": \"client_cert\",\n \"key\": \"client_key\"\n }\n }\n ]\n }\n }\n }\n}",
- "options": {
- "raw": {
- "language": "json"
+ "name": "Bearer Token, Basic and HTTP header upstream authentication",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
}
- }
+ ],
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v2/www.online-boutique.local.crt\",\n \"authentication\": [\n {\n \"profile\": \"Basic authentication profile\"\n }\n ]\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v2/www.online-boutique.local.key\"\n }\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online_boutique_https_access_log\",\n \"error\": \"/var/log/nginx/online_boutique_https_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://upstream_boutique\",\n \"authentication\": {\n \"server\": [\n {\n \"profile\": \"Bearer token-based authentication profile\"\n }\n ]\n }\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"upstream_boutique\",\n \"origin\": [\n {\n \"server\": \"192.168.2.200:80\"\n }\n ]\n }\n ],\n \"authentication\": {\n \"server\": [\n {\n \"name\": \"Bearer token-based authentication profile\",\n \"type\": \"token\",\n \"token\": {\n \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDI0ODEzNjcsImV4cCI6MTcwMjQ4MTM2OH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIl19.SKA_7MszAypMEtX5NDQ0TcUbVYx_Wt0hrtmuyTmrVKU\",\n \"type\": \"bearer\"\n }\n },\n {\n \"name\": \"Header-based authentication profile\",\n \"type\": \"token\",\n \"token\": {\n \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDI0ODEzNjcsImV4cCI6MTcwMjQ4MTM2OH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIl19.SKA_7MszAypMEtX5NDQ0TcUbVYx_Wt0hrtmuyTmrVKU\",\n \"type\": \"header\",\n \"location\": \"X-AUTH-TOKEN\"\n }\n },\n {\n \"name\": \"Basic authentication profile\",\n \"type\": \"token\",\n \"token\": {\n \"type\": \"basic\",\n \"username\": \"authusername\",\n \"password\": \"YXV0aHBhc3N3b3Jk\"\n }\n }\n ]\n }\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config"
+ ]
+ }
+ },
+ "response": []
},
- "url": {
- "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
- "protocol": "http",
- "host": [
- "{{ncg_host}}"
+ {
+ "name": "mTLS upstream authentication",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var respData = JSON.parse(responseBody);",
+ "",
+ "tests[\"configUid is: \" +respData.configUid] = respData.configUid;",
+ "",
+ "pm.collectionVariables.set('configUid',respData.configUid);"
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
+ }
],
- "port": "{{ncg_port}}",
- "path": [
- "{{ngc_api_version}}",
- "config"
- ]
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nms\": {\n \"url\": \"{{nim_host}}\",\n \"username\": \"{{nim_username}}\",\n \"password\": \"{{nim_password}}\",\n \"instancegroup\": \"{{nim_instancegroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v2/www.online-boutique.local.crt\",\n \"authentication\": [\n {\n \"profile\": \"Basic authentication profile\"\n }\n ]\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/v2/www.online-boutique.local.key\"\n }\n },\n {\n \"type\": \"certificate\",\n \"name\": \"client_cert\",\n \"contents\": {\n \"content\": \"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZBakNDQStxZ0F3SUJBZ0lVYXZ1aFhBOWFLVFJlYmZ2Y1BFU2Z0MjBUQXhzd0RRWUpLb1pJaHZjTkFRRUwKQlFBd1ZqRUxNQWtHQTFVRUJoTUNTVVV4RFRBTEJnTlZCQWdNQkVOdmNtc3hEVEFMQmdOVkJBY01CRU52Y21zeApFVEFQQmdOVkJBb01DRUZqYldVZ1RIUmtNUll3RkFZRFZRUUREQTEwWlhOMExtRmpiV1F1YkdGdU1CNFhEVEkwCk1EUXhOVEUzTURnMU0xb1hEVEkxTURReE5URTNNRGcxTTFvd1dERUxNQWtHQTFVRUJoTUNTVVV4RFRBTEJnTlYKQkFnTUJFTnZjbXN4RFRBTEJnTlZCQWNNQkVOdmNtc3hFVEFQQmdOVkJBb01DRUZqYldVZ1RIUmtNUmd3RmdZRApWUVFEREE5amJHbGxiblF1WVdOdFpTNXNZV0l3Z2dJaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQ0R3QXdnZ0lLCkFvSUNBUURUQ2kydi8rc08rdTJTcFF5ZVBLM3hnb3RyRUlDZGJYMmN4N0xkcnRDbE82a0xTM3IybWpxV1ptWkQKUWkvL0dIZXhYS3NaelBURDUyN0ZMZlREcExIb2h1MldmeUErQy9HN2JycXlNT0dQZ3lVcEI2NWN2THU4V1BNOApPa3lxVFdma0xkRnF2akFGclU5czMxUnljT3BQSlB0cFloRWlhQXZRWDlwRnhjalM2NUJscUFCMjY1YnlncGs2CmpsV1E5NTVWUzlmZlNLU3hpQTRCQXAzMHV3Rm5YRWtMcGRCenI1TkFKeXJqdXhzbHJGVEs4SGxvRmQ2MndzQUMKRjYrRGZmQ2FNLzVockljRkswSVFheHBpaWUyWllKaVFmNXJMeVd6VG1xMVh1QmsyaEhBWDNvQUY2bW9hcnVNOAo5UlhxQmlaNnFWdGFPQXFEK0pRVGNpYmVzekQ2Z2xoSitGM0VFTEJOWVhETmFLbGprQXRxVWFwYStXZEdVUkU4CnZvczA4TSsvOUlhWTdQeGtQNXB6bDhmaS9RaS9ESW9WLzh0UUlydFBIYzJqSTFSRkZoL3BpeDFsR2lyTlRBK0QKbTlURDJKT0hTU3VmdkRkRnV1YjFwMnF5TW5Nd3FFNklHOGpmTEg2TGNxRGFSbmcveVpVUTBqa01LSFYrd1gwegpkZ1RsMDVVWjZtMFpFNUdlK1FRaG5nY0FUemdrSWp3WlJod1JLOEx1Nmtwb2Vnb0dMUkhkTVNqcUV0NkNWc25BCmFLZ0hTbTJROE9MS1lJdlhVN1RpME9DNm5OdU40RDlKdkxGQXdPMUVFU2tCUXFQeThGby8zRVNZWU1FazJ6RzQKc3I0UXJ4Q2xuY2pwbUMrdkRmdHJuR055SVJvditOeS9zd2FSdkcvcm15ZnhEYVdNL3dJREFRQUJvNEhGTUlIQwpNQWtHQTFVZEV3UUNNQUF3RVFZSllJWklBWWI0UWdFQkJBUURBZ1dnTURNR0NXQ0dTQUdHK0VJQkRRUW1GaVJQCmNHVnVVMU5NSUVkbGJtVnlZWFJsWkNCRGJHbGxiblFnUTJWeWRHbG1hV05oZEdVd0hRWURWUjBPQkJZRUZGQmIKdmltZDYxekxLdlA0U2RZRFRWbndYdFVwTUI4R0ExVWRJd1FZTUJhQUZLY29GRHpMVnc1QXBiMzB5UTM0c25MZQpHQ1FWTUE0R0ExVWREd0VCL3dRRUF3SUY0REFkQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQWdZSUt3WUJCUVVICkF3UXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBSmg0cm9kZEVGemJwWk5kSW5zUmdubWVnWVIxSWlzUUxRU0IKcmNydEZxVmtLb3Rsc09EUXBFMThIRjBsbVA4WE9IU0hqYytYUVF5YlFNd1ViZ2RNbnhBZE1WaGFaMXppWElnaQpiUHgwOEY0YXR5MElJY1hyOVpFVnZTd1pheURBZHErb2s5RGpoRjQwYU5iQmFBTXB2NTRCL2U3OUNMSWZ6REo4CnNZaWw3K09abWlOUTJtZUNreVBYdXdhd3hTeVRnNVhWS3Q4VEtKQVJ5aTFJeWRHWkZRMTJGWFJHTE1BSjdaYngKRzlPd1ZvazExenpWNkRQZHFuZU5ER3BQRU5WZ2VmVjI0ZU1JVXUrYzhnSThYTU1GMU9VVWR3MmlEQmU4Q01TQQppc2h2aDFWYVZPNC96czlma2dLV2FXejNwQWprN3pkbWdaUnpXRUVHR0JMekJoQk5FQTg9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"client_key\",\n \"contents\": {\n \"content\": \"LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUpRd0lCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQ1Mwd2dna3BBZ0VBQW9JQ0FRRFRDaTJ2LytzTyt1MlMKcFF5ZVBLM3hnb3RyRUlDZGJYMmN4N0xkcnRDbE82a0xTM3IybWpxV1ptWkRRaS8vR0hleFhLc1p6UFRENTI3RgpMZlREcExIb2h1MldmeUErQy9HN2JycXlNT0dQZ3lVcEI2NWN2THU4V1BNOE9reXFUV2ZrTGRGcXZqQUZyVTlzCjMxUnljT3BQSlB0cFloRWlhQXZRWDlwRnhjalM2NUJscUFCMjY1YnlncGs2amxXUTk1NVZTOWZmU0tTeGlBNEIKQXAzMHV3Rm5YRWtMcGRCenI1TkFKeXJqdXhzbHJGVEs4SGxvRmQ2MndzQUNGNitEZmZDYU0vNWhySWNGSzBJUQpheHBpaWUyWllKaVFmNXJMeVd6VG1xMVh1QmsyaEhBWDNvQUY2bW9hcnVNODlSWHFCaVo2cVZ0YU9BcUQrSlFUCmNpYmVzekQ2Z2xoSitGM0VFTEJOWVhETmFLbGprQXRxVWFwYStXZEdVUkU4dm9zMDhNKy85SWFZN1B4a1A1cHoKbDhmaS9RaS9ESW9WLzh0UUlydFBIYzJqSTFSRkZoL3BpeDFsR2lyTlRBK0RtOVREMkpPSFNTdWZ2RGRGdXViMQpwMnF5TW5Nd3FFNklHOGpmTEg2TGNxRGFSbmcveVpVUTBqa01LSFYrd1gwemRnVGwwNVVaNm0wWkU1R2UrUVFoCm5nY0FUemdrSWp3WlJod1JLOEx1Nmtwb2Vnb0dMUkhkTVNqcUV0NkNWc25BYUtnSFNtMlE4T0xLWUl2WFU3VGkKME9DNm5OdU40RDlKdkxGQXdPMUVFU2tCUXFQeThGby8zRVNZWU1FazJ6RzRzcjRRcnhDbG5janBtQyt2RGZ0cgpuR055SVJvditOeS9zd2FSdkcvcm15ZnhEYVdNL3dJREFRQUJBb0lDQUJzWEZBK2krRmVFbW5rdE9xdHRUL1FsCk5TUlozL05WYjJuRlcyUGRqRHhKcGtUTzV2VS9qYThVd2ZmTVIrdWxCbWhSWkVmOFBweVBMc2J5USszV29iSjAKUk9JQlprVjdYd2ZDWDdEVUJDc0VtS3ZscDlvN3JVQmJqV0w1SmpJNDhYeDI3VFR0NlFMY05uVXhUZDUxanRPagpXYXFJdzNqNU1Oc0tFdDRncWlET2RhQzIvMzJaekZkTHNHNWdnRmRnUElZOUpYUXN3bHk2VnZjdzVpU0RoTnRICkcyYWxYYXdiL2s1Sk9OWTIyY3RDT0kyUnhPUGtPc3lYRkoxYTBRQStGYmxBWExKenVubE5ZNU9iOXEwWTFpa2sKSHpGeXBUcENSdmY2dzY3em00NUYvZVdkS0MzdmpnM29JK29GUS9vMTJUdjhWV3Bhc0ptSmoraUJ5aFRpOGx4YQpMempXaHNrUFZJUGJDYjFDTmIzZHNQSWVWYTVQYmRORGh2bHBQZFV4cXhKRGI4ZUFhemxSQXJVdmtaQnpkTjZtCjVwekljNGtMQnd3Wno5eGg1MzdsQ0tlZ3ZJYmdEMlQvMEM4SVFsWmFIK1M3azlWaVU2Z1RWSGNzU1RsSm52NVYKN3VCMWczVzJZRVloZFJxNlJOUXRZaUFuTktUS2ZYb3d1UUJteWRwVWRYWUljTE5GcER6eHgvRGdQSEhnU0J1dQpQZXVMZzdpemhSSndKMTQ1eW5VTlloQnROVVJaOWlRL1cwWTJOa242UWFBZDNld1pLaVg0S3lZU2k3TTF1MFJWCmFDc1BmZWJrWkRTUnRnQ2Q5N3dGSVYyTVh0UnpXNlpKUUlDWkhHTDVkYkJrNU0xQTI2NnJSYmcvTWZJSE9mdTMKRUZBVjc2aXoyVmNtSDRzblNZUHhBb0lCQVFEc0pNWElhM3ZyRXdRSkh0alRWZE9ONk9rbEExRVN4aWtjSWdSOAo3aFRWQXk3dmtORlpFVUhYczQ1TXlYQzRxTWlvUnFhZHVtOXpQWnFBQ0tQMHRWcXdDMVdOcUFrbDBQc1pZYXcrCmpKNjRDQXA4ZnJ4UDUrOVpWREtiamRWK1ZrK1lrbC9UL0Q1djNFTnZIdkVxN3ZMSE56dE9VSmFWZXNFRERQSW8KaER5SHhjRXQwTHRXTFhoNGNMSDhIQk9Kc0wxYXcxRlhNTk1qdERzazlBMTlJRFlYTHcwaWpIeC81c3hHUGcxSQpmMXRIemhpTlN5NUU5RG9pTmJxVFQvWEEyYVdCdjJ1ZlQybmw2ekticHZHNVo0VGlOUE5ESU5MaUFXOVNNQnJnCkJtaXJFVHU4MnVSa3hnaWZTM01CZ0ZFdXVtaSt2cEhwNzhGaUNOcHpZZUFwTUxjN0FvSUJBUURreVFVT29HVjEKTzZaNXJ4KzhLbVh1S3dmbXNHNmh5cmkrNEw4MzRQakVhbHdkdFhFUmphUG8vSTVhOVFoYjNnLzF5SUdiMzdLSgpPaTFCcGVRZ1owUEVQdFgyRWI0QTNCSTA5SzExWWFybnJGM2d6WS9CVWgveEZoL1YvVEVzTTloZTZ4YlhtRm9WCktvMlY1b2NlNnQzNUJuNHVLL2xkSEJKMHJnUENQdXNKVU9JMEhtUzZkdXNQcHczRFpESkZ5SEU4anptSllwcUsKMnBEMlBBMVZ5aVBBM3MwOU12TWdNSmJXajJLQVBoYk4xQXJnTERaUTFuZ0VwaVFtM3hWdmxIVkMzN0JHM0IzcApWbmtSRE9UZnF1N1BXek40aHZnMDRaNkxBdEZuYzNnMFFxRGcvcXZlS0xuclZwOUJEUlhWb0pZZkNMaVBkajZCCmFiYnFXQ0lYTnMwTkFvSUJBUURFWllrQk9UT2t2UG44UStWOVRzSldJa0hWZ0w2cTZKaEVSNTZIOE5MdW5ta28KNGI3Ylh0anQ5dTRBdXdDKzg5Ris4dE9jRnZTZVdidm5oRWdvTzdTaSthbzcyR2RUUmsyd1BHV3UxL0VoaWI1Kwo4RURhREVJcWZ6WmYzVVNVZ0dCT3VsNXN4anQvZVNlMGdYMStnYUQxUXVCV0wvd3RjaHlZMXVtSC9RTUN3TnY3CnFNQkYyaWQ1cy9Demh2NVE0K2Q0VnoyTlVKUXArN204OENWUHpieHU1N2o2NVBDZXgydFplRDQvNzN3UmFqMU4KTmh2VFNYUVlBNnVhM1VPOUVzYnQ5REFrSFQ0cjlNTHdaWlpnNXRIRCtObmhHS21MUWpvOWxyaWpYWEVyNVhkVAppSkd2cG15Qlg1VFV5TTI4R1ZrSVd5S3I5N1ZVUFp6Qm5jTjdQb01GQW9JQkFDSWRCekFESXAyMFkwSkpwb1c4CkhLN0NvODcyQjhrQUhVUDQ1d3BCOVZYME5nQUlDZkFBR3F5bTIrTWNIajcwZ1pTNGJQcjlBL1lLUXExRE94ekoKeVFUK0NaRkRXLzFzMHhvcVVhTHJDVHk2S3RWV1VWVVdGY1V3ODFaSkJvZjh3d3FFSzBmQ1k4dzhLQmh0NHovcwo3V1F3WDZncXptZmZ3N0M2TWIxSS9HckxNSzlzeU1BMDh4L0dYUHNCZWEyR0VieGg3c1paZVlteXhXS3gyWnN0CkpOK2hXU0VDODlXYzZTRGRDR2J1MngrZHVuRnFwajZ2ZS8zVmVCYUR0UUtLTkdIZ1VMeUFIY1dwS3l3cnJBVGQKeS9ZSE4wbUZkb1VNRDBQVEM3NU5MV005ZkJlUVliZ2lnblpnMkNZdStVNTlQMlVwTzd2SWVkRjZIZGdiaEJuSwpCaEVDZ2dFQkFNZmQ2Zi90RThTQlNFUnd5YW80SThuZkhTZUlMUklvM3pqRE5vWHZ6VHlwbG00a3ovYW9QeEF0CmhPYVNmZU41bFljMXFFUkRxZzRIVGRNTUkyenZPaVFuMHNGTEJFZ0UwT0VIOEZxZVZlZGgycUJucFdXWEhwTW8KREd4TnhpUnVpSDZpOEVMVWFoaU1NQkdQVi9ONjI5MDREbnUyYVVHcHlMTzZxems3SmM5VXlITC90QVNRTFIzagp6NFBhb2xTRE5rNzJSUks0VjIyZUprM2EwYVhjRU5vM1R0OUlTUTliMG5DYVVKbFJsZTA0d2QrOWUyN0FRNUNaCkVWbUtZT1JYcW9VTGNQOEcxRm1VUGhDRkU2aEI3L1hSVWpQdmJFdm5rS05Cdko2UHppT0RMdktRK3I4TzR0WkMKQi9LTDlCdjNmdUkvQlJLeU9WZVU1VnZ5MzUveUFxVT0KLS0tLS1FTkQgUFJJVkFURSBLRVktLS0tLQo=\"\n }\n }\n ]\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"www.online-boutique.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:443\",\n \"http2\": true,\n \"tls\": {\n \"certificate\": \"test_cert\",\n \"key\": \"test_key\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": \"/var/log/nginx/online_boutique_https_access_log\",\n \"error\": \"/var/log/nginx/online_boutique_https_error_log\"\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://upstream_boutique\",\n \"authentication\": {\n \"server\": [\n {\n \"profile\": \"mTLS authentication profile\"\n }\n ]\n }\n }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"upstream_boutique\",\n \"origin\": [\n {\n \"server\": \"192.168.2.200:80\"\n }\n ]\n }\n ],\n \"authentication\": {\n \"server\": [\n {\n \"name\": \"mTLS authentication profile\",\n \"type\": \"mtls\",\n \"mtls\": {\n \"certificate\": \"client_cert\",\n \"key\": \"client_key\"\n }\n }\n ]\n }\n }\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config",
+ "protocol": "http",
+ "host": [
+ "{{ncg_host}}"
+ ],
+ "port": "{{ncg_port}}",
+ "path": [
+ "{{ngc_api_version}}",
+ "config"
+ ]
+ }
+ },
+ "response": []
}
- },
- "response": []
+ ]
}
]
}
]
}
- ]
+ ],
+ "description": "[https://github.com/f5devcentral/NGINX-Declarative-API/blob/main/USAGE-v5.0.md](https://github.com/f5devcentral/NGINX-Declarative-API/blob/main/USAGE-v4.2.md)"
}
],
"event": [
@@ -4501,7 +4605,27 @@
},
{
"key": "ngc_api_version",
- "value": "v4.2",
+ "value": "v5.0",
+ "type": "string"
+ },
+ {
+ "key": "nginxone_url",
+ "value": "https://tenant.volterra.us",
+ "type": "string"
+ },
+ {
+ "key": "nginxone_token",
+ "value": "APIToken TOKEN",
+ "type": "string"
+ },
+ {
+ "key": "nginxone_namespace",
+ "value": "default",
+ "type": "string"
+ },
+ {
+ "key": "nginxone_clustername",
+ "value": "declarativeAPITest",
"type": "string"
}
]
diff --git a/contrib/postman/README.md b/contrib/postman/README.md
index 70d1055..20a51bf 100644
--- a/contrib/postman/README.md
+++ b/contrib/postman/README.md
@@ -2,7 +2,7 @@
This collection contains:
-API v4.2 - Latest
+API v5.0 - Latest
- `Configuration generation` - Declaration examples with output to plaintext, JSON, Kubernetes ConfigMap, HTTP POST
- `Declarative automation examples` - Several examples and use cases
- `API Gateway` - Sample API gateway requests for Swagger and OpenAPI schemas import
@@ -18,16 +18,20 @@ API v4.2 - Latest
- `NGINX Javascript` - NGINX configuration with `njs` javascript
- `Server-side and source of truth authentication` - Requests for authentication towards upstreams and source of truth
-API v4.1
+API v4.2
- `Configuration generation` - Declaration examples with output to plaintext, JSON, Kubernetes ConfigMap, HTTP POST
- `Declarative automation examples` - Several examples and use cases
- `API Gateway` - Sample API gateway requests for Swagger and OpenAPI schemas import
- `CRUD automation` - Sample requests for CRUD-based automation
- `GitOps autosync` - GitOps automation demo
- `Housekeeping - common endpoints` - Miscellaneous general purpose requests
+ - `HTTP Headers Manipulation` - `server` and `location` level HTTP headers management
+ - `HTTP Server` - TLS offload with NGINX App Protect WAF
- `JWT Client Authentication` - JWT-based client authentication for HTTP
+ - `JWT Client Authentication and Authorization` - JWT-based client authentication and authorization for HTTP
- `mTLS Client Authentication` - mTLS client authentication for HTTP
- `NGINX App Protect WAF` - Sample requests for declarative configuration lifecycle management
+ - `NGINX Javascript` - NGINX configuration with `njs` javascript
- `Server-side and source of truth authentication` - Requests for authentication towards upstreams and source of truth
---
diff --git a/etc/config.toml b/etc/config.toml
index 659ec8e..07662dd 100644
--- a/etc/config.toml
+++ b/etc/config.toml
@@ -3,7 +3,7 @@
# Main variables
[main]
banner = "NGINX Declarative API"
-version = "4.2"
+version = "5.0"
url = "https://github.com/f5devcentral/NGINX-Declarative-API"
# Templates
@@ -40,6 +40,7 @@ uri = "/v1/devportal"
# Staged configuration for NGINX Instance Manager
[nms]
+nginx_conf = '/etc/nginx/nginx.conf'
config_dir = '/etc/nginx'
certs_dir = '/etc/nginx/ssl'
apigw_dir = '/etc/nginx/apigateway'
diff --git a/src/V4_1_CreateConfig.py b/src/V5_0_CreateConfig.py
similarity index 52%
rename from src/V4_1_CreateConfig.py
rename to src/V5_0_CreateConfig.py
index eb4856f..64746c7 100644
--- a/src/V4_1_CreateConfig.py
+++ b/src/V5_0_CreateConfig.py
@@ -7,6 +7,7 @@
import pickle
import time
import uuid
+import hashlib
from datetime import datetime
from urllib.parse import urlparse
@@ -17,31 +18,29 @@
from pydantic import ValidationError
from requests.packages.urllib3.exceptions import InsecureRequestWarning
-import v4_1.APIGateway
-import v4_1.DevPortal
-import v4_1.DeclarationPatcher
-import v4_1.GitOps
-import v4_1.MiscUtils
+import v5_0.APIGateway
+import v5_0.DevPortal
+import v5_0.DeclarationPatcher
+import v5_0.GitOps
+import v5_0.MiscUtils
+import v5_0.NMSOutput
+import v5_0.NGINXOneOutput
# NGINX App Protect helper functions
-import v4_1.NAPUtils
-import v4_1.NIMUtils
+import v5_0.NAPUtils
+import v5_0.NIMUtils
# NGINX Declarative API modules
from NcgConfig import NcgConfig
from NcgRedis import NcgRedis
# pydantic models
-from V4_1_NginxConfigDeclaration import *
+from V5_0_NginxConfigDeclaration import *
# Tolerates self-signed TLS certificates
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
-def getuniqueid():
- return uuid.uuid4()
-
-
def configautosync(configUid):
print("Autosyncing configuid [" + configUid + "]")
@@ -62,10 +61,10 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn
# Building NGINX configuration for the given declaration
# NGINX configuration files for staged config
- configFiles = {'files': [], 'rootDir': NcgConfig.config['nms']['config_dir']}
+ configFiles = {'files': []}
# NGINX auxiliary files for staged config
- auxFiles = {'files': [], 'rootDir': NcgConfig.config['nms']['config_dir']}
+ auxFiles = {'files': []}
try:
# Pydantic JSON validation
@@ -78,11 +77,11 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn
j2_env = Environment(loader=FileSystemLoader(NcgConfig.config['templates']['root_dir'] + '/' + apiversion),
trim_blocks=True, extensions=["jinja2_base64_filters.Base64Filters"])
- j2_env.filters['regex_replace'] = v4_1.MiscUtils.regex_replace
+ j2_env.filters['regex_replace'] = v5_0.MiscUtils.regex_replace
if 'http' in d['declaration']:
if 'snippet' in d['declaration']['http']:
- status, snippet = v4_1.GitOps.getObjectFromRepo(object = d['declaration']['http']['snippet'], authProfiles = d['declaration']['http']['authentication'])
+ status, snippet = v5_0.GitOps.getObjectFromRepo(object = d['declaration']['http']['snippet'], authProfiles = d['declaration']['http']['authentication'])
if status != 200:
return {"status_code": 422, "message": {"status_code": status, "message": snippet}}
@@ -99,7 +98,7 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn
upstream = http['upstreams'][i]
if upstream['snippet']:
- status, snippet = v4_1.GitOps.getObjectFromRepo(object = upstream['snippet'], authProfiles = d['declaration']['http']['authentication'])
+ status, snippet = v5_0.GitOps.getObjectFromRepo(object = upstream['snippet'], authProfiles = d['declaration']['http']['authentication'])
if status != 200:
return {"status_code": 422, "message": {"status_code": status, "message": snippet}}
@@ -112,7 +111,7 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn
all_ratelimits = []
http = d['declaration']['http']
- d_rate_limit = v4_1.MiscUtils.getDictKey(d, 'declaration.http.rate_limit')
+ d_rate_limit = v5_0.MiscUtils.getDictKey(d, 'declaration.http.rate_limit')
if d_rate_limit is not None:
for i in range(len(d_rate_limit)):
all_ratelimits.append(d_rate_limit[i]['name'])
@@ -123,7 +122,7 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn
all_auth_client_profiles = []
all_auth_server_profiles = []
- d_auth_profiles = v4_1.MiscUtils.getDictKey(d, 'declaration.http.authentication')
+ d_auth_profiles = v5_0.MiscUtils.getDictKey(d, 'declaration.http.authentication')
if d_auth_profiles is not None:
if 'client' in d_auth_profiles:
# Render all client authentication profiles
@@ -160,6 +159,21 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn
all_auth_client_profiles.append(auth_profile['name'])
auxFiles['files'].append(authProfileConfigFile)
+ case 'mtls':
+ # Add the rendered authentication configuration snippet as a config file in the staged configuration - mTLS template
+ templateName = NcgConfig.config['templates']['auth_client_root'] + "/mtls.tmpl"
+ renderedClientAuthProfile = j2_env.get_template(templateName).render(
+ authprofile=auth_profile, ncgconfig=NcgConfig.config)
+
+ b64renderedClientAuthProfile = base64.b64encode(
+ bytes(renderedClientAuthProfile, 'utf-8')).decode('utf-8')
+ configFileName = NcgConfig.config['nms']['auth_client_dir'] + '/' + auth_profile[
+ 'name'].replace(' ', '_') + ".conf"
+ authProfileConfigFile = {'contents': b64renderedClientAuthProfile,
+ 'name': configFileName}
+
+ all_auth_client_profiles.append(auth_profile['name'])
+ auxFiles['files'].append(authProfileConfigFile)
if 'server' in d_auth_profiles:
# Render all server authentication profiles
@@ -170,7 +184,7 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn
match auth_profile['type']:
case 'token':
- # Add the rendered authentication configuration snippet as a config file in the staged configuration - jwt template
+ # Add the rendered authentication configuration snippet as a config file in the staged configuration - token template
templateName = NcgConfig.config['templates']['auth_server_root']+"/token.tmpl"
renderedServerAuthProfile = j2_env.get_template(templateName).render(
authprofile=auth_profile, ncgconfig=NcgConfig.config)
@@ -183,16 +197,142 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn
all_auth_server_profiles.append(auth_profile['name'])
auxFiles['files'].append(authProfileConfigFile)
+ case 'mtls':
+ # Add the rendered authentication configuration snippet as a config file in the staged configuration - mTLS template
+ templateName = NcgConfig.config['templates']['auth_server_root'] + "/mtls.tmpl"
+ renderedServerAuthProfile = j2_env.get_template(templateName).render(
+ authprofile=auth_profile, ncgconfig=NcgConfig.config)
+
+ b64renderedServerAuthProfile = base64.b64encode(
+ bytes(renderedServerAuthProfile, 'utf-8')).decode('utf-8')
+ configFileName = NcgConfig.config['nms']['auth_server_dir'] + '/' + auth_profile[
+ 'name'].replace(' ', '_') + ".conf"
+ authProfileConfigFile = {'contents': b64renderedServerAuthProfile,
+ 'name': configFileName}
+
+ all_auth_server_profiles.append(auth_profile['name'])
+ auxFiles['files'].append(authProfileConfigFile)
+
+
+ # Check authorization profiles validity and creates authorization config files
+
+ # List of all authorization client profile names
+ all_authz_client_profiles = []
+
+ d_authz_profiles = v5_0.MiscUtils.getDictKey(d, 'declaration.http.authorization')
+ if d_authz_profiles is not None:
+ # Render all client authorization profiles
+
+ for i in range(len(d_authz_profiles)):
+ authz_profile = d_authz_profiles[i]
+
+ match authz_profile['type']:
+ case 'jwt':
+ # Add the rendered authorization configuration snippet as a config file in the staged configuration - jwt authZ maps template
+ templateName = NcgConfig.config['templates']['authz_client_root']+"/jwt-authz-map.tmpl"
+ renderedClientAuthZProfile = j2_env.get_template(templateName).render(
+ authprofile=authz_profile, ncgconfig=NcgConfig.config)
+
+ b64renderedClientAuthProfile = base64.b64encode(bytes(renderedClientAuthZProfile, 'utf-8')).decode('utf-8')
+ configFileName = NcgConfig.config['nms']['authz_client_dir'] + '/'+authz_profile['name'].replace(' ','_')+".maps.conf"
+ authProfileConfigFile = {'contents': b64renderedClientAuthProfile,
+ 'name': configFileName }
+
+ all_authz_client_profiles.append(authz_profile['name'])
+ auxFiles['files'].append(authProfileConfigFile)
+
+ # Add the rendered authorization configuration snippet as a config file in the staged configuration - jwt template
+ templateName = NcgConfig.config['templates']['authz_client_root'] + "/jwt.tmpl"
+ renderedClientAuthZProfile = j2_env.get_template(templateName).render(
+ authprofile=authz_profile, ncgconfig=NcgConfig.config)
+
+ b64renderedClientAuthProfile = base64.b64encode(bytes(renderedClientAuthZProfile, 'utf-8')).decode(
+ 'utf-8')
+ configFileName = NcgConfig.config['nms']['authz_client_dir'] + '/' + authz_profile['name'].replace(' ',
+ '_') + ".conf"
+ authProfileConfigFile = {'contents': b64renderedClientAuthProfile,
+ 'name': configFileName}
+
+ all_authz_client_profiles.append(authz_profile['name'])
+ auxFiles['files'].append(authProfileConfigFile)
+
+ # NGINX Javascript profiles
+ all_njs_profiles = []
+ d_njs_files = v5_0.MiscUtils.getDictKey(d, 'declaration.http.njs_profiles')
+ if d_njs_files is not None:
+ for i in range(len(d_njs_files)):
+ njs_file = d_njs_files[i]
+ njs_filename = njs_file['name'].replace(' ','_')
+
+ status, content = v5_0.GitOps.getObjectFromRepo(object=njs_file['file'],
+ authProfiles=d['declaration']['http'][
+ 'authentication'])
+
+ if status != 200:
+ return {"status_code": 422, "message": {"status_code": status, "message": content}}
+
+ njsAuxFile = {'contents': content['content'],
+ 'name': NcgConfig.config['nms']['njs_dir'] + '/' + njs_filename + '.js'}
+ auxFiles['files'].append(njsAuxFile)
+ all_njs_profiles.append(njs_filename)
+
+ # HTTP level Javascript hooks
+ d_http_njs_hooks = v5_0.MiscUtils.getDictKey(d, 'declaration.http.njs')
+ if d_http_njs_hooks is not None:
+ for i in range(len(d_http_njs_hooks)):
+ if d_http_njs_hooks[i]['profile'] not in all_njs_profiles:
+ return {"status_code": 422,
+ "message": {"status_code": status, "message":
+ {"code": status,
+ "content": f"invalid njs profile [{d_http_njs_hooks[i]['profile']}] in HTTP declaration, must be one of {all_njs_profiles}"}}}
+
# Parse HTTP servers
- d_servers = v4_1.MiscUtils.getDictKey(d, 'declaration.http.servers')
+ d_servers = v5_0.MiscUtils.getDictKey(d, 'declaration.http.servers')
if d_servers is not None:
- apiGatewaySnippet = ''
-
for server in d_servers:
serverSnippet = ''
+ # Server level Javascript hooks
+ if server['njs']:
+ for i in range(len(server['njs'])):
+ if server['njs'][i]['profile'] not in all_njs_profiles:
+ return {"status_code": 422,
+ "message": {"status_code": status, "message":
+ {"code": status,
+ "content": f"invalid njs profile [{server['njs'][i]['profile']}] in server [{server['name']}], must be one of {all_njs_profiles}"}}}
+
+ # Server client authentication name validity check
+ if 'authentication' in server and server['authentication']:
+ serverAuthClientProfiles = server['authentication']['client']
+
+ for authClientProfile in serverAuthClientProfiles:
+ if authClientProfile['profile'] not in all_auth_client_profiles:
+ return {"status_code": 422,
+ "message": {"status_code": status, "message":
+ {"code": status,
+ "content": f"invalid client authentication profile [{authClientProfile['profile']}] in server [{server['name']}] must be one of {all_auth_client_profiles}"}}}
+
+ # Location client authorization name validity check
+ if 'authorization' in server and server['authorization']:
+ if server['authorization']['profile'] and server['authorization']['profile'] not in all_authz_client_profiles:
+ return {"status_code": 422,
+ "message": {"status_code": status, "message":
+ {"code": status,
+ "content": f"invalid client authorization profile [{server['authorization']['profile']}] in server [{server['name']}] must be one of {all_authz_client_profiles}"}}}
+
+ # mTLS client authentication name validity check
+ if 'authentication' in server['listen']['tls']:
+ if 'client' in server['listen']['tls']['authentication']:
+ tlsAuthProfiles = server['listen']['tls']['authentication']['client']
+ for mtlsClientProfile in tlsAuthProfiles:
+ if mtlsClientProfile['profile'] not in all_auth_client_profiles:
+ return {"status_code": 422,
+ "message": {"status_code": status, "message":
+ {"code": status,
+ "content": f"invalid client authentication profile [{mtlsClientProfile['profile']}] in server [{server['name']}] must be one of {all_auth_client_profiles}"}}}
+
if server['snippet']:
- status, serverSnippet = v4_1.GitOps.getObjectFromRepo(object = server['snippet'], authProfiles = d['declaration']['http']['authentication'], base64Encode = False)
+ status, serverSnippet = v5_0.GitOps.getObjectFromRepo(object = server['snippet'], authProfiles = d['declaration']['http']['authentication'], base64Encode = False)
if status != 200:
return {"status_code": 422, "message": {"status_code": status, "message": serverSnippet}}
@@ -200,8 +340,18 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn
serverSnippet = serverSnippet['content']
for loc in server['locations']:
+
+ # Location level Javascript hooks
+ if loc['njs']:
+ for i in range(len(loc['njs'])):
+ if loc['njs'][i]['profile'] not in all_njs_profiles:
+ return {"status_code": 422,
+ "message": {"status_code": status, "message":
+ {"code": status,
+ "content": f"invalid njs profile [{loc['njs'][i]['profile']}] in location [{loc['uri']}], must be one of {all_njs_profiles}"}}}
+
if loc['snippet']:
- status, snippet = v4_1.GitOps.getObjectFromRepo(object = loc['snippet'], authProfiles = d['declaration']['http']['authentication'])
+ status, snippet = v5_0.GitOps.getObjectFromRepo(object = loc['snippet'], authProfiles = d['declaration']['http']['authentication'])
if status != 200:
return {"status_code": 422, "message": {"status_code": status, "message": snippet}}
@@ -222,7 +372,14 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn
if authClientProfile['profile'] not in all_auth_client_profiles:
return {"status_code": 422,
"message": {"status_code": status, "message":
- {"code": status, "content": f"invalid client authentication profile [{authClientProfile['profile']}] in location [{loc['uri']}]"}}}
+ {"code": status, "content": f"invalid client authentication profile [{authClientProfile['profile']}] in location [{loc['uri']}] must be one of {all_auth_client_profiles}"}}}
+
+ # Location client authorization name validity check
+ if 'authorization' in loc and loc['authorization']:
+ if loc['authorization']['profile'] and loc['authorization']['profile'] not in all_authz_client_profiles:
+ return {"status_code": 422,
+ "message": {"status_code": status, "message":
+ {"code": status, "content": f"invalid client authorization profile [{loc['authorization']['profile']}] in location [{loc['uri']}] must be one of {all_authz_client_profiles}"}}}
# Location server authentication name validity check
if 'authentication' in loc and loc['authentication']:
@@ -243,19 +400,27 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn
{"code": status,
"content": f"invalid server authentication profile [{openApiAuthProfile[0]['profile']}] for OpenAPI schema [{loc['apigateway']['openapi_schema']['content']}]"}}}
- status, apiGatewayConfigDeclaration = v4_1.APIGateway.createAPIGateway(locationDeclaration = loc, authProfiles = d['declaration']['http']['authentication'])
- else:
- apiGatewayConfigDeclaration = ''
+ status, apiGatewayConfigDeclaration = v5_0.APIGateway.createAPIGateway(locationDeclaration = loc, authProfiles = d['declaration']['http']['authentication'])
+
+ # API Gateway configuration template rendering
+ if apiGatewayConfigDeclaration:
+ apiGatewaySnippet = j2_env.get_template(NcgConfig.config['templates']['apigwconf']).render(
+ declaration=apiGatewayConfigDeclaration, ncgconfig=NcgConfig.config)
+ apiGatewaySnippetb64 = base64.b64encode(bytes(apiGatewaySnippet, 'utf-8')).decode('utf-8')
+
+ newAuxFile = {'contents': apiGatewaySnippetb64, 'name': NcgConfig.config['nms']['apigw_dir'] +
+ loc['uri'] + ".conf" }
+ auxFiles['files'].append(newAuxFile)
# API Gateway Developer portal provisioning
if loc['apigateway'] and loc['apigateway']['developer_portal'] and 'enabled' in loc['apigateway']['developer_portal'] and loc['apigateway']['developer_portal']['enabled'] == True:
- status, devPortalHTML = v4_1.DevPortal.createDevPortal(locationDeclaration = loc, authProfiles = d['declaration']['http']['authentication'])
+ status, devPortalHTML = v5_0.DevPortal.createDevPortal(locationDeclaration = loc, authProfiles = d['declaration']['http']['authentication'])
if status != 200:
- return {"status_code": 400,
+ return {"status_code": 412,
"message": {"status_code": status, "message":
- {"code": status, "content": f"Developer Portal creation failed for {loc['apigateway']['openapi_schema']['content']}"}}}
+ {"code": status, "content": f"Developer Portal creation failed for {loc['uri']}"}}}
### Add optional API Developer portal HTML files
# devPortalHTML
@@ -276,28 +441,23 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn
"content":
f"invalid rate_limit profile [{loc['rate_limit']['profile']}]"}}}
- # API Gateway configuration template rendering
- apiGatewaySnippet += j2_env.get_template(NcgConfig.config['templates']['apigwconf']).render(
- declaration=apiGatewayConfigDeclaration, ncgconfig=NcgConfig.config)\
- if apiGatewayConfigDeclaration else ''
-
- server['snippet']['content'] = base64.b64encode(bytes(serverSnippet + apiGatewaySnippet, 'utf-8')).decode('utf-8')
+ server['snippet']['content'] = base64.b64encode(bytes(serverSnippet, 'utf-8')).decode('utf-8')
if 'layer4' in d['declaration']:
# Check Layer4/stream upstreams validity
all_upstreams = []
- d_upstreams = v4_1.MiscUtils.getDictKey(d, 'declaration.layer4.upstreams')
+ d_upstreams = v5_0.MiscUtils.getDictKey(d, 'declaration.layer4.upstreams')
if d_upstreams is not None:
for i in range(len(d_upstreams)):
all_upstreams.append(d_upstreams[i]['name'])
- d_servers = v4_1.MiscUtils.getDictKey(d, 'declaration.layer4.servers')
+ d_servers = v5_0.MiscUtils.getDictKey(d, 'declaration.layer4.servers')
if d_servers is not None:
for server in d_servers:
if server['snippet']:
- status, snippet = v4_1.GitOps.getObjectFromRepo(object = server['snippet'], authProfiles = d['declaration']['http']['authentication'])
+ status, snippet = v5_0.GitOps.getObjectFromRepo(object = server['snippet'], authProfiles = d['declaration']['http']['authentication'])
if status != 200:
return {"status_code": 422, "message": {"status_code": status, "message": snippet}}
@@ -378,319 +538,37 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn
return Response(content=cmHttp + '\n---\n' + cmStream, headers={'Content-Type': 'application/x-yaml'})
elif decltype.lower() == 'nms':
- # NGINX Instance Manager Staged Configuration publish
+ # Output to NGINX Instance Manager
- nmsUsername = v4_1.MiscUtils.getDictKey(d, 'output.nms.username')
- nmsPassword = v4_1.MiscUtils.getDictKey(d, 'output.nms.password')
- nmsInstanceGroup = v4_1.MiscUtils.getDictKey(d, 'output.nms.instancegroup')
- nmsSynctime = v4_1.MiscUtils.getDictKey(d, 'output.nms.synctime')
+ # NGINX configuration files for staged config
+ configFiles['rootDir'] = NcgConfig.config['nms']['config_dir']
- nmsUrlFromJson = v4_1.MiscUtils.getDictKey(d, 'output.nms.url')
- urlCheck = urlparse(nmsUrlFromJson)
+ # NGINX auxiliary files for staged config
+ auxFiles['rootDir'] = NcgConfig.config['nms']['config_dir']
- if urlCheck.scheme not in ['http', 'https'] or urlCheck.scheme == "" or urlCheck.netloc == "":
- return {"status_code": 400,
- "message": {"status_code": 400, "message": {"code": 400,
- "content": f"invalid NGINX Management Suite URL {nmsUrlFromJson}"}},
- "headers": {'Content-Type': 'application/json'}}
+ return v5_0.NMSOutput.NMSOutput(d = d, declaration = declaration, apiversion = apiversion,
+ b64HttpConf = b64HttpConf, b64StreamConf = b64StreamConf,
+ configFiles = configFiles,
+ auxFiles = auxFiles,
+ runfromautosync = runfromautosync, configUid = configUid )
- nmsUrl = f"{urlCheck.scheme}://{urlCheck.netloc}"
+ elif decltype.lower() == 'nginxone':
+ # Output to NGINX One SaaS Console
- if nmsSynctime < 0:
- return {"status_code": 400,
- "message": {"status_code": 400, "message": {"code": 400, "content": "synctime must be >= 0"}},
- "headers": {'Content-Type': 'application/json'}}
+ # NGINX configuration files for staged config
+ configFiles['name'] = NcgConfig.config['nms']['config_dir']
- # Fetch NGINX App Protect WAF policies from source of truth if needed
- d_policies = v4_1.MiscUtils.getDictKey(d, 'output.nms.policies')
- if d_policies is not None:
- for policy in d_policies:
- if 'versions' in policy:
- for policyVersion in policy['versions']:
- status, content = v4_1.GitOps.getObjectFromRepo(object = policyVersion['contents'], authProfiles = d['declaration']['http']['authentication'])
+ # NGINX auxiliary files for staged config
+ # TODO
+ # auxFiles['name'] = NcgConfig.config['nms']['config_dir']
- if status != 200:
- return {"status_code": 422, "message": {"status_code": status, "message": content}}
-
- policyVersion['contents'] = content
-
- # Check TLS items validity
- all_tls = {'certificate': {}, 'key': {}}
+ #return v5_0.NGINXOneOutput.NGINXOneOutput(d = d, declaration = declaration, apiversion = apiversion,
+ # b64HttpConf = b64HttpConf, b64StreamConf = b64StreamConf,
+ # configFiles = configFiles,
+ # auxFiles = auxFiles,
+ # runfromautosync = runfromautosync, configUid = configUid )
- d_certs = v4_1.MiscUtils.getDictKey(d, 'output.nms.certificates')
- if d_certs is not None:
- for i in range(len(d_certs)):
- if d_certs[i]['name']:
- all_tls[d_certs[i]['type']][d_certs[i]['name']] = True
-
- d_servers = v4_1.MiscUtils.getDictKey(d, 'declaration.http.servers')
- if d_servers is not None:
- for server in d_servers:
- if server['listen'] is not None:
- if 'tls' in server['listen']:
- cert_name = v4_1.MiscUtils.getDictKey(server, 'listen.tls.certificate')
- if cert_name and cert_name not in all_tls['certificate']:
- return {"status_code": 422,
- "message": {
- "status_code": 422,
- "message": {"code": 422,
- "content": "invalid TLS certificate " +
- cert_name + " for server" + str(
- server['names'])}
- }}
-
- cert_key = v4_1.MiscUtils.getDictKey(server, 'listen.tls.key')
- if cert_key and cert_key not in all_tls['key']:
- return {"status_code": 422,
- "message": {
- "status_code": 422,
- "message": {"code": 422,
- "content": "invalid TLS key " + cert_key + " for server" + str(
- server['names'])}
- }}
-
- trusted_cert_name = v4_1.MiscUtils.getDictKey(server, 'listen.tls.trusted_ca_certificates')
- if trusted_cert_name and trusted_cert_name not in all_tls['certificate']:
- return {"status_code": 422,
- "message": {
- "status_code": 422,
- "message": {"code": 422,
- "content": "invalid trusted CA certificate " +
- trusted_cert_name + " for server" + str(server['names'])}
- }}
-
- if v4_1.MiscUtils.getDictKey(server, 'listen.tls.mtls.enabled') in ['optional_no_ca'] \
- and 'ocsp' in server['listen']['tls']:
- return {"status_code": 422,
- "message": {
- "status_code": 422,
- "message": {"code": 422,
- "content": "OCSP is incompatible with 'optional_no_ca' client "
- "mTLS verification for server" + str(
- server['names'])}
- }}
-
- client_cert_name = v4_1.MiscUtils.getDictKey(server, 'listen.tls.mtls.client_certificates')
- if client_cert_name and client_cert_name not in all_tls['certificate']:
- return {"status_code": 422,
- "message": {
- "status_code": 422,
- "message": {"code": 422,
- "content": f"invalid mTLS client certificates [{client_cert_name}] for server {str(server['names'])}"}
- }}
-
- # Add optional certificates specified under output.nms.certificates
- extensions_map = {'certificate': '.crt', 'key': '.key'}
-
- d_certificates = v4_1.MiscUtils.getDictKey(d, 'output.nms.certificates')
- if d_certificates is not None:
- for c in d_certificates:
- status, certContent = v4_1.GitOps.getObjectFromRepo(object = c['contents'], authProfiles = d['declaration']['http']['authentication'])
-
- if status != 200:
- return {"status_code": 422,
- "message": {"status_code": status, "message": {"code": status, "content": certContent}}}
-
- newAuxFile = {'contents': certContent['content'], 'name': NcgConfig.config['nms']['certs_dir'] +
- '/' + c['name'] + extensions_map[c['type']]}
- auxFiles['files'].append(newAuxFile)
-
- ### / Add optional certificates specified under output.nms.certificates
-
- # NGINX main configuration file through template
- j2_env = Environment(loader=FileSystemLoader(NcgConfig.config['templates']['root_dir'] + '/' + apiversion),
- trim_blocks=True, extensions=["jinja2_base64_filters.Base64Filters"])
-
- nginxMainConf = j2_env.get_template(NcgConfig.config['templates']['nginxmain']).render(
- nginxconf={'modules': v4_1.MiscUtils.getDictKey(d, 'output.nms.modules')})
-
- # Base64-encoded NGINX main configuration (/etc/nginx/nginx.conf)
- b64NginxMain = str(base64.urlsafe_b64encode(nginxMainConf.encode("utf-8")), "utf-8")
-
- # Base64-encoded NGINX mime.types (/etc/nginx/mime.types)
- f = open(NcgConfig.config['templates']['root_dir'] + '/' + apiversion + '/' + NcgConfig.config['templates'][
- 'mimetypes'], 'r')
- nginxMimeTypes = f.read()
- f.close()
-
- b64NginxMimeTypes = str(base64.urlsafe_b64encode(nginxMimeTypes.encode("utf-8")), "utf-8")
- filesMimeType = {'contents': b64NginxMimeTypes, 'name': NcgConfig.config['nms']['config_dir'] + '/mime.types'}
- auxFiles['files'].append(filesMimeType)
-
- # Base64-encoded NGINX HTTP service configuration
- filesNginxMain = {'contents': b64NginxMain, 'name': NcgConfig.config['nms']['config_dir'] + '/nginx.conf'}
- filesHttpConf = {'contents': b64HttpConf,
- 'name': NcgConfig.config['nms']['config_dir'] + '/' + NcgConfig.config['nms'][
- 'staged_config_http_filename']}
- filesStreamConf = {'contents': b64StreamConf,
- 'name': NcgConfig.config['nms']['config_dir'] + '/' + NcgConfig.config['nms'][
- 'staged_config_stream_filename']}
-
- # Append config files to staged configuration
- configFiles['files'].append(filesNginxMain)
- configFiles['files'].append(filesHttpConf)
- configFiles['files'].append(filesStreamConf)
-
- # Staged config
- baseStagedConfig = {'auxFiles': auxFiles, 'configFiles': configFiles}
- stagedConfig = {'auxFiles': auxFiles, 'configFiles': configFiles,
- 'updateTime': datetime.utcnow().isoformat()[:-3] + 'Z',
- 'ignoreConflict': True, 'validateConfig': False}
-
- currentBaseStagedConfig = NcgRedis.redis.get(f'ncg.basestagedconfig.{configUid}').decode('utf-8') if NcgRedis.redis.get(f'ncg.basestagedconfig.{configUid}') else None
- newBaseStagedConfig = json.dumps(baseStagedConfig)
-
- if currentBaseStagedConfig is not None and newBaseStagedConfig == currentBaseStagedConfig:
- print(f'Declaration [{configUid}] not changed')
- return {"status_code": 200,
- "message": {"status_code": 200, "message": {"code": 200, "content": "no changes"}}}
- else:
- # Configuration objects have changed, publish to NIM needed
- print(f'Declaration [{configUid}] changed, publishing to NMS')
-
- # Retrieve instance group uid
- try:
- ig = requests.get(url=f'{nmsUrl}/api/platform/v1/instance-groups', auth=(nmsUsername, nmsPassword),
- verify=False)
- except Exception as e:
- return {"status_code": 400,
- "message": {"status_code": 400,
- "message": {"code": 400, "content": f"Can't connect to {nmsUrl}"}}}
-
- if ig.status_code != 200:
- try:
- return {"status_code": ig.status_code,
- "message": {"status_code": ig.status_code,
- "message": {"code": ig.status_code, "content": json.loads(ig.text)}}}
- except:
- return {"status_code": ig.status_code,
- "message": {"status_code": ig.status_code,
- "message": {"code": ig.status_code, "content": ig.text}}}
-
- # Get the instance group id
- igUid = v4_1.NIMUtils.getNIMInstanceGroupUid(nmsUrl=nmsUrl, nmsUsername=nmsUsername,
- nmsPassword=nmsPassword, instanceGroupName=nmsInstanceGroup)
-
- # Invalid instance group
- if igUid is None:
- return {"status_code": 404,
- "message": {"status_code": 404, "message": {"code": 404,
- "content": f"instance group {nmsInstanceGroup} not found"}},
- "headers": {'Content-Type': 'application/json'}}
-
- ### NGINX App Protect policies support - commits policies to control plane
-
- # Check NGINX App Protect WAF policies configuration sanity
- status, description = v4_1.NAPUtils.checkDeclarationPolicies(d)
-
- if status != 200:
- return {"status_code": 422, "message": {"status_code": status, "message": description}}
-
- # Provision NGINX App Protect WAF policies to NGINX Instance Manager
- provisionedNapPolicies, activePolicyUids = v4_1.NAPUtils.provisionPolicies(
- nmsUrl=nmsUrl, nmsUsername=nmsUsername, nmsPassword=nmsPassword, declaration=d)
-
- ### / NGINX App Protect policies support
-
- ### Publish staged config to instance group
- r = requests.post(url=nmsUrl + f"/api/platform/v1/instance-groups/{igUid}/config",
- data=json.dumps(stagedConfig),
- headers={'Content-Type': 'application/json'},
- auth=(nmsUsername, nmsPassword),
- verify=False)
-
- if r.status_code != 202:
- # Configuration push failed
- return {"status_code": r.status_code,
- "message": {"status_code": r.status_code, "message": r.text},
- "headers": {'Content-Type': 'application/json'}}
-
- # Fetch the deployment status
- publishResponse = json.loads(r.text)
-
- # Wait for either NIM success or failure after pushing a staged config
- isPending = True
- while isPending:
- time.sleep(NcgConfig.config['nms']['staged_config_publish_waittime'])
- deploymentCheck = requests.get(url=nmsUrl + publishResponse['links']['rel'],
- auth=(nmsUsername, nmsPassword),
- verify=False)
-
- checkJson = json.loads(deploymentCheck.text)
-
- if not checkJson['details']['pending']:
- isPending = False
-
- if len(checkJson['details']['failure']) > 0:
- # Staged config publish to NIM failed
- jsonResponse = checkJson['details']['failure'][0]
- deploymentCheck.status_code = 422
- else:
- # Staged config publish to NIM succeeded
- jsonResponse = json.loads(deploymentCheck.text)
-
- # if nmsSynctime > 0 and runfromautosync == False:
- if runfromautosync == False:
- # No configuration is found, generate one
- configUid = str(getuniqueid())
-
- # Stores the staged config to redis
- # Redis keys:
- # ncg.declaration.[configUid] = original config declaration
- # ncg.declarationrendered.[configUid] = original config declaration - rendered
- # ncg.basestagedconfig.[configUid] = base staged configuration
- # ncg.apiversion.[configUid] = ncg API version
- # ncg.status.[configUid] = latest status
-
- NcgRedis.redis.set(f'ncg.declaration.{configUid}', pickle.dumps(declaration))
- NcgRedis.redis.set(f'ncg.declarationrendered.{configUid}', json.dumps(d))
- NcgRedis.redis.set(f'ncg.basestagedconfig.{configUid}', json.dumps(baseStagedConfig))
- NcgRedis.redis.set(f'ncg.apiversion.{configUid}', apiversion)
-
- # Makes NGINX App Protect policies active
- doWeHavePolicies = v4_1.NAPUtils.makePolicyActive(nmsUrl=nmsUrl, nmsUsername=nmsUsername,
- nmsPassword=nmsPassword,
- activePolicyUids=activePolicyUids,
- instanceGroupUid=igUid)
-
- if doWeHavePolicies:
- # Clean up NGINX App Protect WAF policies not used anymore
- # and not defined in the declaration just pushed
- time.sleep(NcgConfig.config['nms']['staged_config_publish_waittime'])
- v4_1.NAPUtils.cleanPolicyLeftovers(nmsUrl=nmsUrl, nmsUsername=nmsUsername,
- nmsPassword=nmsPassword,
- currentPolicies=provisionedNapPolicies)
-
- # If deploying a new configuration in GitOps mode start autosync
- if nmsSynctime == 0:
- NcgRedis.declarationsList[configUid] = "static"
- elif not runfromautosync:
- # GitOps autosync
- print(f'Starting autosync for configUid {configUid} every {nmsSynctime} seconds')
-
- job = schedule.every(nmsSynctime).seconds.do(lambda: configautosync(configUid))
- # Keep track of GitOps configs, key is the threaded job
- NcgRedis.declarationsList[configUid] = job
-
- NcgRedis.redis.set(f'ncg.apiversion.{configUid}', apiversion)
-
- responseContent = {'code': deploymentCheck.status_code, 'content': jsonResponse, 'configUid': configUid}
-
- # Configuration push completed, update redis keys
- if configUid != "":
- NcgRedis.redis.set('ncg.status.' + configUid, json.dumps(responseContent))
-
- # if nmsSynctime > 0:
- # Updates status, declaration and basestagedconfig in redis
- NcgRedis.redis.set('ncg.declaration.' + configUid, pickle.dumps(declaration))
- NcgRedis.redis.set('ncg.declarationrendered.' + configUid, json.dumps(d))
- NcgRedis.redis.set('ncg.basestagedconfig.' + configUid, json.dumps(baseStagedConfig))
-
- return {"status_code": deploymentCheck.status_code,
- "message": {"status_code": deploymentCheck.status_code,
- "message": responseContent},
- "headers": {'Content-Type': 'application/json'}
- }
+ return {"status_code": 501, "message": {"code": 501, "content": "NGINX One support not yet available"}}
else:
return {"status_code": 422, "message": {"status_code": 422, "message": f"output type {decltype} unknown"}}
@@ -712,51 +590,51 @@ def patch_config(declaration: ConfigDeclaration, configUid: str, apiversion: str
status_code, currentDeclaration = get_declaration(configUid=configUid)
# Handle policy updates
- d_policies = v4_1.MiscUtils.getDictKey(declarationToPatch, 'output.nms.policies')
+ d_policies = v5_0.MiscUtils.getDictKey(declarationToPatch, 'output.nms.policies')
if d_policies is not None:
# NGINX App Protect WAF policy updates
for p in d_policies:
- currentDeclaration = v4_1.DeclarationPatcher.patchNAPPolicies(
+ currentDeclaration = v5_0.DeclarationPatcher.patchNAPPolicies(
sourceDeclaration=currentDeclaration, patchedNAPPolicies=p)
# Handle certificate updates
- d_certificates = v4_1.MiscUtils.getDictKey(declarationToPatch, 'output.nms.certificates')
+ d_certificates = v5_0.MiscUtils.getDictKey(declarationToPatch, 'output.nms.certificates')
if d_certificates is not None:
# TLS certificate/key updates
for p in d_certificates:
- currentDeclaration = v4_1.DeclarationPatcher.patchCertificates(
+ currentDeclaration = v5_0.DeclarationPatcher.patchCertificates(
sourceDeclaration=currentDeclaration, patchedCertificates=p)
# Handle declaration updates
if 'declaration' in declarationToPatch:
# HTTP
- d_upstreams = v4_1.MiscUtils.getDictKey(declarationToPatch, 'declaration.http.upstreams')
+ d_upstreams = v5_0.MiscUtils.getDictKey(declarationToPatch, 'declaration.http.upstreams')
if d_upstreams:
# HTTP upstream patch
for u in d_upstreams:
- currentDeclaration = v4_1.DeclarationPatcher.patchHttpUpstream(
+ currentDeclaration = v5_0.DeclarationPatcher.patchHttpUpstream(
sourceDeclaration=currentDeclaration, patchedHttpUpstream=u)
- d_servers = v4_1.MiscUtils.getDictKey(declarationToPatch, 'declaration.http.servers')
+ d_servers = v5_0.MiscUtils.getDictKey(declarationToPatch, 'declaration.http.servers')
if d_servers:
# HTTP servers patch
for s in d_servers:
- currentDeclaration = v4_1.DeclarationPatcher.patchHttpServer(
+ currentDeclaration = v5_0.DeclarationPatcher.patchHttpServer(
sourceDeclaration=currentDeclaration, patchedHttpServer=s)
# Stream / Layer4
- d_upstreams = v4_1.MiscUtils.getDictKey(declarationToPatch, 'declaration.layer4.upstreams')
+ d_upstreams = v5_0.MiscUtils.getDictKey(declarationToPatch, 'declaration.layer4.upstreams')
if d_upstreams:
# Stream upstream patch
for u in d_upstreams:
- currentDeclaration = v4_1.DeclarationPatcher.patchStreamUpstream(
+ currentDeclaration = v5_0.DeclarationPatcher.patchStreamUpstream(
sourceDeclaration=currentDeclaration, patchedStreamUpstream=u)
- d_servers = v4_1.MiscUtils.getDictKey(declarationToPatch, 'declaration.layer4.servers')
+ d_servers = v5_0.MiscUtils.getDictKey(declarationToPatch, 'declaration.layer4.servers')
if d_servers:
# Stream servers patch
for s in d_servers:
- currentDeclaration = v4_1.DeclarationPatcher.patchStreamServer(
+ currentDeclaration = v5_0.DeclarationPatcher.patchStreamServer(
sourceDeclaration=currentDeclaration, patchedStreamServer=s)
# Apply the updated declaration
@@ -789,4 +667,4 @@ def get_declaration(configUid: str):
if cfg is None:
return 404, ""
- return 200, pickle.loads(cfg).dict()
+ return 200, pickle.loads(cfg).dict()
\ No newline at end of file
diff --git a/src/V4_1_NginxConfigDeclaration.py b/src/V5_0_NginxConfigDeclaration.py
similarity index 62%
rename from src/V4_1_NginxConfigDeclaration.py
rename to src/V5_0_NginxConfigDeclaration.py
index df73430..685aa59 100644
--- a/src/V4_1_NginxConfigDeclaration.py
+++ b/src/V5_0_NginxConfigDeclaration.py
@@ -1,13 +1,15 @@
"""
-JSON declaration format
+JSON declaration structure
"""
from __future__ import annotations
-
from typing import List, Optional
-
from pydantic import BaseModel, Extra, model_validator
+import re
+
+# Regexp to check names
+alphanumRegexp = '^[a-zA-Z0-9\ \-\_]+$'
class OutputConfigMap(BaseModel, extra="forbid"):
name: str = "nginx-config"
@@ -120,17 +122,30 @@ class OutputNMS(BaseModel, extra="forbid"):
log_profiles: Optional[List[LogProfile]] = []
+class OutputNGINXOne(BaseModel, extra="forbid"):
+ url: str = ""
+ namespace: str = ""
+ token: str = ""
+ cluster: str = ""
+ synctime: Optional[int] = 0
+ modules: Optional[List[str]] = []
+ certificates: Optional[List[NmsCertificate]] = []
+ policies: Optional[List[NmsPolicy]] = []
+ log_profiles: Optional[List[LogProfile]] = []
+
+
class Output(BaseModel, extra="forbid"):
type: str
configmap: Optional[OutputConfigMap] = {}
http: Optional[OutputHttp] = {}
nms: Optional[OutputNMS] = {}
+ nginxone: Optional[OutputNGINXOne] = {}
@model_validator(mode='after')
def check_type(self) -> 'Output':
- _type, configmap, http, nms = self.type, self.configmap, self.http, self.nms
+ _type, configmap, http, nms, nginxone = self.type, self.configmap, self.http, self.nms, self.nginxone
- valid = ['plaintext', 'json', 'configmap', 'http', 'nms']
+ valid = ['plaintext', 'json', 'configmap', 'http', 'nms', 'nginxone']
if _type not in valid:
raise ValueError(f"Invalid output type [{_type}] must be one of {str(valid)}")
@@ -142,6 +157,8 @@ def check_type(self) -> 'Output':
isError = True
elif _type == 'nms' and not nms:
isError = True
+ elif _type == 'nginxone' and not nginxone:
+ isError = True
if isError:
raise ValueError(f"Invalid output data for type [{_type}]")
@@ -160,13 +177,26 @@ class Ocsp(BaseModel, extra="forbid"):
enabled: Optional[str] = "off"
responder: Optional[str] = ""
+ @model_validator(mode='after')
+ def check_type(self) -> 'Ocsp':
+ _enabled = self.enabled
+
+ valid = ['on', 'off', 'leaf']
+ if _enabled not in valid:
+ raise ValueError(f"Invalid OCSP validation type type [{_enabled}] must be one of {str(valid)}")
+
+ return self
+
-class Mtls(BaseModel, extra="forbid"):
+class AuthClientMtls(BaseModel, extra="forbid"):
enabled: Optional[str] = "off"
client_certificates: str = ""
+ trusted_ca_certificates: Optional[str] = ""
+ ocsp: Optional[Ocsp] = {}
+ stapling: Optional[OcspStapling] = {}
@model_validator(mode='after')
- def check_type(self) -> 'Mtls':
+ def check_type(self) -> 'AuthClientMtls':
_enabled = self.enabled
valid = ['on', 'off', 'optional', 'optional_no_ca']
@@ -179,12 +209,9 @@ def check_type(self) -> 'Mtls':
class Tls(BaseModel, extra="forbid"):
certificate: str = ""
key: str = ""
- trusted_ca_certificates: str = ""
ciphers: Optional[str] = ""
protocols: Optional[List[str]] = []
- mtls: Optional[Mtls] = {}
- ocsp: Optional[Ocsp] = {}
- stapling: Optional[OcspStapling] = {}
+ authentication: Optional[LocationAuth] = {}
class Listen(BaseModel, extra="forbid"):
@@ -232,11 +259,34 @@ class LocationAuthServer(BaseModel, extra="forbid"):
profile: Optional[str] = ""
+class LocationHeaderToClient(BaseModel, extra="forbid"):
+ add: Optional[List[HTTPHeader]] = []
+ delete: Optional[List[str]] = []
+ replace: Optional[List[HTTPHeader]] = []
+
+
+class LocationHeaderToServer(BaseModel, extra="forbid"):
+ set: Optional[List[HTTPHeader]] = []
+ delete: Optional[List[str]] = []
+
+
+class HTTPHeader(BaseModel, extra="forbid"):
+ name: str = ""
+ value: str = ""
+
+
class LocationAuth(BaseModel, extra="forbid"):
client: Optional[List[LocationAuthClient]] = []
server: Optional[List[LocationAuthServer]] = []
+class AuthorizationProfileReference(BaseModel, extra="forbid"):
+ profile: Optional[str] = ""
+
+class LocationHeaders(BaseModel, extra="forbid"):
+ to_server: Optional[LocationHeaderToServer] = {}
+ to_client: Optional[LocationHeaderToClient] = {}
+
class RateLimitApiGw(BaseModel, extra="forbid"):
profile: Optional[str] = ""
httpcode: Optional[int] = 429
@@ -251,18 +301,24 @@ class APIGatewayAuthentication(BaseModel, extra="forbid"):
paths: Optional[List[str]] = []
+class APIGatewayAuthorization(BaseModel, extra="forbid"):
+ profile: str
+ enforceOnPaths: Optional[bool] = True
+ paths: Optional[List[str]] = []
+
class AuthClientJWT(BaseModel, extra="forbid"):
realm: str = "JWT Authentication"
key: str = ""
cachetime: Optional[int] = 0
jwt_type: str = "signed"
+ token_location: Optional[str] = ""
@model_validator(mode='after')
def check_type(self) -> 'AuthClientJWT':
jwt_type, key = self.jwt_type, self.key
- if not key.strip() :
- raise ValueError(f"Invalid: JWT key must not be empty")
+ #if not key.strip():
+ # raise ValueError(f"Invalid: JWT key must not be empty")
valid = ['signed', 'encrypted', 'nested']
if jwt_type not in valid:
@@ -272,23 +328,53 @@ def check_type(self) -> 'AuthClientJWT':
class AuthServerToken(BaseModel, extra="forbid"):
token: str = ""
- type: Optional[str] = "bearer"
+ type: Optional[str] = ""
location: Optional[str] = ""
+ username: Optional[str] = ""
+ password: Optional[str] = ""
@model_validator(mode='after')
def check_type(self) -> 'AuthServerToken':
- location, type = self.location, self.type.lower()
+ tokentype, location, username, password = self.type.lower(), self.location, self.username, self.password
+
+ valid = ['bearer', 'header', 'basic', '']
+ if tokentype not in valid:
+ raise ValueError(f"Invalid token type [{tokentype}] must be one of {str(valid)}")
+
+ if tokentype in ['header'] and location == "":
+ raise ValueError(f"Empty location for [{tokentype}] token")
+
+ if tokentype in ['basic'] and (username == "" or password == ""):
+ raise ValueError(f"Missing username/password for [{tokentype}] token")
+
+ return self
+
+
+class AuthServerMtls(BaseModel, extra="forbid"):
+ certificate: str = ""
+ key: str = ""
- valid = ['bearer', 'header']
- if type not in valid:
- raise ValueError(f"Invalid token type [{type}] must be one of {str(valid)}")
- if type in ['header'] and location == "":
- raise ValueError(f"Empty location for [{type}] token")
+class JwtAuthZNameValue(BaseModel, extra="forbid"):
+ name: str
+ value: List[str]
+ errorcode: Optional[int] = 401
+
+ @model_validator(mode='after')
+ def check_type(self) -> 'JwtAuthZNameValue':
+ errorcode = self.errorcode
+
+ valid = [401, 403]
+ if errorcode not in valid:
+ raise ValueError(f"Invalid errorcode [{errorcode}] must be one of {str(valid)}")
return self
+class AuthorizationJWT(BaseModel, extra="forbid"):
+ claims: List[JwtAuthZNameValue]
+
+
class HealthCheck(BaseModel, extra="forbid"):
enabled: Optional[bool] = False
uri: Optional[str] = "/"
@@ -321,6 +407,9 @@ class Location(BaseModel, extra="forbid"):
app_protect: Optional[AppProtect] = {}
snippet: Optional[ObjectFromSourceOfTruth] = {}
authentication: Optional[LocationAuth] = {}
+ authorization: Optional[AuthorizationProfileReference] = {}
+ headers: Optional[LocationHeaders]= {}
+ njs: Optional[List[NjsHookLocation]] = []
@model_validator(mode='after')
def check_type(self) -> 'Location':
@@ -342,6 +431,71 @@ class ObjectFromSourceOfTruth(BaseModel, extra="forbid"):
content: str = ""
authentication: Optional[List[LocationAuthServer]] = []
+
+class NjsHook_js_body_filter(BaseModel, extra="forbid"):
+ buffer_type: Optional[str] = ""
+
+
+class NjsHook_js_periodic(BaseModel, extra="forbid"):
+ interval: Optional[str] = ""
+ jitter: Optional[int] = 0
+ worker_affinity: Optional[str] = ""
+
+
+class NjsHook_js_preload_object(BaseModel, extra="forbid"):
+ file: str
+
+
+class NjsHook_js_set(BaseModel, extra="forbid"):
+ variable: str
+
+
+class NjsHookHttpServerDetails(BaseModel, extra="forbid"):
+ type: str
+ js_preload_object: Optional[NjsHook_js_preload_object] = {}
+ js_set: Optional[NjsHook_js_set] = {}
+
+ @model_validator(mode='after')
+ def check_type(self) -> 'NjsHookHttpServerDetails':
+ _type = self.type
+
+ valid = ['js_preload_object', 'js_set']
+ if _type not in valid:
+ raise ValueError(f"Invalid hook [{_type}] must be one of {str(valid)}")
+
+ return self
+
+
+class NjsHookLocationDetails(BaseModel, extra="forbid"):
+ type: str
+ js_preload_object: Optional[NjsHook_js_preload_object] = {}
+ js_set: Optional[NjsHook_js_set] = {}
+ js_body_filter: Optional[NjsHook_js_body_filter] = {}
+ js_periodic: Optional[NjsHook_js_periodic] = {}
+
+ @model_validator(mode='after')
+ def check_type(self) -> 'NjsHookLocationDetails':
+ _type = self.type
+
+ valid = ['js_body_filter', 'js_content', 'js_header_filter', 'js_periodic', 'js_preload_object', 'js_set']
+ if _type not in valid:
+ raise ValueError(f"Invalid hook [{_type}] must be one of {str(valid)}")
+
+ return self
+
+
+class NjsHookHttpServer(BaseModel, extra="forbid"):
+ hook: NjsHookHttpServerDetails
+ profile: str
+ function: str
+
+
+class NjsHookLocation(BaseModel, extra="forbid"):
+ hook: NjsHookLocationDetails
+ profile: str
+ function: str
+
+
class Server(BaseModel, extra="forbid"):
name: str
names: Optional[List[str]] = []
@@ -351,6 +505,19 @@ class Server(BaseModel, extra="forbid"):
locations: Optional[List[Location]] = []
app_protect: Optional[AppProtect] = {}
snippet: Optional[ObjectFromSourceOfTruth] = {}
+ headers: Optional[LocationHeaders] = {}
+ njs: Optional[List[NjsHookHttpServer]] = []
+ authentication: Optional[LocationAuth] = {}
+ authorization: Optional[AuthorizationProfileReference] = {}
+
+ @model_validator(mode='after')
+ def check_type(self) -> 'Server':
+ name = self.name
+
+ if not re.search(alphanumRegexp,name):
+ raise ValueError(f"Invalid name [{name}] should match regexp {alphanumRegexp}")
+
+ return self
class L4Server(BaseModel, extra="forbid"):
@@ -359,6 +526,15 @@ class L4Server(BaseModel, extra="forbid"):
upstream: Optional[str] = ""
snippet: Optional[ObjectFromSourceOfTruth] = {}
+ @model_validator(mode='after')
+ def check_type(self) -> 'L4Server':
+ name = self.name
+
+ if not re.search(alphanumRegexp,name):
+ raise ValueError(f"Invalid name [{name}] should match regexp {alphanumRegexp}")
+
+ return self
+
class Sticky(BaseModel, extra="forbid"):
cookie: str = ""
@@ -393,12 +569,30 @@ class Upstream(BaseModel, extra="forbid"):
sticky: Optional[Sticky] = {}
snippet: Optional[ObjectFromSourceOfTruth] = {}
+ @model_validator(mode='after')
+ def check_type(self) -> 'Upstream':
+ name = self.name
+
+ if not re.search(alphanumRegexp,name):
+ raise ValueError(f"Invalid name [{name}] should match regexp {alphanumRegexp}")
+
+ return self
+
class L4Upstream(BaseModel, extra="forbid"):
name: str
origin: Optional[List[L4Origin]] = []
snippet: Optional[ObjectFromSourceOfTruth] = {}
+ @model_validator(mode='after')
+ def check_type(self) -> 'L4Upstream':
+ name = self.name
+
+ if not re.search(alphanumRegexp,name):
+ raise ValueError(f"Invalid name [{name}] should match regexp {alphanumRegexp}")
+
+ return self
+
class ValidItem(BaseModel, extra="forbid"):
codes: Optional[List[int]] = [200]
@@ -411,6 +605,15 @@ class CachingItem(BaseModel, extra="forbid"):
size: Optional[str] = "10m"
valid: Optional[List[ValidItem]] = []
+ @model_validator(mode='after')
+ def check_type(self) -> 'CachingItem':
+ name = self.name
+
+ if not re.search(alphanumRegexp,name):
+ raise ValueError(f"Invalid name [{name}] should match regexp {alphanumRegexp}")
+
+ return self
+
class RateLimitItem(BaseModel, extra="forbid"):
name: str
@@ -418,6 +621,15 @@ class RateLimitItem(BaseModel, extra="forbid"):
size: Optional[str] = ""
rate: Optional[str] = ""
+ @model_validator(mode='after')
+ def check_type(self) -> 'RateLimitItem':
+ name = self.name
+
+ if not re.search(alphanumRegexp,name):
+ raise ValueError(f"Invalid name [{name}] should match regexp {alphanumRegexp}")
+
+ return self
+
class NginxPlusApi(BaseModel, extra="forbid"):
write: Optional[bool] = False
@@ -457,15 +669,19 @@ class Authentication_Client(BaseModel, extra="forbid"):
type: str
jwt: Optional[AuthClientJWT] = {}
+ mtls: Optional[AuthClientMtls] = {}
@model_validator(mode='after')
def check_type(self) -> 'Authentication_Client':
_type, name = self.type, self.name
- valid = ['jwt']
+ valid = ['jwt', 'mtls']
if _type not in valid:
raise ValueError(f"Invalid client authentication type [{_type}] for profile [{name}] must be one of {str(valid)}")
+ if not re.search(alphanumRegexp,name):
+ raise ValueError(f"Invalid name [{name}] should match regexp {alphanumRegexp}")
+
return self
@@ -474,15 +690,19 @@ class Authentication_Server(BaseModel, extra="forbid"):
type: str
token: Optional[AuthServerToken] = {}
+ mtls: Optional[AuthServerMtls] = {}
@model_validator(mode='after')
def check_type(self) -> 'Authentication_Server':
_type, name = self.type, self.name
- valid = ['token']
+ valid = ['token', 'mtls']
if _type not in valid:
raise ValueError(f"Invalid server authentication type [{_type}] for profile [{name}] must be one of {str(valid)}")
+ if not re.search(alphanumRegexp,name):
+ raise ValueError(f"Invalid name [{name}] should match regexp {alphanumRegexp}")
+
return self
@@ -491,6 +711,39 @@ class Authentication(BaseModel, extra="forbid"):
server: Optional[List[Authentication_Server]] = []
+class Authorization(BaseModel, extra="forbid"):
+ name: str
+ type: str
+
+ jwt: Optional[AuthorizationJWT] = {}
+
+ @model_validator(mode='after')
+ def check_type(self) -> 'Authorization':
+ _type, name = self.type, self.name
+
+ valid = ['jwt']
+ if _type not in valid:
+ raise ValueError(f"Invalid authorization type [{_type}] for profile [{name}] must be one of {str(valid)}")
+
+ if not re.search(alphanumRegexp,name):
+ raise ValueError(f"Invalid name [{name}] should match regexp {alphanumRegexp}")
+
+ return self
+
+class NjsFile(BaseModel, extra="forbid"):
+ name: str
+ file: ObjectFromSourceOfTruth
+
+ @model_validator(mode='after')
+ def check_type(self) -> 'NjsFile':
+ name = self.name
+
+ if not re.search(alphanumRegexp,name):
+ raise ValueError(f"Invalid name [{name}] should match regexp {alphanumRegexp}")
+
+ return self
+
+
class Http(BaseModel, extra="forbid"):
servers: Optional[List[Server]] = []
upstreams: Optional[List[Upstream]] = []
@@ -500,6 +753,9 @@ class Http(BaseModel, extra="forbid"):
maps: Optional[List[Map]] = []
snippet: Optional[ObjectFromSourceOfTruth] = {}
authentication: Optional[Authentication] = {}
+ authorization: Optional[List[Authorization]] = []
+ njs: Optional[List[NjsHookHttpServer]] = []
+ njs_profiles: Optional[List[NjsFile]] = []
class Declaration(BaseModel, extra="forbid"):
@@ -522,6 +778,7 @@ class APIGateway(BaseModel, extra="forbid"):
developer_portal: Optional[DeveloperPortal] = {}
rate_limit: Optional[List[RateLimitApiGw]] = []
authentication: Optional[APIGatewayAuthentication] = {}
+ authorization: Optional[List[APIGatewayAuthorization]] = []
log: Optional[Log] = {}
diff --git a/src/main.py b/src/main.py
index 73b9085..67451f0 100644
--- a/src/main.py
+++ b/src/main.py
@@ -16,12 +16,11 @@
import NcgConfig
import NcgRedis
-import V4_1_CreateConfig
-import V4_1_NginxConfigDeclaration
-
import V4_2_CreateConfig
import V4_2_NginxConfigDeclaration
+import V5_0_CreateConfig
+import V5_0_NginxConfigDeclaration
cfg = NcgConfig.NcgConfig(configFile="../etc/config.toml")
redis = NcgRedis.NcgRedis(host=cfg.config['redis']['host'], port=cfg.config['redis']['port'])
@@ -39,10 +38,10 @@ def runScheduler():
time.sleep(1)
-# Submit declaration using v4.1 API
-@app.post("/v4.1/config", status_code=200, response_class=PlainTextResponse)
-def post_config_v4_1(d: V4_1_NginxConfigDeclaration.ConfigDeclaration, response: Response):
- output = V4_1_CreateConfig.createconfig(declaration=d, apiversion='v4.1')
+# Submit declaration using v4.2 API
+@app.post("/v4.2/config", status_code=200, response_class=PlainTextResponse)
+def post_config_v4_2(d: V4_2_NginxConfigDeclaration.ConfigDeclaration, response: Response):
+ output = V4_2_CreateConfig.createconfig(declaration=d, apiversion='v4.2')
if type(output) in [Response, str]:
# ConfigMap or plaintext response
@@ -61,10 +60,10 @@ def post_config_v4_1(d: V4_1_NginxConfigDeclaration.ConfigDeclaration, response:
return JSONResponse(content=response, status_code=output['status_code'], headers=headers)
-# Submit declaration using v4.2 API
-@app.post("/v4.2/config", status_code=200, response_class=PlainTextResponse)
-def post_config_v4_2(d: V4_2_NginxConfigDeclaration.ConfigDeclaration, response: Response):
- output = V4_2_CreateConfig.createconfig(declaration=d, apiversion='v4.2')
+# Submit declaration using v5.0 API
+@app.post("/v5.0/config", status_code=200, response_class=PlainTextResponse)
+def post_config_v5_0(d: V5_0_NginxConfigDeclaration.ConfigDeclaration, response: Response):
+ output = V5_0_CreateConfig.createconfig(declaration=d, apiversion='v5.0')
if type(output) in [Response, str]:
# ConfigMap or plaintext response
@@ -83,22 +82,22 @@ def post_config_v4_2(d: V4_2_NginxConfigDeclaration.ConfigDeclaration, response:
return JSONResponse(content=response, status_code=output['status_code'], headers=headers)
-# Modify declaration using v4.1 API
-@app.patch("/v4.1/config/{configuid}", status_code=200, response_class=PlainTextResponse)
-def patch_config_v4_1(d: V4_1_NginxConfigDeclaration.ConfigDeclaration, response: Response, configuid: str):
- return V4_1_CreateConfig.patch_config(declaration=d, configUid=configuid, apiversion='v4.1')
-
-
# Modify declaration using v4.2 API
@app.patch("/v4.2/config/{configuid}", status_code=200, response_class=PlainTextResponse)
def patch_config_v4_2(d: V4_2_NginxConfigDeclaration.ConfigDeclaration, response: Response, configuid: str):
return V4_2_CreateConfig.patch_config(declaration=d, configUid=configuid, apiversion='v4.2')
-# Get declaration - v4.1 API
-@app.get("/v4.1/config/{configuid}", status_code=200, response_class=PlainTextResponse)
-def get_config_declaration_v4_1(configuid: str):
- status_code, content = V4_1_CreateConfig.get_declaration(configUid=configuid)
+# Modify declaration using v5.0 API
+@app.patch("/v5.0/config/{configuid}", status_code=200, response_class=PlainTextResponse)
+def patch_config_v5_0(d: V5_0_NginxConfigDeclaration.ConfigDeclaration, response: Response, configuid: str):
+ return V5_0_CreateConfig.patch_config(declaration=d, configUid=configuid, apiversion='v5.0')
+
+
+# Get declaration - v4.2 API
+@app.get("/v4.2/config/{configuid}", status_code=200, response_class=PlainTextResponse)
+def get_config_declaration_v4_2(configuid: str):
+ status_code, content = V4_2_CreateConfig.get_declaration(configUid=configuid)
if status_code == 404:
return JSONResponse(
@@ -114,11 +113,10 @@ def get_config_declaration_v4_1(configuid: str):
)
-
-# Get declaration - v4.2 API
-@app.get("/v4.2/config/{configuid}", status_code=200, response_class=PlainTextResponse)
-def get_config_declaration_v4_2(configuid: str):
- status_code, content = V4_2_CreateConfig.get_declaration(configUid=configuid)
+# Get declaration - v5.0 API
+@app.get("/v5.0/config/{configuid}", status_code=200, response_class=PlainTextResponse)
+def get_config_declaration_v5_0(configuid: str):
+ status_code, content = V5_0_CreateConfig.get_declaration(configUid=configuid)
if status_code == 404:
return JSONResponse(
@@ -135,8 +133,8 @@ def get_config_declaration_v4_2(configuid: str):
# Get declaration status
-@app.get("/v4.1/config/{configuid}/status", status_code=200, response_class=PlainTextResponse)
@app.get("/v4.2/config/{configuid}/status", status_code=200, response_class=PlainTextResponse)
+@app.get("/v5.0/config/{configuid}/status", status_code=200, response_class=PlainTextResponse)
def get_config_status(configuid: str):
status = redis.redis.get('ncg.status.' + configuid)
@@ -155,8 +153,8 @@ def get_config_status(configuid: str):
# Delete declaration
-@app.delete("/v4.1/config/{configuid}", status_code=200, response_class=PlainTextResponse)
@app.delete("/v4.2/config/{configuid}", status_code=200, response_class=PlainTextResponse)
+@app.delete("/v5.0/config/{configuid}", status_code=200, response_class=PlainTextResponse)
def delete_config(configuid: str = ""):
if configuid not in redis.declarationsList:
return JSONResponse(
diff --git a/src/v4_1/APIGateway.py b/src/v4_1/APIGateway.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/v4_1/DeclarationPatcher.py b/src/v4_1/DeclarationPatcher.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/v4_1/DevPortal.py b/src/v4_1/DevPortal.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/v4_1/OpenAPIParser.py b/src/v4_1/OpenAPIParser.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/v5_0/APIGateway.py b/src/v5_0/APIGateway.py
new file mode 100644
index 0000000..ca61c19
--- /dev/null
+++ b/src/v5_0/APIGateway.py
@@ -0,0 +1,37 @@
+"""
+API Gateway support functions
+"""
+
+import json
+
+import v5_0.GitOps
+import v5_0.MiscUtils
+from v5_0.OpenAPIParser import OpenAPIParser
+
+# pydantic models
+from V5_0_NginxConfigDeclaration import *
+
+
+# Builds the declarative JSON for the API Gateway configuration
+# Return a tuple: status, description. If status = 200 things were successful
+def createAPIGateway(locationDeclaration: dict, authProfiles: Authentication={}):
+ apiGwDeclaration = {}
+
+ if locationDeclaration['apigateway']['openapi_schema']:
+ status, apiSchemaString = v5_0.GitOps.getObjectFromRepo(object=locationDeclaration['apigateway']['openapi_schema'],
+ authProfiles = authProfiles['server'] if 'server' in authProfiles else {}, base64Encode=False)
+
+ if v5_0.MiscUtils.yaml_or_json(apiSchemaString['content']) == 'yaml':
+ # YAML to JSON conversion
+ apiSchemaString['content'] = v5_0.MiscUtils.yaml_to_json(apiSchemaString['content'])
+
+ apiSchema = OpenAPIParser(json.loads(apiSchemaString['content']))
+
+ apiGwDeclaration = {}
+ apiGwDeclaration['location'] = locationDeclaration
+ apiGwDeclaration['info'] = apiSchema.info()
+ apiGwDeclaration['servers'] = apiSchema.servers()
+ apiGwDeclaration['paths'] = apiSchema.paths()
+ apiGwDeclaration['version'] = apiSchema.version()
+
+ return 200, apiGwDeclaration
\ No newline at end of file
diff --git a/src/v5_0/DeclarationPatcher.py b/src/v5_0/DeclarationPatcher.py
new file mode 100644
index 0000000..6e27285
--- /dev/null
+++ b/src/v5_0/DeclarationPatcher.py
@@ -0,0 +1,238 @@
+"""
+Declaration parsing functions
+"""
+
+
+# Returns the patched declaration based on the patchedHttpServer
+def patchHttpServer(sourceDeclaration: dict, patchedHttpServer: dict):
+ allTargetServers = []
+
+ haveWePatched = False
+
+ if 'declaration' not in sourceDeclaration:
+ sourceDeclaration['declaration'] = {}
+
+ if 'http' not in sourceDeclaration['declaration']:
+ sourceDeclaration['declaration']['http'] = {}
+
+ if 'servers' not in sourceDeclaration['declaration']['http']:
+ sourceDeclaration['declaration']['http']['servers'] = []
+
+ # HTTP server patch
+ for s in sourceDeclaration['declaration']['http']['servers']:
+ if s['name'] == patchedHttpServer['name']:
+ # Patching an existing HTTP server, 'name' is the key
+ if len(patchedHttpServer) > 1:
+ # Patching HTTP server specifying only 'name' (len == 1) means delete
+ # If further fields are specified HTTP server is patched
+ allTargetServers.append(patchedHttpServer)
+
+ haveWePatched = True
+ else:
+ # Unmodified HTTP server
+ allTargetServers.append(s)
+
+ if not haveWePatched:
+ # The HTTP server being patched is a new one, let's add it
+ allTargetServers.append(patchedHttpServer)
+
+ sourceDeclaration['declaration']['http']['servers'] = allTargetServers
+
+ return sourceDeclaration
+
+
+# Returns the patched declaration based on the patchedHttpUpstream
+def patchHttpUpstream(sourceDeclaration: dict, patchedHttpUpstream: dict):
+ allTargetUpstreams = []
+
+ haveWePatched = False
+
+ if 'declaration' not in sourceDeclaration:
+ sourceDeclaration['declaration'] = {}
+
+ if 'http' not in sourceDeclaration['declaration']:
+ sourceDeclaration['declaration']['http'] = {}
+
+ if 'upstreams' not in sourceDeclaration['declaration']['http']:
+ sourceDeclaration['declaration']['http']['upstreams'] = []
+
+ # HTTP upstreams patch
+ for s in sourceDeclaration['declaration']['http']['upstreams']:
+ if s['name'] == patchedHttpUpstream['name']:
+ # Patching an existing HTTP upstream, 'name' is the key
+ if len(patchedHttpUpstream) > 1:
+ # Patching HTTP upstream specifying only 'name' (len == 1) means delete
+ # If further fields are specified HTTP upstream is patched
+ allTargetUpstreams.append(patchedHttpUpstream)
+
+ haveWePatched = True
+ else:
+ # Unmodified HTTP upstream
+ allTargetUpstreams.append(s)
+
+ if not haveWePatched:
+ # The HTTP upstream being patched is a new one, let's add it
+ allTargetUpstreams.append(patchedHttpUpstream)
+
+ sourceDeclaration['declaration']['http']['upstreams'] = allTargetUpstreams
+
+ return sourceDeclaration
+
+
+# Returns the patched declaration based on the patchedStreamServer
+def patchStreamServer(sourceDeclaration: dict, patchedStreamServer: dict):
+ allTargetServers = []
+
+ haveWePatched = False
+
+ if 'declaration' not in sourceDeclaration:
+ sourceDeclaration['declaration'] = {}
+
+ if 'layer4' not in sourceDeclaration['declaration']:
+ sourceDeclaration['declaration']['layer4'] = {}
+
+ if 'servers' not in sourceDeclaration['declaration']['layer4']:
+ sourceDeclaration['declaration']['layer4']['servers'] = []
+
+ # HTTP server patch
+ for s in sourceDeclaration['declaration']['layer4']['servers']:
+ if s['name'] == patchedStreamServer['name']:
+ # Patching an existing Stream server, 'name' is the key
+ if len(patchedStreamServer) > 1:
+ # Patching Stream server specifying only 'name' (len == 1) means delete
+ # If further fields are specified HTTP server is patched
+ allTargetServers.append(patchedStreamServer)
+
+ haveWePatched = True
+ else:
+ # Unmodified HTTP server
+ allTargetServers.append(s)
+
+ if not haveWePatched:
+ # The Stream server being patched is a new one, let's add it
+ allTargetServers.append(patchedStreamServer)
+
+ sourceDeclaration['declaration']['layer4']['servers'] = allTargetServers
+
+ return sourceDeclaration
+
+
+# Returns the patched declaration based on the patchedStreamUpstream
+def patchStreamUpstream(sourceDeclaration: dict, patchedStreamUpstream: dict):
+ allTargetUpstreams = []
+
+ haveWePatched = False
+
+ if 'declaration' not in sourceDeclaration:
+ sourceDeclaration['declaration'] = {}
+
+ if 'layer4' not in sourceDeclaration['declaration']:
+ sourceDeclaration['declaration']['layer4'] = {}
+
+ if 'upstreams' not in sourceDeclaration['declaration']['layer4']:
+ sourceDeclaration['declaration']['layer4']['upstreams'] = []
+
+ # HTTP upstreams patch
+ for s in sourceDeclaration['declaration']['layer4']['upstreams']:
+ if s['name'] == patchedStreamUpstream['name']:
+ # Patching an existing Stream upstream, 'name' is the key
+ if len(patchedStreamUpstream) > 1:
+ # Patching Stream upstream specifying only 'name' (len == 1) means delete
+ # If further fields are specified HTTP upstream is patched
+ allTargetUpstreams.append(patchedStreamUpstream)
+
+ haveWePatched = True
+ else:
+ # Unmodified HTTP upstream
+ allTargetUpstreams.append(s)
+
+ if not haveWePatched:
+ # The Stream upstream being patched is a new one, let's add it
+ allTargetUpstreams.append(patchedStreamUpstream)
+
+ sourceDeclaration['declaration']['layer4']['upstreams'] = allTargetUpstreams
+
+ return sourceDeclaration
+
+
+# Returns the patched declaration based on the patchedNAPPolicies
+def patchNAPPolicies(sourceDeclaration: dict, patchedNAPPolicies: dict):
+ allTargetPolicies = []
+
+ haveWePatched = False
+
+ if 'output' not in sourceDeclaration:
+ return sourceDeclaration
+
+ if 'nms' not in sourceDeclaration['output']:
+ return sourceDeclaration
+
+ if 'policies' not in sourceDeclaration['output']['nms']:
+ return sourceDeclaration
+
+ # NGINX App Protect WAF policies patch
+ for p in sourceDeclaration['output']['nms']['policies']:
+ if 'type' in p and p['type'] == 'app_protect' \
+ and 'name' in p and p['name'] \
+ and p['type'] == patchedNAPPolicies['type'] \
+ and p['name'] == patchedNAPPolicies['name']:
+
+ # Patching an existing NGINX App Protect WAF policy, 'name' is the key
+ if patchedNAPPolicies['versions'] and patchedNAPPolicies['active_tag']:
+ # Patching NAP policy specifying 'versions' and 'active_tag' means updating
+ # If 'versions' and 'active_tag' are missing then it's a deletion
+ allTargetPolicies.append(patchedNAPPolicies)
+
+ haveWePatched = True
+ else:
+ # Unmodified HTTP upstream
+ allTargetPolicies.append(p)
+
+ if not haveWePatched:
+ # The NAP policy being patched is a new one, let's add it
+ allTargetPolicies.append(patchedNAPPolicies)
+
+ sourceDeclaration['output']['nms']['policies'] = allTargetPolicies
+
+ return sourceDeclaration
+
+
+# Returns the patched declaration based on patchedCertificates
+def patchCertificates(sourceDeclaration: dict, patchedCertificates: dict):
+ allTargetCertificates = []
+
+ haveWePatched = False
+
+ if 'output' not in sourceDeclaration:
+ return sourceDeclaration
+
+ if 'nms' not in sourceDeclaration['output']:
+ return sourceDeclaration
+
+ if 'certificates' not in sourceDeclaration['output']['nms']:
+ return sourceDeclaration
+
+ # TLS certificates patch
+ for c in sourceDeclaration['output']['nms']['certificates']:
+ if 'type' in c and c['type'] in ['certificate', 'key', 'chain'] \
+ and 'name' in c and c['name'] \
+ and c['type'] == patchedCertificates['type'] \
+ and c['name'] == patchedCertificates['name']:
+
+ if 'contents' in c and c['contents']:
+ # Patching an existing TLS certificate/key/chain, 'name' is the key.
+ # If content is empty the certificate is deleted
+ allTargetCertificates.append(patchedCertificates)
+
+ haveWePatched = True
+ else:
+ # Unmodified HTTP upstream
+ allTargetCertificates.append(c)
+
+ if not haveWePatched:
+ # The TLS certificate/key/chain being patched is a new one, let's add it
+ allTargetCertificates.append(patchedCertificates)
+
+ sourceDeclaration['output']['nms']['certificates'] = allTargetCertificates
+
+ return sourceDeclaration
diff --git a/src/v5_0/DevPortal.py b/src/v5_0/DevPortal.py
new file mode 100644
index 0000000..85e75c1
--- /dev/null
+++ b/src/v5_0/DevPortal.py
@@ -0,0 +1,46 @@
+"""
+API Gateway Developer Portal support functions
+"""
+
+import json
+import requests
+import base64
+
+# NGINX Declarative API modules
+from NcgConfig import NcgConfig
+import v5_0.GitOps
+import v5_0.MiscUtils
+
+# pydantic models
+from V5_0_NginxConfigDeclaration import *
+
+def buildDevPortal(openapischema):
+ try:
+ response = requests.post(f"http://{NcgConfig.config['devportal']['host']}:"
+ f"{NcgConfig.config['devportal']['port']}{NcgConfig.config['devportal']['uri']}",
+ headers={'Content-Type': 'application/json'}, data=openapischema)
+ except Exception as e:
+ return 400, ""
+
+ return response.status_code, json.loads(response.text)
+
+
+# Builds the declarative JSON for the API Gateway configuration
+# Return a tuple: status, description. If status = 200 things were successful
+def createDevPortal(locationDeclaration: dict, authProfiles: Authentication={}):
+ if locationDeclaration['apigateway']['openapi_schema']:
+ status, apiSchemaString = v5_0.GitOps.getObjectFromRepo(
+ object = locationDeclaration['apigateway']['openapi_schema'], authProfiles = authProfiles['server'] if 'server' in authProfiles else {}, base64Encode = False)
+
+ if v5_0.MiscUtils.yaml_or_json(apiSchemaString['content']) == 'yaml':
+ # YAML to JSON conversion
+ status, devportalJSON = buildDevPortal(openapischema = v5_0.MiscUtils.yaml_to_json(apiSchemaString['content']))
+ else:
+ status, devportalJSON = buildDevPortal(openapischema = apiSchemaString['content'])
+
+ if status == 200:
+ devportalHTML = base64.b64encode(bytes(devportalJSON['devportal'], 'utf-8')).decode('utf-8')
+ else:
+ devportalHTML = ""
+
+ return status, devportalHTML
\ No newline at end of file
diff --git a/src/v4_1/GitOps.py b/src/v5_0/GitOps.py
similarity index 75%
rename from src/v4_1/GitOps.py
rename to src/v5_0/GitOps.py
index 5a1be5b..3b56ea7 100644
--- a/src/v4_1/GitOps.py
+++ b/src/v5_0/GitOps.py
@@ -6,10 +6,9 @@
import requests
from requests import ReadTimeout, HTTPError, Timeout, ConnectionError, ConnectTimeout
-from typing import List
# pydantic models
-from V4_1_NginxConfigDeclaration import *
+from V5_0_NginxConfigDeclaration import *
# Fetches a URL content
@@ -37,18 +36,27 @@ def getObjectFromRepo(object: ObjectFromSourceOfTruth, authProfiles: Authenticat
headers = {}
# Set server authentication if needed
- if authProfiles and 'server' in authProfiles:
+ if authProfiles and 'server' in authProfiles and len(object['authentication'])>0:
for authP in authProfiles['server']:
if object['authentication'][0]['profile'] == authP['name']:
# Sets up authentication
if authP['type'].lower() == 'token':
+
+ print(f"===> {authP['name']} {authP['token']['username']} {authP['token']['password']}")
+
authToken = authP['token']['token']
authTokenType = authP['token']['type']
- authTokenLocation = authP['token']['location']
if authTokenType.lower() == 'bearer':
headers['Authorization'] = f"Bearer {authToken}"
+ elif authTokenType.lower() == 'basic':
+ authTokenUsername = authP['token']['username']
+ authTokenPassword = base64.b64decode(authP['token']['password']).decode('utf-8')
+
+ headers['Authorization'] = f"Basic {base64.b64encode(str.encode(authTokenUsername + ':' + authTokenPassword)).decode('utf-8')}"
elif authTokenType.lower() == 'header':
+ authTokenLocation = authP['token']['location']
+
headers[authTokenLocation] = authToken
status_code, fetchedContent = __fetchfromsourceoftruth__(url = object['content'], headers = headers)
diff --git a/src/v4_1/MiscUtils.py b/src/v5_0/MiscUtils.py
similarity index 87%
rename from src/v4_1/MiscUtils.py
rename to src/v5_0/MiscUtils.py
index a5ea547..0d8349a 100644
--- a/src/v4_1/MiscUtils.py
+++ b/src/v5_0/MiscUtils.py
@@ -5,6 +5,8 @@
import re
import json
import yaml
+import uuid
+
def getDictKey(_dict: dict, key_lookup: str, separator='.'):
"""
@@ -41,4 +43,11 @@ def yaml_or_json(document: str):
YAML to JSON conversion
"""
def yaml_to_json(document: str):
- return json.dumps(yaml.safe_load(document))
\ No newline at end of file
+ return json.dumps(yaml.safe_load(document))
+
+
+"""
+Returns a unique ID
+"""
+def getuniqueid():
+ return uuid.uuid4()
\ No newline at end of file
diff --git a/src/v4_1/NAPUtils.py b/src/v5_0/NAPUtils.py
similarity index 99%
rename from src/v4_1/NAPUtils.py
rename to src/v5_0/NAPUtils.py
index bdfcea8..0d8ab65 100644
--- a/src/v4_1/NAPUtils.py
+++ b/src/v5_0/NAPUtils.py
@@ -5,7 +5,7 @@
import requests
import json
-import v4_1.GitOps
+import v5_0.GitOps
from fastapi.responses import Response, JSONResponse
@@ -171,7 +171,7 @@ def provisionPolicies(nmsUrl: str, nmsUsername: str, nmsPassword: str, declarati
if p['type'] == 'app_protect':
# Iterates over all policy versions
for policyVersion in p['versions']:
- status, policyBody = v4_1.GitOps.getObjectFromRepo(policyVersion['contents'])
+ status, policyBody = v5_0.GitOps.getObjectFromRepo(policyVersion['contents'])
if status != 200:
return JSONResponse(
diff --git a/src/v5_0/NGINXOneOutput.py b/src/v5_0/NGINXOneOutput.py
new file mode 100644
index 0000000..0d3b2ff
--- /dev/null
+++ b/src/v5_0/NGINXOneOutput.py
@@ -0,0 +1,3 @@
+"""
+Placeholder
+"""
\ No newline at end of file
diff --git a/src/v5_0/NGINXOneUtils.py b/src/v5_0/NGINXOneUtils.py
new file mode 100644
index 0000000..a6dc62b
--- /dev/null
+++ b/src/v5_0/NGINXOneUtils.py
@@ -0,0 +1,28 @@
+"""
+NGINX One support functions
+"""
+
+import requests
+import json
+
+
+# Fetch a cluster ID from NGINX One
+# Return None if not found
+def getClusterId(nOneUrl: str, nOneToken: str, nameSpace: str, clusterName: str):
+ # Retrieve instance group uid
+ print(f"URL {nOneUrl} namespace {nameSpace} cluster {clusterName} token {nOneToken}")
+
+ cluster = requests.get(url=f'{nOneUrl}/api/nginx/one/namespaces/{nameSpace}/clusters',
+ verify=False, headers = {"Authorization": f"Bearer {nOneToken}"})
+
+ if cluster.status_code != 200:
+ return None
+
+ # Get the instance group id
+ igUid = None
+ igJson = json.loads(cluster.text)
+ for i in igJson['items']:
+ if i['name'] == clusterName:
+ igUid = i['object_id']
+
+ return igUid
diff --git a/src/v4_1/NIMUtils.py b/src/v5_0/NIMUtils.py
similarity index 90%
rename from src/v4_1/NIMUtils.py
rename to src/v5_0/NIMUtils.py
index 8472ba7..de1b9a9 100644
--- a/src/v4_1/NIMUtils.py
+++ b/src/v5_0/NIMUtils.py
@@ -5,10 +5,6 @@
import requests
import json
-import v4_1.GitOps
-
-from fastapi.responses import Response, JSONResponse
-
# Fetch an instance group UID from NGINX Instance Manager
# Return None if not found
diff --git a/src/v5_0/NMSOutput.py b/src/v5_0/NMSOutput.py
new file mode 100644
index 0000000..4610a38
--- /dev/null
+++ b/src/v5_0/NMSOutput.py
@@ -0,0 +1,321 @@
+"""
+Output to NGINX Instance Manager
+"""
+
+import base64
+import requests
+import json
+import pickle
+import time
+import schedule
+
+from jinja2 import Environment, FileSystemLoader
+from urllib.parse import urlparse
+from datetime import datetime
+
+import V5_0_CreateConfig
+
+import v5_0.APIGateway
+import v5_0.DevPortal
+import v5_0.DeclarationPatcher
+import v5_0.GitOps
+import v5_0.MiscUtils
+import v5_0.NMSOutput
+
+# pydantic models
+from V5_0_NginxConfigDeclaration import *
+
+# NGINX App Protect helper functions
+import v5_0.NAPUtils
+import v5_0.NIMUtils
+import v5_0.MiscUtils
+
+# NGINX Declarative API modules
+from NcgConfig import NcgConfig
+from NcgRedis import NcgRedis
+
+def NMSOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpConf: str,
+ b64StreamConf: str,configFiles = {}, auxFiles = {},
+ runfromautosync: bool = False,
+ configUid: str = ""):
+ # NGINX Instance Manager Staged Configuration publish
+
+ nmsUsername = v5_0.MiscUtils.getDictKey(d, 'output.nms.username')
+ nmsPassword = v5_0.MiscUtils.getDictKey(d, 'output.nms.password')
+ nmsInstanceGroup = v5_0.MiscUtils.getDictKey(d, 'output.nms.instancegroup')
+ nmsSynctime = v5_0.MiscUtils.getDictKey(d, 'output.nms.synctime')
+
+ nmsUrlFromJson = v5_0.MiscUtils.getDictKey(d, 'output.nms.url')
+ urlCheck = urlparse(nmsUrlFromJson)
+
+ if urlCheck.scheme not in ['http', 'https'] or urlCheck.scheme == "" or urlCheck.netloc == "":
+ return {"status_code": 400,
+ "message": {"status_code": 400, "message": {"code": 400,
+ "content": f"invalid NGINX Instance Manager URL {nmsUrlFromJson}"}},
+ "headers": {'Content-Type': 'application/json'}}
+
+ nmsUrl = f"{urlCheck.scheme}://{urlCheck.netloc}"
+
+ if nmsSynctime < 0:
+ return {"status_code": 400,
+ "message": {"status_code": 400, "message": {"code": 400, "content": "synctime must be >= 0"}},
+ "headers": {'Content-Type': 'application/json'}}
+
+ # Fetch NGINX App Protect WAF policies from source of truth if needed
+ d_policies = v5_0.MiscUtils.getDictKey(d, 'output.nms.policies')
+ if d_policies is not None:
+ for policy in d_policies:
+ if 'versions' in policy:
+ for policyVersion in policy['versions']:
+ status, content = v5_0.GitOps.getObjectFromRepo(object=policyVersion['contents'],
+ authProfiles=d['declaration']['http'][
+ 'authentication'])
+
+ if status != 200:
+ return {"status_code": 422, "message": {"status_code": status, "message": content}}
+
+ policyVersion['contents'] = content
+
+ # Check TLS items validity
+ all_tls = {'certificate': {}, 'key': {}}
+
+ d_certs = v5_0.MiscUtils.getDictKey(d, 'output.nms.certificates')
+ if d_certs is not None:
+ for i in range(len(d_certs)):
+ if d_certs[i]['name']:
+ all_tls[d_certs[i]['type']][d_certs[i]['name']] = True
+
+ d_servers = v5_0.MiscUtils.getDictKey(d, 'declaration.http.servers')
+ if d_servers is not None:
+ for server in d_servers:
+ if server['listen'] is not None:
+ if 'tls' in server['listen']:
+ cert_name = v5_0.MiscUtils.getDictKey(server, 'listen.tls.certificate')
+ if cert_name and cert_name not in all_tls['certificate']:
+ return {"status_code": 422,
+ "message": {
+ "status_code": 422,
+ "message": {"code": 422,
+ "content": "invalid TLS certificate " +
+ cert_name + " for server" + str(
+ server['names'])}
+ }}
+
+ cert_key = v5_0.MiscUtils.getDictKey(server, 'listen.tls.key')
+ if cert_key and cert_key not in all_tls['key']:
+ return {"status_code": 422,
+ "message": {
+ "status_code": 422,
+ "message": {"code": 422,
+ "content": "invalid TLS key " + cert_key + " for server" + str(
+ server['names'])}
+ }}
+
+ trusted_cert_name = v5_0.MiscUtils.getDictKey(server, 'listen.tls.trusted_ca_certificates')
+ if trusted_cert_name and trusted_cert_name not in all_tls['certificate']:
+ return {"status_code": 422,
+ "message": {
+ "status_code": 422,
+ "message": {"code": 422,
+ "content": "invalid trusted CA certificate " +
+ trusted_cert_name + " for server" + str(server['names'])}
+ }}
+
+ # Add optional certificates specified under output.nms.certificates
+ extensions_map = {'certificate': '.crt', 'key': '.key'}
+
+ d_certificates = v5_0.MiscUtils.getDictKey(d, 'output.nms.certificates')
+ if d_certificates is not None:
+ for c in d_certificates:
+ status, certContent = v5_0.GitOps.getObjectFromRepo(object=c['contents'],
+ authProfiles=d['declaration']['http']['authentication'])
+
+ if status != 200:
+ return {"status_code": 422,
+ "message": {"status_code": status, "message": {"code": status, "content": certContent}}}
+
+ newAuxFile = {'contents': certContent['content'], 'name': NcgConfig.config['nms']['certs_dir'] +
+ '/' + c['name'] + extensions_map[c['type']]}
+ auxFiles['files'].append(newAuxFile)
+
+ ### / Add optional certificates specified under output.nms.certificates
+
+ # NGINX main configuration file through template
+ j2_env = Environment(loader=FileSystemLoader(NcgConfig.config['templates']['root_dir'] + '/' + apiversion),
+ trim_blocks=True, extensions=["jinja2_base64_filters.Base64Filters"])
+
+ nginxMainConf = j2_env.get_template(NcgConfig.config['templates']['nginxmain']).render(
+ nginxconf={'modules': v5_0.MiscUtils.getDictKey(d, 'output.nms.modules')})
+
+ # Base64-encoded NGINX main configuration (/etc/nginx/nginx.conf)
+ b64NginxMain = str(base64.urlsafe_b64encode(nginxMainConf.encode("utf-8")), "utf-8")
+
+ # Base64-encoded NGINX mime.types (/etc/nginx/mime.types)
+ f = open(NcgConfig.config['templates']['root_dir'] + '/' + apiversion + '/' + NcgConfig.config['templates'][
+ 'mimetypes'], 'r')
+ nginxMimeTypes = f.read()
+ f.close()
+
+ b64NginxMimeTypes = str(base64.urlsafe_b64encode(nginxMimeTypes.encode("utf-8")), "utf-8")
+ filesMimeType = {'contents': b64NginxMimeTypes, 'name': NcgConfig.config['nms']['config_dir'] + '/mime.types'}
+ auxFiles['files'].append(filesMimeType)
+
+ # Base64-encoded NGINX HTTP service configuration
+ filesNginxMain = {'contents': b64NginxMain, 'name': NcgConfig.config['nms']['config_dir'] + '/nginx.conf'}
+ filesHttpConf = {'contents': b64HttpConf,
+ 'name': NcgConfig.config['nms']['config_dir'] + '/' + NcgConfig.config['nms'][
+ 'staged_config_http_filename']}
+ filesStreamConf = {'contents': b64StreamConf,
+ 'name': NcgConfig.config['nms']['config_dir'] + '/' + NcgConfig.config['nms'][
+ 'staged_config_stream_filename']}
+
+ # Append config files to staged configuration
+ configFiles['files'].append(filesNginxMain)
+ configFiles['files'].append(filesHttpConf)
+ configFiles['files'].append(filesStreamConf)
+
+ # Staged config
+ baseStagedConfig = {'auxFiles': auxFiles, 'configFiles': configFiles}
+ stagedConfig = {'auxFiles': auxFiles, 'configFiles': configFiles,
+ 'updateTime': datetime.utcnow().isoformat()[:-3] + 'Z',
+ 'ignoreConflict': True, 'validateConfig': False}
+
+ currentBaseStagedConfig = NcgRedis.redis.get(f'ncg.basestagedconfig.{configUid}').decode(
+ 'utf-8') if NcgRedis.redis.get(f'ncg.basestagedconfig.{configUid}') else None
+ newBaseStagedConfig = json.dumps(baseStagedConfig)
+
+ if currentBaseStagedConfig is not None and newBaseStagedConfig == currentBaseStagedConfig:
+ print(f'Declaration [{configUid}] not changed')
+ return {"status_code": 200,
+ "message": {"status_code": 200, "message": {"code": 200, "content": "no changes"}}}
+ else:
+ # Configuration objects have changed, publish to NIM needed
+ print(
+ f'Declaration [{configUid}] changed, publishing' if configUid else f'New declaration created, publishing')
+
+ # Get the instance group id
+ igUid = v5_0.NIMUtils.getNIMInstanceGroupUid(nmsUrl=nmsUrl, nmsUsername=nmsUsername,
+ nmsPassword=nmsPassword, instanceGroupName=nmsInstanceGroup)
+
+ # Invalid instance group
+ if igUid is None:
+ return {"status_code": 404,
+ "message": {"status_code": 404, "message": {"code": 404,
+ "content": f"instance group {nmsInstanceGroup} not found"}},
+ "headers": {'Content-Type': 'application/json'}}
+
+ ### NGINX App Protect policies support - commits policies to control plane
+
+ # Check NGINX App Protect WAF policies configuration sanity
+ status, description = v5_0.NAPUtils.checkDeclarationPolicies(d)
+
+ if status != 200:
+ return {"status_code": 422,
+ "message": {"status_code": status, "message": {"code": status, "content": description}},
+ "headers": {'Content-Type': 'application/json'}}
+
+ # Provision NGINX App Protect WAF policies to NGINX Instance Manager
+ provisionedNapPolicies, activePolicyUids = v5_0.NAPUtils.provisionPolicies(
+ nmsUrl=nmsUrl, nmsUsername=nmsUsername, nmsPassword=nmsPassword, declaration=d)
+
+ ### / NGINX App Protect policies support
+
+ ### Publish staged config to instance group
+ r = requests.post(url=nmsUrl + f"/api/platform/v1/instance-groups/{igUid}/config",
+ data=json.dumps(stagedConfig),
+ headers={'Content-Type': 'application/json'},
+ auth=(nmsUsername, nmsPassword),
+ verify=False)
+
+ if r.status_code != 202:
+ # Configuration push failed
+ return {"status_code": r.status_code,
+ "message": {"status_code": r.status_code, "message": r.text},
+ "headers": {'Content-Type': 'application/json'}}
+
+ # Fetch the deployment status
+ publishResponse = json.loads(r.text)
+
+ # Wait for either NIM success or failure after pushing a staged config
+ isPending = True
+ while isPending:
+ time.sleep(NcgConfig.config['nms']['staged_config_publish_waittime'])
+ deploymentCheck = requests.get(url=nmsUrl + publishResponse['links']['rel'],
+ auth=(nmsUsername, nmsPassword),
+ verify=False)
+
+ checkJson = json.loads(deploymentCheck.text)
+
+ if not checkJson['details']['pending']:
+ isPending = False
+
+ if len(checkJson['details']['failure']) > 0:
+ # Staged config publish to NIM failed
+ jsonResponse = checkJson['details']['failure'][0]
+ deploymentCheck.status_code = 422
+ else:
+ # Staged config publish to NIM succeeded
+ jsonResponse = json.loads(deploymentCheck.text)
+
+ # if nmsSynctime > 0 and runfromautosync == False:
+ if runfromautosync == False:
+ # No configuration is found, generate one
+ configUid = str(v5_0.MiscUtils.getuniqueid())
+
+ # Stores the staged config to redis
+ # Redis keys:
+ # ncg.declaration.[configUid] = original config declaration
+ # ncg.declarationrendered.[configUid] = original config declaration - rendered
+ # ncg.basestagedconfig.[configUid] = base staged configuration
+ # ncg.apiversion.[configUid] = ncg API version
+ # ncg.status.[configUid] = latest status
+
+ NcgRedis.redis.set(f'ncg.declaration.{configUid}', pickle.dumps(declaration))
+ NcgRedis.redis.set(f'ncg.declarationrendered.{configUid}', json.dumps(d))
+ NcgRedis.redis.set(f'ncg.basestagedconfig.{configUid}', json.dumps(baseStagedConfig))
+ NcgRedis.redis.set(f'ncg.apiversion.{configUid}', apiversion)
+
+ # Makes NGINX App Protect policies active
+ doWeHavePolicies = v5_0.NAPUtils.makePolicyActive(nmsUrl=nmsUrl, nmsUsername=nmsUsername,
+ nmsPassword=nmsPassword,
+ activePolicyUids=activePolicyUids,
+ instanceGroupUid=igUid)
+
+ if doWeHavePolicies:
+ # Clean up NGINX App Protect WAF policies not used anymore
+ # and not defined in the declaration just pushed
+ time.sleep(NcgConfig.config['nms']['staged_config_publish_waittime'])
+ v5_0.NAPUtils.cleanPolicyLeftovers(nmsUrl=nmsUrl, nmsUsername=nmsUsername,
+ nmsPassword=nmsPassword,
+ currentPolicies=provisionedNapPolicies)
+
+ # If deploying a new configuration in GitOps mode start autosync
+ if nmsSynctime == 0:
+ NcgRedis.declarationsList[configUid] = "static"
+ elif not runfromautosync:
+ # GitOps autosync
+ print(f'Starting autosync for configUid {configUid} every {nmsSynctime} seconds')
+
+ job = schedule.every(nmsSynctime).seconds.do(lambda: V5_0_CreateConfig.configautosync(configUid))
+ # Keep track of GitOps configs, key is the threaded job
+ NcgRedis.declarationsList[configUid] = job
+
+ NcgRedis.redis.set(f'ncg.apiversion.{configUid}', apiversion)
+
+ responseContent = {'code': deploymentCheck.status_code, 'content': jsonResponse, 'configUid': configUid}
+
+ # Configuration push completed, update redis keys
+ if configUid != "":
+ NcgRedis.redis.set('ncg.status.' + configUid, json.dumps(responseContent))
+
+ # if nmsSynctime > 0:
+ # Updates status, declaration and basestagedconfig in redis
+ NcgRedis.redis.set('ncg.declaration.' + configUid, pickle.dumps(declaration))
+ NcgRedis.redis.set('ncg.declarationrendered.' + configUid, json.dumps(d))
+ NcgRedis.redis.set('ncg.basestagedconfig.' + configUid, json.dumps(baseStagedConfig))
+
+ return {"status_code": deploymentCheck.status_code,
+ "message": {"status_code": deploymentCheck.status_code,
+ "message": responseContent},
+ "headers": {'Content-Type': 'application/json'}
+ }
\ No newline at end of file
diff --git a/src/v5_0/OpenAPIParser.py b/src/v5_0/OpenAPIParser.py
new file mode 100644
index 0000000..0e4e355
--- /dev/null
+++ b/src/v5_0/OpenAPIParser.py
@@ -0,0 +1,71 @@
+"""
+OpenAPI schema parser support functions
+"""
+
+import json
+
+class OpenAPIParser:
+ httpMethods = ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'CONNECT', 'OPTIONS', 'TRACE', 'PATCH']
+
+ def __init__(self, openAPISchema):
+ self.openAPISchema = openAPISchema
+
+ def version(self):
+ if 'openapi' in self.openAPISchema:
+ return self.openAPISchema['openapi']
+ elif 'swagger' in self.openAPISchema:
+ return self.openAPISchema['swagger']
+
+ return None
+
+ def info(self):
+ return self.openAPISchema['info']
+
+ def servers(self):
+ self.allServers = []
+
+ # Loop over OpenAPI schema servers
+ if 'servers' in self.openAPISchema:
+ for server in self.openAPISchema['servers']:
+ urlName = server['url']
+ self.s = {}
+ self.s['url'] = urlName
+
+ if 'description' in server:
+ self.s['description'] = server['description']
+
+ self.allServers.append(self.s)
+
+ return self.allServers
+
+ def paths(self):
+ self.allPaths = []
+
+ # Loop over OpenAPI schema paths
+ if 'paths' in self.openAPISchema:
+ for path in self.openAPISchema['paths'].keys():
+ #print(f"- {path}")
+ self.p = {}
+ self.p['path'] = path
+ self.p['methods'] = []
+
+ # Loop over path HTTP methods found in schema
+ for method in self.openAPISchema['paths'][path].keys():
+ methodInfo = self.openAPISchema['paths'][path][method]
+
+ if method.upper() in self.httpMethods:
+ #print(f" - {method} - {methodInfo['description'] if 'description' in methodInfo else ''}")
+ self.m = {}
+ self.m['method'] = method
+ self.m['details'] = {}
+
+ if 'description' in methodInfo and methodInfo['description']:
+ self.m['details']['description'] = methodInfo['description']
+ if 'operationId' in methodInfo and methodInfo['operationId']:
+ self.m['details']['operationId'] = methodInfo['operationId']
+
+ self.p['methods'].append(self.m)
+
+ self.allPaths.append(self.p)
+
+ return self.allPaths
\ No newline at end of file
diff --git a/templates/v4.1/apigateway.tmpl b/templates/v4.1/apigateway.tmpl
deleted file mode 100644
index e69de29..0000000
diff --git a/templates/v4.1/auth/client/jwks.tmpl b/templates/v4.1/auth/client/jwks.tmpl
deleted file mode 100644
index e69de29..0000000
diff --git a/templates/v4.1/auth/client/jwt.tmpl b/templates/v4.1/auth/client/jwt.tmpl
deleted file mode 100644
index e69de29..0000000
diff --git a/templates/v4.1/auth/server/token.tmpl b/templates/v4.1/auth/server/token.tmpl
deleted file mode 100644
index e69de29..0000000
diff --git a/templates/v4.1/configmap.tmpl b/templates/v4.1/configmap.tmpl
deleted file mode 100644
index e69de29..0000000
diff --git a/templates/v4.1/http.tmpl b/templates/v4.1/http.tmpl
deleted file mode 100644
index e69de29..0000000
diff --git a/templates/v4.1/logformat.tmpl b/templates/v4.1/logformat.tmpl
deleted file mode 100644
index e69de29..0000000
diff --git a/templates/v4.1/nginx-conf/mime.types b/templates/v4.1/nginx-conf/mime.types
deleted file mode 100644
index e69de29..0000000
diff --git a/templates/v4.1/nginx-conf/nginx.conf b/templates/v4.1/nginx-conf/nginx.conf
deleted file mode 100644
index e69de29..0000000
diff --git a/templates/v4.1/stream.tmpl b/templates/v4.1/stream.tmpl
deleted file mode 100644
index e69de29..0000000
diff --git a/templates/v5.0/apigateway.tmpl b/templates/v5.0/apigateway.tmpl
new file mode 100644
index 0000000..292c814
--- /dev/null
+++ b/templates/v5.0/apigateway.tmpl
@@ -0,0 +1,138 @@
+{% if declaration.servers %}
+ {# --- OpenAPI schema contains server details --- #}
+ {% if declaration.servers[0].url.lower().startswith('http://') or declaration.servers[0].url.lower().startswith('https://') %}
+ {# --- OpenAPI schema contains a full server URL --- #}
+ {% set destination_server = declaration.servers[0].url %}
+ {% else %}
+ {# --- OpenAPI schema contains a server URI --- #}
+ {% set destination_server = declaration.location.apigateway.api_gateway.server_url + declaration.servers[0].url %}
+ {% endif %}
+{% else %}
+ {# --- OpenAPI schema contains no server details --- #}
+ {% set destination_server = declaration.location.apigateway.api_gateway.server_url %}
+{% endif %}
+
+# API Gateway: {{ declaration.info.title }} {{ declaration.info.version }}
+# OpenAPI version: {{ declaration.version }}
+# Base URI: {{ declaration.location.uri }}
+# Strip base URI: {{ declaration.location.apigateway.api_gateway.strip_uri }}
+# Destination server: {{ destination_server }}
+
+{% if declaration.paths -%}
+{% for path in declaration.paths %}
+location {% if '{' not in path.path %}={% else %}~{% endif %} {{ declaration.location.uri }}{{ path.path | regex_replace('{(.*?)}','(.*)') }} {
+ {% for method in path.methods -%}
+ # {{ method.method|upper }} - operationId: {{ method.details.operationId }}
+ {% endfor -%}
+ {% set method_names = path.methods|map(attribute='method')|list %}
+
+ {% if declaration.location.apigateway.log.access %}access_log {{ declaration.location.apigateway.log.access }} main;{% endif %}
+
+ {% if declaration.location.apigateway.log.error %}error_log {{ declaration.location.apigateway.log.error }};{% endif %}
+
+
+ limit_except {{ method_names|join(' ')|upper }} { deny all; }
+
+ {# --- Rate limiting start --- #}
+ {%- for rl in declaration.location.apigateway.rate_limit -%}
+ {%- set enforceRL = namespace(toBeEnforced = False) -%}
+ {%- if rl.enforceOnPaths == False -%}
+ {%- set enforceRL.toBeEnforced = True -%}
+ {%- endif -%}
+ {%- for rlPath in rl.paths -%}
+ {%- if path.path == rlPath -%}
+ {%- if rl.enforceOnPaths == True -%}
+ {%- set enforceRL.toBeEnforced = True -%}
+ {%- else -%}
+ {%- set enforceRL.toBeEnforced = False -%}
+ {%- endif -%}
+ {%- endif -%}
+ {%- endfor -%}
+
+ {%- if enforceRL.toBeEnforced == True -%}
+ {%- if rl.profile %}limit_req zone={{ rl.profile }}{% if rl.burst %} burst={{ rl.burst }}{% endif %}{% if rl.delay == 0 %} nodelay;{% else %} delay={{ rl.delay }};{% endif %}{% endif %}
+
+ {% if rl.httpcode %}limit_req_status {{ rl.httpcode }};{% endif %}
+ {%- endif -%}
+ {%- endfor -%}
+
+ {# --- Rate limiting end --- #}
+
+
+ {# --- Authentication start --- #}
+ {%- if declaration.location.apigateway.authentication -%}
+ {%- set enforceAuth = namespace(toBeEnforced = False) -%}
+ {%- if declaration.location.apigateway.authentication.enforceOnPaths == False -%}
+ {%- set enforceAuth.toBeEnforced = True -%}
+ {%- endif -%}
+ {%- for authPath in declaration.location.apigateway.authentication.paths -%}
+ {%- if path.path == authPath -%}
+ {%- if declaration.location.apigateway.authentication.enforceOnPaths == True -%}
+ {%- set enforceAuth.toBeEnforced = True -%}
+ {%- else -%}
+ {%- set enforceAuth.toBeEnforced = False -%}
+ {%- endif -%}
+ {%- endif -%}
+ {%- endfor -%}
+
+ {# --- Client authentication --- #}
+ {%- if enforceAuth.toBeEnforced == True -%}
+ {%- if declaration.location.apigateway.authentication and declaration.location.apigateway.authentication.client -%}
+ {%- for clientAuthProfile in declaration.location.apigateway.authentication.client -%}
+ include "{{ ncgconfig.nms.auth_client_dir }}/{{ clientAuthProfile.profile | replace(" ", "_") }}.conf";
+ {% endfor -%}
+ {%- endif -%}
+ {%- endif -%}
+
+ {%- endif %}
+
+ {# --- Authentication end --- #}
+
+
+ {# --- Authorization start --- #}
+ {%- if declaration.location.apigateway.authorization -%}
+ {%- for authZentry in declaration.location.apigateway.authorization %}
+ {%- set enforceAuthZ = namespace(toBeEnforced = False) -%}
+ {%- if authZentry.enforceOnPaths == False -%}
+ {%- set enforceAuthZ.toBeEnforced = True -%}
+ {%- endif -%}
+ {%- for authPath in authZentry.paths -%}
+ {%- if path.path == authPath -%}
+ {%- if authZentry.enforceOnPaths == True -%}
+ {%- set enforceAuthZ.toBeEnforced = True -%}
+ {%- else -%}
+ {%- set enforceAuthZ.toBeEnforced = False -%}
+ {%- endif -%}
+ {%- endif -%}
+ {%- endfor -%}
+
+ {# --- Client authorization --- #}
+ {%- if enforceAuthZ.toBeEnforced == True -%}
+ include "{{ ncgconfig.nms.authz_client_dir }}/{{ authZentry.profile | replace(" ", "_") }}.conf";
+ {%- endif -%}
+
+ {%- endfor -%}
+ {%- endif %}
+
+ {# --- Authorization end --- #}
+
+ {% if declaration.location.apigateway.api_gateway.strip_uri -%}
+ rewrite ^{{ declaration.location.uri }}/(.*)$ /$1 break;
+ {% endif %}
+
+ {% if declaration.location.apigateway.api_gateway.server_url -%}
+ proxy_set_header Host {{ declaration.location.apigateway.api_gateway.server_url.split('://')[1].split('/')[0] }};
+ {% endif -%}
+
+ proxy_pass {{ destination_server }}$uri;
+}
+
+{% endfor %}
+
+{% if declaration.location.apigateway.developer_portal.enabled == True -%}
+location = {{ declaration.location.uri }}{{ declaration.location.apigateway.developer_portal.uri }} {
+ rewrite ^{{ declaration.location.uri }}/(.*)$ /$1 break;
+ root {{ ncgconfig.nms.devportal_dir }};
+}
+{% endif %}
+{% endif %}
diff --git a/templates/v5.0/authn/client/jwks.tmpl b/templates/v5.0/authn/client/jwks.tmpl
new file mode 100644
index 0000000..aea3a35
--- /dev/null
+++ b/templates/v5.0/authn/client/jwks.tmpl
@@ -0,0 +1,11 @@
+location = /_auth/jwt/{{ authprofile.name | replace(" ", "_") }}/_jwks_uri {
+ internal;
+
+ {% if authprofile.jwt.key.startswith('http://') or authprofile.jwt.key.startswith('https://') -%}
+ proxy_method GET;
+ proxy_pass {{ authprofile.jwt.key }};
+ {% else -%}
+ return 200 '{{ authprofile.jwt.key }}';
+ {%- endif %}
+
+}
diff --git a/templates/v5.0/authn/client/jwt.tmpl b/templates/v5.0/authn/client/jwt.tmpl
new file mode 100644
index 0000000..14e9719
--- /dev/null
+++ b/templates/v5.0/authn/client/jwt.tmpl
@@ -0,0 +1,6 @@
+auth_jwt "{{ authprofile.jwt.realm }}"{% if authprofile.jwt.token_location %} token={{ authprofile.jwt.token_location }}{% endif %};
+auth_jwt_type {{ authprofile.jwt.jwt_type }};
+auth_jwt_key_request /_auth/jwt/{{ authprofile.name | replace(" ", "_") }}/_jwks_uri;
+{% if authprofile.jwt.cachetime != 0 %}
+auth_jwt_key_cache {{ authprofile.jwt.cachetime }};
+{% endif %}
diff --git a/templates/v5.0/authn/client/mtls.tmpl b/templates/v5.0/authn/client/mtls.tmpl
new file mode 100644
index 0000000..683facc
--- /dev/null
+++ b/templates/v5.0/authn/client/mtls.tmpl
@@ -0,0 +1,29 @@
+{%- if authprofile.mtls.enabled|lower != "off" -%}
+ssl_verify_client {{ authprofile.mtls.enabled }};
+{% if authprofile.mtls.client_certificates -%}
+ssl_client_certificate {{ ncgconfig.nms.certs_dir }}/{{ authprofile.mtls.client_certificates }}.crt;
+{% endif %}
+
+{% if authprofile.mtls.trusted_ca_certificates -%}
+ssl_trusted_certificate {{ ncgconfig.nms.certs_dir }}/{{ authprofile.mtls.trusted_ca_certificates }}.crt;
+{% endif %}
+
+{# --- OCSP section start --- #}
+{%- if authprofile.mtls.ocsp and authprofile.mtls.ocsp.enabled|lower != "off" -%}
+ssl_ocsp {{ authprofile.mtls.ocsp.enabled }};
+{% if authprofile.mtls.ocsp.responder -%}
+ssl_ocsp_responder {{ authprofile.mtls.ocsp.responder }};
+{% endif %}
+{% endif %}
+{# --- OCSP section end --- #}
+
+{# --- TLS stapling section start --- #}
+{%- if authprofile.mtls.stapling and authprofile.mtls.stapling.enabled == True -%}
+ssl_stapling on;
+ssl_stapling_verify {% if authprofile.mtls.stapling.verify == True %}on{% else %}off{% endif %};
+{% if authprofile.mtls.stapling.responder -%}
+ssl_stapling_responder {{ authprofile.mtls.stapling.responder }};
+{% endif -%}
+{%- endif %}
+{# --- TLS stapling section end --- #}
+{% endif %}
\ No newline at end of file
diff --git a/templates/v5.0/authn/server/mtls.tmpl b/templates/v5.0/authn/server/mtls.tmpl
new file mode 100644
index 0000000..5b0ae18
--- /dev/null
+++ b/templates/v5.0/authn/server/mtls.tmpl
@@ -0,0 +1,2 @@
+proxy_ssl_certificate {{ ncgconfig.nms.certs_dir }}/{{ authprofile.mtls.certificate }}.crt;
+proxy_ssl_certificate_key {{ ncgconfig.nms.certs_dir }}/{{ authprofile.mtls.certificate }}.key;
diff --git a/templates/v5.0/authn/server/token.tmpl b/templates/v5.0/authn/server/token.tmpl
new file mode 100644
index 0000000..7acbd60
--- /dev/null
+++ b/templates/v5.0/authn/server/token.tmpl
@@ -0,0 +1,7 @@
+{% if authprofile.token.type == "bearer" %}
+proxy_set_header Authorization "Bearer {{ authprofile.token.token }}";
+{% elif authprofile.token.type == "basic" %}
+proxy_set_header Authorization "Basic {{ (authprofile.token.username + ':' + (authprofile.token.password | b64decode) ) | b64encode }}";
+{% elif authprofile.token.type == "header" %}
+proxy_set_header {{ authprofile.token.location }} "{{ authprofile.token.token }}";
+{% endif %}
\ No newline at end of file
diff --git a/templates/v5.0/authz/client/jwt-authz-map.tmpl b/templates/v5.0/authz/client/jwt-authz-map.tmpl
new file mode 100644
index 0000000..047da21
--- /dev/null
+++ b/templates/v5.0/authz/client/jwt-authz-map.tmpl
@@ -0,0 +1,14 @@
+{% for claim in authprofile.jwt.claims %}
+auth_jwt_claim_set $authz_match_jwt_claim_{{ claim.name }}_{{ authprofile.name | replace(" ", "_") }} {{ claim.name }};
+{% endfor %}
+
+{% for claim in authprofile.jwt.claims %}
+# JWT claim {{ claim.name }} validation for profile "{{ authprofile.name }}"
+map $authz_match_jwt_claim_{{ claim.name }}_{{ authprofile.name | replace(" ", "_") }} $jwt_authz_claim_{{ claim.name }}_{{ authprofile.name | replace(" ", "_") }} {
+{% for value in claim.value %}
+ "{{ value }}" 1;
+{% endfor %}
+ default 0;
+}
+
+{% endfor %}
\ No newline at end of file
diff --git a/templates/v5.0/authz/client/jwt.tmpl b/templates/v5.0/authz/client/jwt.tmpl
new file mode 100644
index 0000000..f6b4d91
--- /dev/null
+++ b/templates/v5.0/authz/client/jwt.tmpl
@@ -0,0 +1,3 @@
+{% for claim in authprofile.jwt.claims %}
+auth_jwt_require $jwt_authz_claim_{{ claim.name }}_{{ authprofile.name | replace(" ", "_") }} error={{ claim.errorcode }};
+{% endfor %}
\ No newline at end of file
diff --git a/templates/v5.0/configmap.tmpl b/templates/v5.0/configmap.tmpl
new file mode 100644
index 0000000..29c3973
--- /dev/null
+++ b/templates/v5.0/configmap.tmpl
@@ -0,0 +1,13 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: {{ name }}
+ {% if namespace -%}
+ namespace: {{ namespace }}
+ {% endif %}
+
+data:
+ {{ filename }}: |-
+{% filter indent(width = 4) %}
+ {{ nginxconfig }}
+{% endfilter %}
\ No newline at end of file
diff --git a/templates/v5.0/http.tmpl b/templates/v5.0/http.tmpl
new file mode 100644
index 0000000..e62ef0e
--- /dev/null
+++ b/templates/v5.0/http.tmpl
@@ -0,0 +1,418 @@
+# NGINX configuration file - HTTP servers - generated by https://github.com/f5devcentral/NGINX-Declarative-API
+
+{# --- njs import section --- #}
+{% if declaration.njs_profiles %}
+js_path "{{ ncgconfig.nms.njs_dir }}";
+{% for njsp in declaration.njs_profiles %}
+js_import {{ njsp.name | replace(" ", "_") }} from {{ njsp.name | replace(" ", "_") }}.js;
+{% endfor %}
+{% endif %}
+
+{# --- njs functions section - HTTP level --- #}
+{% if declaration.njs %}
+{% for njshook in declaration.njs %}
+{% if njshook.hook.type|lower == "js_set" %}
+{{ njshook.hook.type }} {{ njshook.hook.js_set.variable }} {{ njshook.profile }}.{{ njshook.function }};
+{% elif njshook.hook.type|lower == "js_preload_object" %}
+{{ njshook.hook.type }} {{ njshook.profile }}.{{ njshook.function }} {% if njshook.hook.js_preload_object.file %}from {{ njshook.hook.js_preload_object.file }}{% endif%};
+{% endif %}
+{% endfor %}
+{% endif %}
+
+{# --- Maps section --- #}
+
+{% if declaration.maps %}
+{% for m in declaration.maps %}
+
+map {{ m.match }} {{ m.variable }} {
+ {% for e in m.entries %}
+ {%- if e.keymatch|lower == "exact" %}{% endif -%}
+ {%- if e.keymatch|lower == "regex" %} ~^ {%- endif -%}
+ {%- if e.keymatch|lower == "iregex" %} ~*^ {%- endif -%}
+ {{ e.key }} {{ e.value }};
+ {% endfor -%}
+
+}
+{% endfor %}
+{% endif %}
+
+{# --- Maps section for authorization --- #}
+{%- if declaration.authorization -%}
+variables_hash_bucket_size 512;
+{% for authzprofile in declaration.authorization -%}
+include "{{ ncgconfig.nms.authz_client_dir }}/{{ authzprofile.name | replace(" ", "_") }}.maps.conf";
+{% endfor -%}
+{%- endif -%}
+
+{# --- Snippets section --- #}
+{% if declaration.snippet and declaration.snippet.content %}{{ declaration.snippet.content | b64decode }}{% endif %}
+
+
+{# --- Upstreams section --- #}
+{% if declaration.upstreams %}
+{% for u in declaration.upstreams %}
+{% if u.name %}
+{% if u.origin %}
+upstream {{ u.name }} {
+ zone {{ u.name }} 64k;
+ {% for o in u.origin -%}
+ server {{ o.server }}{% if o.weight %} weight={{ o.weight }}{% endif %}{% if o.max_fails %} max_fails={{ o.max_fails }}{% endif %}{% if o.fail_timeout %} fail_timeout={{ o.fail_timeout }}{% endif %}{% if o.max_conns %} max_conns={{ o.max_conns }}{% endif %}{% if o.slow_start %} slow_start={{ o.slow_start }}{% endif %}{% if o.backup and o.backup == True %} backup{% endif %};
+ {% endfor %}
+
+ {% if u.sticky and u.sticky.cookie and u.sticky.expires and u.sticky.domain and u.sticky.path -%}
+ sticky cookie {{ u.sticky.cookie }}{% if u.sticky.expires %} expires={{ u.sticky.expires }}{% endif %}{% if u.sticky.domain %} domain={{ u.sticky.domain }}{% endif %}{% if u.sticky.path %} path={{ u.sticky.path }}{% endif %};
+ {% endif -%}
+
+ {% if u.snippet and u.snippet.content %}{{ u.snippet.content | b64decode }}{% endif %}
+
+}
+{% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}
+
+{# --- Rate limit section --- #}
+
+{% if declaration.rate_limit %}
+{% for rl in declaration.rate_limit %}
+limit_req_zone {{ rl.key }} zone={{ rl.name }}:{{ rl.size }} rate={{ rl.rate }};
+{% endfor %}
+{% endif %}
+
+{# --- Server section for NGINX Plus API --- #}
+
+{% if declaration.nginx_plus_api %}
+{% if declaration.nginx_plus_api.listen %}
+server {
+ listen {{ declaration.nginx_plus_api.listen }};
+
+ location /api {
+ {% if declaration.nginx_plus_api.write == True %}api write=on;{% else %}api write=off;{% endif %}
+
+ {% if declaration.nginx_plus_api.allow_acl -%}
+ allow {{ declaration.nginx_plus_api.allow_acl }};
+ deny all;
+ {% else %}
+ allow all;
+ {% endif %}
+
+ }
+
+ location / {
+ root /usr/share/nginx/html;
+ index dashboard.html;
+ }
+}
+{% endif %}
+{% endif %}
+
+{# --- Server section --- #}
+
+{% for s in declaration.servers %}
+server {
+ # {{ s.name }}
+ {# --- Listen section start --- #}
+ {%- if s.listen -%}
+ {% if s.listen.address %}
+
+ listen {{ s.listen.address }}{% if s.listen.tls and s.listen.tls.certificate %} ssl{% endif %};
+ {% if s.listen.http2 and s.listen.http2 == True -%}http2 on;{% endif -%}
+ {%- endif %}
+
+ {# --- TLS section start --- #}
+ {%- if s.listen.tls -%}
+
+ {%- if s.listen.tls.certificate -%}
+ ssl_certificate {{ ncgconfig.nms.certs_dir }}/{{ s.listen.tls.certificate }}.crt;
+ {% endif -%}
+ {%- if s.listen.tls.key -%}
+ ssl_certificate_key {{ ncgconfig.nms.certs_dir }}/{{ s.listen.tls.key }}.key;
+ {% endif -%}
+ {% if s.listen.tls.ciphers -%}
+ ssl_ciphers {{ s.listen.tls.ciphers }};
+ {% endif -%}
+ {% if s.listen.tls.protocols -%}
+ ssl_protocols{% for p in s.listen.tls.protocols %} {{ p }}{% endfor %};
+ {% endif -%}
+
+ {# --- client authentication section --- #}
+ {%- if s.listen.tls and s.listen.tls.authentication and s.listen.tls.authentication.client[0] and s.listen.tls.authentication.client[0].profile -%}
+ include "{{ ncgconfig.nms.auth_client_dir }}/{{ s.listen.tls.authentication.client[0].profile | replace(" ", "_") }}.conf";
+ {% endif %}
+
+ {%- endif %}
+ {# --- TLS section end --- #}
+
+ {%- endif -%}
+ {# --- Listen section end --- #}
+
+ {# --- njs functions section start - server level --- #}
+ {%- if s.njs -%}
+ {%- for njshook in s.njs -%}
+ {% if njshook.hook.type|lower == "js_set" %}
+ {{ njshook.hook.type }} {{ njshook.hook.js_set.variable }} {{ njshook.profile }}.{{ njshook.function }};
+ {% elif njshook.hook.type|lower == "js_preload_object" %}
+ {{ njshook.hook.type }} {{ njshook.profile }}.{{ njshook.function }} {% if njshook.hook.js_preload_object.file %}from {{ njshook.hook.js_preload_object.file }}{% endif%};
+ {% elif njshook.hook.type|lower == "js_periodic" %}
+ {{ njshook.hook.type }} {{ njshook.profile }}.{{ njshook.function }} {% if njshook.hook.js_periodic.interval %}interval={{ njshook.hook.js_periodic.interval }}{% endif%} {% if njshook.hook.js_periodic.jitter %}interval={{ njshook.hook.js_periodic.jitter }}{% endif%} {% if njshook.hook.js_periodic.worker_affinity %}interval={{ njshook.hook.js_periodic.worker_affinity }}{% endif%};
+ {% elif njshook.hook.type|lower == "js_body_filter" %}
+ {{ njshook.hook.type }} {{ njshook.profile }}.{{ njshook.function }} {% if njshook.hook.js_body_filter.buffer_type %}{{ njshook.hook.js_body_filter.buffer_type }}{% endif%};
+ {% elif njshook.hook.type|lower == "js_header_filter" %}
+ {{ njshook.hook.type }} {{ njshook.profile }}.{{ njshook.function }};
+ {% elif njshook.hook.type|lower == "js_content" %}
+ {{ njshook.hook.type }} {{ njshook.profile }}.{{ njshook.function }};
+ {% endif %}
+ {%- endfor -%}
+ {%- endif -%}
+
+ {# --- njs functions section end - server level --- #}
+
+ {% if s.names -%}
+ server_name{% for svrname in s.names %} {{ svrname }}{% endfor -%};
+ status_zone {{ s.names[0] }};
+ proxy_ssl_server_name on;
+ {% endif -%}
+
+ {% if s.resolver -%}
+ resolver {{ s.resolver }};
+ {% endif -%}
+
+ {# --- Server NGINX App Protect WAF section start --- #}
+
+ {% if s.app_protect -%}
+ {% if s.app_protect.enabled == True -%}
+ app_protect_enable on;
+ {% endif -%}
+ {% if s.app_protect.policy -%}
+ app_protect_policy_file {{ ncgconfig.nms.nap_policies_dir_pum }}/{{ s.app_protect.policy }}.tgz;
+ {% endif -%}
+ {%- if s.app_protect.log -%}
+ {%- if s.app_protect.log.enabled == True -%}
+ app_protect_security_log_enable on;
+ {%- if s.app_protect.log.profile_name -%}
+ app_protect_security_log "{{ ncgconfig.nms.nap_logformats_dir_pum }}/{{ s.app_protect.log.profile_name }}.tgz" syslog:server={{ s.app_protect.log.destination }};
+ {% endif -%}
+ {% endif %}
+ {% endif %}
+ {% endif %}
+ {# --- Server NGINX App Protect WAF section end --- #}
+
+ {# --- HTTP headers manipulation section start --- #}
+ {%- if s.headers -%}
+ {%- if s.headers.to_server -%}
+
+ {%- if s.headers.to_server.set -%}
+
+ {%- for hSet in s.headers.to_server.set -%}
+ proxy_set_header {{ hSet.name }} "{{ hSet.value }}";
+ {% endfor -%}
+ {%- endif %}
+ {% if s.headers.to_server.delete -%}
+ {% for hDel in s.headers.to_server.delete -%}
+ proxy_set_header {{ hDel }} "";
+ {% endfor -%}
+ {% endif -%}
+
+ {% endif %}
+
+ {% if s.headers.to_client -%}
+
+ {% if s.headers.to_client.add -%}
+ {% for hAdd in s.headers.to_client.add -%}
+ add_header {{ hAdd.name }} "{{ hAdd.value }}";
+ {% endfor %}
+ {% endif %}
+
+ {% if s.headers.to_client.delete -%}
+ {% for hDel in s.headers.to_client.delete -%}
+ proxy_hide_header {{ hDel }};
+ {% endfor %}
+ {% endif %}
+
+ {% if s.headers.to_client.replace -%}
+ {% for hDel in s.headers.to_client.replace -%}
+ proxy_hide_header {{ hDel.name }};
+ add_header {{ hDel.name }} "{{ hDel.value }}";
+ {% endfor %}
+ {% endif %}
+
+ {% endif %}
+ {% endif %}
+
+ {# --- HTTP headers manipulation section end --- #}
+
+ {% if s.log.access %}access_log {{ s.log.access }} main;{% endif %}
+
+ {% if s.log.error %}error_log {{ s.log.error }};{% endif %}
+
+ {# --- Client authentication at server {} level --- #}
+ {%- if s.authentication and s.authentication.client -%}
+ {%- for clientAuthProfile in s.authentication.client -%}
+ include "{{ ncgconfig.nms.auth_client_dir }}/{{ clientAuthProfile.profile | replace(" ", "_") }}.conf";
+ {% endfor -%}
+ {%- endif -%}
+
+ {# --- Client authorization at server {} level --- #}
+ {%- if s.authorization and s.authorization.profile -%}
+ include "{{ ncgconfig.nms.authz_client_dir }}/{{ s.authorization.profile | replace(" ", "_") }}.conf";
+ {%- endif -%}
+
+ {% filter indent(width=4) %}
+{% if s.snippet and s.snippet.content %}{{ s.snippet.content | b64decode }}{% endif %}
+ {% endfilter %}
+
+ {# --- Server location section start --- #}
+ {% for loc in s.locations %}
+
+ location
+ {%- if loc.urimatch -%}
+ {# location URI match types: prefix (default), exact (=), casesens_regex (~), caseinsens_regex (~*), best_nonregex (^~) #}
+ {%- if loc.urimatch|lower == "prefix" %} {% endif %}
+ {%- if loc.urimatch|lower == "exact" %} = {% endif %}
+ {%- if loc.urimatch|lower == "regex" %} ~ {% endif %}
+ {%- if loc.urimatch|lower == "iregex" %} ~* {% endif %}
+ {%- if loc.urimatch|lower == "best" %} ^~ {% endif %}
+ {%- endif -%}
+ {{ loc.uri }} {
+ {% if loc.authentication and loc.authentication.server and loc.authentication.server[0].profile -%}
+ include "{{ ncgconfig.nms.auth_server_dir }}/{{ loc.authentication.server[0].profile | replace(" ", "_") }}.conf";
+ {% endif %}
+
+ {% if loc.upstream %}proxy_pass {{ loc.upstream }};{% endif %}
+
+ {% if loc.log.access %}access_log {{ loc.log.access }} main;{% endif %}
+
+ {% if loc.log.error %}error_log {{ loc.log.error }};{% endif %}
+
+ {# --- Active healthchecks --- #}
+
+ {% if loc.health_check -%}
+ {% if loc.health_check.enabled == True -%}
+ health_check{% if loc.health_check.uri %} uri={{ loc.health_check.uri }}{% endif %}{% if loc.health_check.interval %} interval={{ loc.health_check.interval }}{% endif %}{% if loc.health_check.fails %} fails={{ loc.health_check.fails }}{% endif %}{% if loc.health_check.passes %} passes={{ loc.health_check.passes }}{% endif %};
+ {% endif %}
+ {% endif %}
+
+ {# --- njs functions section start - location level --- #}
+ {%- if loc.njs -%}
+ {%- for njshook in loc.njs -%}
+ {% if njshook.hook.type|lower == "js_set" %}
+ {{ njshook.hook.type }} {{ njshook.hook.js_set.variable }} {{ njshook.profile }}.{{ njshook.function }};
+ {% elif njshook.hook.type|lower == "js_preload_object" %}
+ {{ njshook.hook.type }} {{ njshook.profile }}.{{ njshook.function }} {% if njshook.hook.js_preload_object.file %}from {{ njshook.hook.js_preload_object.file }}{% endif%};
+ {% elif njshook.hook.type|lower == "js_periodic" %}
+ {{ njshook.hook.type }} {{ njshook.profile }}.{{ njshook.function }} {% if njshook.hook.js_periodic.interval %}interval={{ njshook.hook.js_periodic.interval }}{% endif%} {% if njshook.hook.js_periodic.jitter %}interval={{ njshook.hook.js_periodic.jitter }}{% endif%} {% if njshook.hook.js_periodic.worker_affinity %}interval={{ njshook.hook.js_periodic.worker_affinity }}{% endif%};
+ {% elif njshook.hook.type|lower == "js_body_filter" %}
+ {{ njshook.hook.type }} {{ njshook.profile }}.{{ njshook.function }} {% if njshook.hook.js_body_filter.buffer_type %}{{ njshook.hook.js_body_filter.buffer_type }}{% endif%};
+ {% elif njshook.hook.type|lower == "js_header_filter" %}
+ {{ njshook.hook.type }} {{ njshook.profile }}.{{ njshook.function }};
+ {% elif njshook.hook.type|lower == "js_content" %}
+ {{ njshook.hook.type }} {{ njshook.profile }}.{{ njshook.function }};
+ {% endif %}
+ {%- endfor -%}
+ {%- endif -%}
+
+ {# --- njs functions section end - server level --- #}
+
+ {# --- HTTP headers manipulation section @ location start --- #}
+ {%- if loc.headers -%}
+ {% if loc.headers.to_server -%}
+
+ {% if loc.headers.to_server.set -%}
+ {% for hSet in loc.headers.to_server.set -%}
+ proxy_set_header {{ hSet.name }} "{{ hSet.value }}";
+ {% endfor %}
+ {% endif %}
+
+ {% if loc.headers.to_server.delete -%}
+ {% for hDel in loc.headers.to_server.delete -%}
+ proxy_set_header {{ hDel }} "";
+ {% endfor %}
+ {% endif %}
+
+ {% endif %}
+
+ {% if loc.headers.to_client -%}
+
+ {% if loc.headers.to_client.add -%}
+ {% for hAdd in loc.headers.to_client.add -%}
+ add_header {{ hAdd.name }} "{{ hAdd.value }}";
+ {% endfor %}
+ {% endif %}
+
+ {% if loc.headers.to_client.delete -%}
+ {% for hDel in loc.headers.to_client.delete -%}
+ proxy_hide_header {{ hDel }};
+ {% endfor %}
+ {% endif %}
+
+ {% if loc.headers.to_client.replace -%}
+ {% for hDel in loc.headers.to_client.replace -%}
+ proxy_hide_header {{ hDel.name }};
+ add_header {{ hDel.name }} "{{ hDel.value }}";
+ {% endfor %}
+ {% endif %}
+
+ {% endif %}
+ {% endif %}
+ {# --- HTTP headers manipulation section @ location end --- #}
+
+ {# --- Rate limiting --- #}
+
+ {% if loc.rate_limit -%}
+ {% if loc.rate_limit.profile %}limit_req zone={{ loc.rate_limit.profile }}{% if loc.rate_limit.burst %} burst={{ loc.rate_limit.burst }}{% endif %}{% if loc.rate_limit.delay == 0 %} nodelay;{% else %} delay={{ loc.rate_limit.delay }};{% endif %}
+
+ {% if loc.rate_limit.httpcode %}limit_req_status {{ loc.rate_limit.httpcode }};{% endif %}{% endif %}
+ {% endif %}
+
+ {# --- Client authentication at location level --- #}
+ {%- if loc.authentication and loc.authentication.client -%}
+ {%- for clientAuthProfile in loc.authentication.client -%}
+ include "{{ ncgconfig.nms.auth_client_dir }}/{{ clientAuthProfile.profile | replace(" ", "_") }}.conf";
+ {% endfor -%}
+ {%- endif -%}
+
+ {# --- Client authorization at location level --- #}
+ {%- if loc.authorization and loc.authorization.profile -%}
+ include "{{ ncgconfig.nms.authz_client_dir }}/{{ loc.authorization.profile | replace(" ", "_") }}.conf";
+ {%- endif -%}
+
+ {# --- Location NGINX App Protect WAF --- #}
+
+ {% if loc.app_protect -%}
+ {% if loc.app_protect.enabled == True -%}
+ app_protect_enable on;
+ {% endif -%}
+ {% if loc.app_protect.policy -%}
+ app_protect_policy_file {{ ncgconfig.nms.nap_policies_dir_pum }}/{{ loc.app_protect.policy }}.tgz;
+ {% endif %}
+ {% if loc.app_protect.log -%}
+ {%- if loc.app_protect.log.enabled == True -%}
+ app_protect_security_log_enable on;
+ {% if loc.app_protect.log.profile_name -%}
+ app_protect_security_log "{{ ncgconfig.nms.nap_logformats_dir_pum }}/{{ loc.app_protect.log.profile_name }}.tgz" syslog:server={{ loc.app_protect.log.destination }};
+ {% endif %}
+ {% endif %}
+ {% endif %}
+ {% endif %}
+
+ {% if loc.apigateway and loc.apigateway.api_gateway.enabled == True %}
+ include "{{ ncgconfig.nms.apigw_dir }}{{ loc.uri }}.conf";
+ {% endif %}
+
+ {# --- Location snippets --- #}
+ {% if loc.snippet and loc.snippet.content %}{{ loc.snippet.content | b64decode }}{% endif %}
+
+ }
+ {% endfor %}
+
+ {# --- JWT authentication JWKS endpoints --- #}
+ {%- if declaration.authentication and declaration.authentication.client -%}
+ {%- for clientAuthProfile in declaration.authentication.client -%}
+ {%- if clientAuthProfile.type == "jwt" -%}
+ include "{{ ncgconfig.nms.auth_client_dir }}/jwks_{{ clientAuthProfile.name | replace(" ", "_") }}.conf";
+ {% endif -%}
+ {%- endfor -%}
+ {%- endif %}
+
+}
+{% endfor -%}
\ No newline at end of file
diff --git a/templates/v5.0/logformat.tmpl b/templates/v5.0/logformat.tmpl
new file mode 100644
index 0000000..db9863e
--- /dev/null
+++ b/templates/v5.0/logformat.tmpl
@@ -0,0 +1,12 @@
+{
+ "filter": {
+ "request_type": "{{ log.type }}"
+ },
+
+ "content": {
+ "format": "{{ log.format }}",
+ "format_string": "{{ log.format_string }}",
+ "max_request_size": "{{ log.max_request_size }}",
+ "max_message_size": "{{ log.max_message_size }}"
+ }
+}
diff --git a/templates/v5.0/nginx-conf/mime.types b/templates/v5.0/nginx-conf/mime.types
new file mode 100644
index 0000000..d4e08df
--- /dev/null
+++ b/templates/v5.0/nginx-conf/mime.types
@@ -0,0 +1,97 @@
+types {
+ text/html html htm shtml;
+ text/css css;
+ text/xml xml;
+ image/gif gif;
+ image/jpeg jpeg jpg;
+ application/javascript js;
+ application/atom+xml atom;
+ application/rss+xml rss;
+
+ text/mathml mml;
+ text/plain txt;
+ text/vnd.sun.j2me.app-descriptor jad;
+ text/vnd.wap.wml wml;
+ text/x-component htc;
+
+ image/png png;
+ image/svg+xml svg svgz;
+ image/tiff tif tiff;
+ image/vnd.wap.wbmp wbmp;
+ image/webp webp;
+ image/x-icon ico;
+ image/x-jng jng;
+ image/x-ms-bmp bmp;
+
+ font/woff woff;
+ font/woff2 woff2;
+
+ application/java-archive jar war ear;
+ application/json json;
+ application/mac-binhex40 hqx;
+ application/msword doc;
+ application/pdf pdf;
+ application/postscript ps eps ai;
+ application/rtf rtf;
+ application/vnd.apple.mpegurl m3u8;
+ application/vnd.google-earth.kml+xml kml;
+ application/vnd.google-earth.kmz kmz;
+ application/vnd.ms-excel xls;
+ application/vnd.ms-fontobject eot;
+ application/vnd.ms-powerpoint ppt;
+ application/vnd.oasis.opendocument.graphics odg;
+ application/vnd.oasis.opendocument.presentation odp;
+ application/vnd.oasis.opendocument.spreadsheet ods;
+ application/vnd.oasis.opendocument.text odt;
+ application/vnd.openxmlformats-officedocument.presentationml.presentation
+ pptx;
+ application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
+ xlsx;
+ application/vnd.openxmlformats-officedocument.wordprocessingml.document
+ docx;
+ application/vnd.wap.wmlc wmlc;
+ application/wasm wasm;
+ application/x-7z-compressed 7z;
+ application/x-cocoa cco;
+ application/x-java-archive-diff jardiff;
+ application/x-java-jnlp-file jnlp;
+ application/x-makeself run;
+ application/x-perl pl pm;
+ application/x-pilot prc pdb;
+ application/x-rar-compressed rar;
+ application/x-redhat-package-manager rpm;
+ application/x-sea sea;
+ application/x-shockwave-flash swf;
+ application/x-stuffit sit;
+ application/x-tcl tcl tk;
+ application/x-x509-ca-cert der pem crt;
+ application/x-xpinstall xpi;
+ application/xhtml+xml xhtml;
+ application/xspf+xml xspf;
+ application/zip zip;
+
+ application/octet-stream bin exe dll;
+ application/octet-stream deb;
+ application/octet-stream dmg;
+ application/octet-stream iso img;
+ application/octet-stream msi msp msm;
+
+ audio/midi mid midi kar;
+ audio/mpeg mp3;
+ audio/ogg ogg;
+ audio/x-m4a m4a;
+ audio/x-realaudio ra;
+
+ video/3gpp 3gpp 3gp;
+ video/mp2t ts;
+ video/mp4 mp4;
+ video/mpeg mpeg mpg;
+ video/quicktime mov;
+ video/webm webm;
+ video/x-flv flv;
+ video/x-m4v m4v;
+ video/x-mng mng;
+ video/x-ms-asf asx asf;
+ video/x-ms-wmv wmv;
+ video/x-msvideo avi;
+}
\ No newline at end of file
diff --git a/templates/v5.0/nginx-conf/nginx.conf b/templates/v5.0/nginx-conf/nginx.conf
new file mode 100644
index 0000000..6ee69c9
--- /dev/null
+++ b/templates/v5.0/nginx-conf/nginx.conf
@@ -0,0 +1,40 @@
+user nginx;
+worker_processes auto;
+
+error_log /var/log/nginx/error.log notice;
+pid /var/run/nginx.pid;
+
+{% for m in nginxconf.modules %}
+load_module modules/{{m}}.so;
+{% endfor %}
+
+events {
+ worker_connections 1024;
+}
+
+http {
+ include /etc/nginx/mime.types;
+ default_type application/octet-stream;
+
+ log_format main '$remote_addr - $remote_user [$time_local] "$request" '
+ '$status $body_bytes_sent "$http_referer" '
+ '"$http_user_agent" "$http_x_forwarded_for"';
+
+ access_log /var/log/nginx/access.log main;
+
+ sendfile on;
+ #tcp_nopush on;
+ keepalive_timeout 65;
+ #gzip on;
+ include /etc/nginx/conf.d/*.conf;
+}
+
+
+# TCP/UDP proxy and load balancing block
+stream {
+ log_format stream-main '$remote_addr [$time_local] '
+ '$protocol $status $bytes_sent $bytes_received '
+ '$session_time "$ssl_preread_server_name"';
+ #access_log /dev/stdout stream-main;
+ include /etc/nginx/stream-conf.d/*.conf;
+}
\ No newline at end of file
diff --git a/templates/v5.0/stream.tmpl b/templates/v5.0/stream.tmpl
new file mode 100644
index 0000000..3ae64f0
--- /dev/null
+++ b/templates/v5.0/stream.tmpl
@@ -0,0 +1,66 @@
+# NGINX configuration file - Stream servers - generated by https://github.com/f5devcentral/NGINX-Declarative-API
+
+{# --- Upstreams section --- #}
+
+{% if declaration.upstreams %}
+{% for u in declaration.upstreams %}
+{% if u.name %}
+{% if u.origin %}
+upstream {{ u.name }} {
+ zone {{ u.name }} 64k;
+ {% for o in u.origin -%}
+ server {{ o.server }}{% if o.weight %} weight={{ o.weight }}{% endif %}{% if o.max_fails %} max_fails={{ o.max_fails }}{% endif %}{% if o.fail_timeout %} fail_timeout={{ o.fail_timeout }}{% endif %}{% if o.max_conns %} max_conns={{ o.max_conns }}{% endif %}{% if o.slow_start %} slow_start={{ o.slow_start }}{% endif %}{% if o.backup and o.backup == True %} backup{% endif %};
+ {% endfor %}
+
+ {% if u.snippet and u.snippet.content %}{{ u.snippet.content }}{% endif %}
+
+}
+{% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}
+
+
+{# --- Stream server section --- #}
+
+{% for s in declaration.servers %}
+ {%- if s.listen %}
+ {% if s.listen.address %}
+
+server {
+ listen {{ s.listen.address }}{% if s.listen.protocol == "udp" %} {{ s.listen.protocol }}{% endif %};
+ status_zone {{ s.name }};
+ {% endif -%}
+ {% endif -%}
+
+
+ {# --- TLS section --- #}
+ {%- if s.listen.tls -%}
+ {%- if s.listen.tls.certificate -%}
+ ssl_certificate {{ ncgconfig.nms.certs_dir }}/{{ s.listen.tls.certificate }}.crt;
+ {% endif -%}
+ {%- if s.listen.tls.key -%}
+ ssl_certificate_key {{ ncgconfig.nms.certs_dir }}/{{ s.listen.tls.key }}.key;
+ {% endif -%}
+ {% if s.listen.tls.ciphers -%}
+ ssl_ciphers {{ s.listen.tls.ciphers }};
+ {% endif -%}
+ {% if s.listen.tls.protocols -%}
+ ssl_protocols{% for p in s.listen.tls.protocols %} {{ p }}{% endfor %};
+ {% endif %}
+ {% endif %}
+
+ {% if s.upstream -%}
+ proxy_pass {{ s.upstream }};
+ {% endif %}
+
+ {% if s.snippet and s.snippet.content %}{{ s.snippet.content | b64decode }}{% endif %}
+
+ {%- if s.listen %}
+ {%- if s.listen.address %}
+
+}
+ {% endif -%}
+ {% endif -%}
+
+{%- endfor %}