From c346d84a4f820b4e1cf129d0e48ea8789b9e7249 Mon Sep 17 00:00:00 2001 From: Fabrizio Fiorucci Date: Tue, 21 Apr 2026 14:30:09 +0100 Subject: [PATCH 01/12] v5.6 initial commit --- .gitignore | 2 +- README.md | 6 +- USAGE-v5.4.md | 67 - .../{v5.4 => v5.6}/NginxDefaultPolicy.json | 0 .../{v5.4 => v5.6}/apigw.nginx.lab.crt | 0 .../{v5.4 => v5.6}/apigw.nginx.lab.key | 0 .../{v5.4 => v5.6}/client.cert.pem | 0 .../{v5.4 => v5.6}/client.key.pem | 0 .../nap-policy-xss-allowed.json | 0 .../nap-policy-xss-blocked-bot-allowed.json | 0 .../nap-policy-xss-blocked.json | 0 .../{v5.4 => v5.6}/testcert.chain | 0 .../{v5.4 => v5.6}/testcert.crt | 0 .../{v5.4 => v5.6}/testcert.key | 0 .../{v5.4 => v5.6}/testcert2.chain | 0 .../{v5.4 => v5.6}/testcert2.crt | 0 .../{v5.4 => v5.6}/testcert2.key | 0 etc/config.toml | 2 +- openapi.json | 6686 ----------------- src/V5_4_CreateConfig.py | 898 --- src/V5_4_NginxConfigDeclaration.py | 1038 --- src/main.py | 109 +- src/v5_4/APIGateway.py | 37 - src/v5_4/Asynchronous.py | 36 - src/v5_4/DeclarationPatcher.py | 238 - src/v5_4/DevPortal.py | 46 - src/v5_4/GitOps.py | 83 - src/v5_4/MiscUtils.py | 67 - src/v5_4/NGINXOneNAPUtils.py | 256 - src/v5_4/NGINXOneOutput.py | 379 - src/v5_4/NGINXOneUtils.py | 32 - src/v5_4/NIMNAPUtils.py | 272 - src/v5_4/NIMOutput.py | 370 - src/v5_4/NIMUtils.py | 26 - src/v5_4/OpenAPIParser.py | 73 - src/v5_5/NGINXOneNAPUtils.py | 4 +- src/v5_5/NGINXOneOutput.py | 8 +- src/v5_5/NIMNAPUtils.py | 4 +- templates/v5.4/apigateway.tmpl | 182 - templates/v5.4/authn/client/jwks.tmpl | 11 - templates/v5.4/authn/client/jwt.tmpl | 6 - templates/v5.4/authn/client/mtls.tmpl | 29 - templates/v5.4/authn/client/oidc.tmpl | 47 - templates/v5.4/authn/server/mtls.tmpl | 2 - templates/v5.4/authn/server/token.tmpl | 7 - .../v5.4/authz/client/jwt-authz-map.tmpl | 14 - templates/v5.4/authz/client/jwt.tmpl | 3 - templates/v5.4/devportal/backstage.tmpl | 17 - templates/v5.4/http.tmpl | 140 - templates/v5.4/logformat.tmpl | 12 - templates/v5.4/misc/acme.tmpl | 21 - templates/v5.4/misc/resolver.tmpl | 4 - templates/v5.4/misc/server-http.tmpl | 359 - templates/v5.4/misc/server-stream.tmpl | 43 - templates/v5.4/misc/upstream-http.tmpl | 23 - templates/v5.4/misc/upstream-stream.tmpl | 19 - templates/v5.4/nginx-conf/license-key.tmpl | 1 - templates/v5.4/nginx-conf/mime.types | 97 - templates/v5.4/nginx-conf/nginx.conf | 65 - templates/v5.4/stream.tmpl | 17 - templates/v5.4/visibility/moesif/http.tmpl | 14 - templates/v5.4/visibility/moesif/server.tmpl | 21 - webui/IMPLEMENTATION.md | 1 - 63 files changed, 75 insertions(+), 11819 deletions(-) delete mode 100644 USAGE-v5.4.md rename contrib/gitops-examples/{v5.4 => v5.6}/NginxDefaultPolicy.json (100%) rename contrib/gitops-examples/{v5.4 => v5.6}/apigw.nginx.lab.crt (100%) rename contrib/gitops-examples/{v5.4 => v5.6}/apigw.nginx.lab.key (100%) rename contrib/gitops-examples/{v5.4 => v5.6}/client.cert.pem (100%) rename contrib/gitops-examples/{v5.4 => v5.6}/client.key.pem (100%) rename contrib/gitops-examples/{v5.4 => v5.6}/nap-policy-xss-allowed.json (100%) rename contrib/gitops-examples/{v5.4 => v5.6}/nap-policy-xss-blocked-bot-allowed.json (100%) rename contrib/gitops-examples/{v5.4 => v5.6}/nap-policy-xss-blocked.json (100%) rename contrib/gitops-examples/{v5.4 => v5.6}/testcert.chain (100%) rename contrib/gitops-examples/{v5.4 => v5.6}/testcert.crt (100%) rename contrib/gitops-examples/{v5.4 => v5.6}/testcert.key (100%) rename contrib/gitops-examples/{v5.4 => v5.6}/testcert2.chain (100%) rename contrib/gitops-examples/{v5.4 => v5.6}/testcert2.crt (100%) rename contrib/gitops-examples/{v5.4 => v5.6}/testcert2.key (100%) delete mode 100644 openapi.json delete mode 100644 src/V5_4_CreateConfig.py delete mode 100644 src/V5_4_NginxConfigDeclaration.py delete mode 100644 src/v5_4/APIGateway.py delete mode 100644 src/v5_4/Asynchronous.py delete mode 100644 src/v5_4/DeclarationPatcher.py delete mode 100644 src/v5_4/DevPortal.py delete mode 100644 src/v5_4/GitOps.py delete mode 100644 src/v5_4/MiscUtils.py delete mode 100644 src/v5_4/NGINXOneNAPUtils.py delete mode 100644 src/v5_4/NGINXOneOutput.py delete mode 100644 src/v5_4/NGINXOneUtils.py delete mode 100644 src/v5_4/NIMNAPUtils.py delete mode 100644 src/v5_4/NIMOutput.py delete mode 100644 src/v5_4/NIMUtils.py delete mode 100644 src/v5_4/OpenAPIParser.py delete mode 100644 templates/v5.4/apigateway.tmpl delete mode 100644 templates/v5.4/authn/client/jwks.tmpl delete mode 100644 templates/v5.4/authn/client/jwt.tmpl delete mode 100644 templates/v5.4/authn/client/mtls.tmpl delete mode 100644 templates/v5.4/authn/client/oidc.tmpl delete mode 100644 templates/v5.4/authn/server/mtls.tmpl delete mode 100644 templates/v5.4/authn/server/token.tmpl delete mode 100644 templates/v5.4/authz/client/jwt-authz-map.tmpl delete mode 100644 templates/v5.4/authz/client/jwt.tmpl delete mode 100644 templates/v5.4/devportal/backstage.tmpl delete mode 100644 templates/v5.4/http.tmpl delete mode 100644 templates/v5.4/logformat.tmpl delete mode 100644 templates/v5.4/misc/acme.tmpl delete mode 100644 templates/v5.4/misc/resolver.tmpl delete mode 100644 templates/v5.4/misc/server-http.tmpl delete mode 100644 templates/v5.4/misc/server-stream.tmpl delete mode 100644 templates/v5.4/misc/upstream-http.tmpl delete mode 100644 templates/v5.4/misc/upstream-stream.tmpl delete mode 100644 templates/v5.4/nginx-conf/license-key.tmpl delete mode 100644 templates/v5.4/nginx-conf/mime.types delete mode 100644 templates/v5.4/nginx-conf/nginx.conf delete mode 100644 templates/v5.4/stream.tmpl delete mode 100644 templates/v5.4/visibility/moesif/http.tmpl delete mode 100644 templates/v5.4/visibility/moesif/server.tmpl diff --git a/.gitignore b/.gitignore index a2f74f3e..96c1c4a0 100644 --- a/.gitignore +++ b/.gitignore @@ -21,8 +21,8 @@ Thumbs.db /.idea/ /venv/ /src/__pycache__/ -/src/v5_4/__pycache__/ /src/v5_5/__pycache__/ +/src/v5_6/__pycache__/ /contrib/devportal/redocly/src/__pycache__/ # Test coverage artifacts # diff --git a/README.md b/README.md index 170e5a2b..436ccfbe 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ A **blog article** to automate NGINX API Gateway management from OpenAPI schemas - [F5 NGINX Plus R33+](https://docs.nginx.com/nginx/) - [F5 WAF for NGINX](https://docs.nginx.com/waf/) -**Note**: F5 NGINX Plus R33 and above [require a valid license](https://docs.nginx.com/solutions/about-subscription-licenses/) and the `.output.license` section in the declarative JSON is required. See the [usage notes](/USAGE-v5.4.md) for further details. [Postman collection](/contrib/postman) examples are provided for NGINX Plus R33+. +**Note**: F5 NGINX Plus R33 and above [require a valid license](https://docs.nginx.com/solutions/about-subscription-licenses/) and the `.output.license` section in the declarative JSON is required. ## 🛠️ Architecture @@ -215,8 +215,8 @@ See the [features list](/FEATURES.md) Usage details and JSON schema are available here: -- [API v5.5](/USAGE-v5.5.md) - latest -- [API v5.4](/USAGE-v5.4.md) - stable +- [API v5.6](/USAGE-v5.6.md) - latest +- [API v5.5](/USAGE-v5.5.md) - stable A sample Postman collection and usage instructions can be found [here](/contrib/postman) diff --git a/USAGE-v5.4.md b/USAGE-v5.4.md deleted file mode 100644 index 4ed88b24..00000000 --- a/USAGE-v5.4.md +++ /dev/null @@ -1,67 +0,0 @@ -# Usage for NGINX Declarative API v5.4 - -Version 5.4 supports: - -- [NGINX Instance Manager](https://docs.nginx.com/nginx-management-suite/nim/) 2.14+. Version 2.18+ is required for NGINX R33 and above -- [NGINX One Console](https://docs.nginx.com/nginx-one/) -- [NGINX Plus](https://docs.nginx.com/nginx/) R31+ -- [NGINX App Protect WAF](https://docs.nginx.com/nginx-app-protect-waf/) v4 or v5 with precompiled [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) for usage examples - -- `.output.license` defines the JWT license to use for NGINX Plus R33+ - - `.output.license.endpoint` the usage reporting endpoint (defaults to `product.connect.nginx.com`). NGINX Instance Manager address can be used here - - `.output.license.token` the JWT license token. If this field is omitted, it is assumed that a `/etc/nginx/license.jwt` token already exists on the instance and it won't be replaced - - `.output.license.ssl_verify` set to `false` to trust all SSL certificates (not recommended). Useful for reporting to NGINX Instance Manager without a local PKI. - - `.output.license.grace_period` Set to 'true' to begin the 180-day reporting enforcement grace period. Reporting must begin or resume before the end of the grace period to ensure continued operation -- `.output.type` defines how NGINX configuration will be returned: - - *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.synchronous` **optional**, when set to `True` (default) the NGINX Declarative API waits for NGINX Instance Manager successful reply after publishing the NGINX configuration. Setting this to `False` enqueues the request, supporting multiple JSON declarations to be submitted at the same time/from multiple clients. Currently supported for `PATCH` operations only. - - `.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 - - *nginxone* - NGINX configuration is published to a NGINX One Console config sync group - - `.output.nginxone.url` the NGINX One Console URL - - `.output.nginxone.namespace` the NGINX One Console namespace - - `.output.nginxone.token` the authentication token - - `.output.nginxone.configsyncgroup` the NGINX One Console config sync group name - - `.output.nginxone.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 One Cloud Console - - `.output.nms.synchronous` **optional**, when set to `True` (default) the NGINX Declarative API waits for NGINX One Console successful reply after publishing the NGINX configuration. Setting this to `False` enqueues the request, supporting multiple JSON declarations to be submitted at the same time/from multiple clients. Currently supported for `PATCH` operations only. - - `.output.nginxone.modules` an optional array of NGINX module names (ie. 'ngx_http_app_protect_module', 'ngx_http_js_module','ngx_stream_js_module') - - `.output.nginxone.certificates` an optional array of TLS certificates/keys/chains to be published - - `.output.nginxone.certificates[].type` the item type ('certificate', 'key', 'chain') - - `.output.nginxone.certificates[].name` the certificate/key/chain name with no path/extension (ie. 'test-application') - - `.output.nginxone.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 -- `.declaration` describes the NGINX configuration to be created - - `.declaration.http[]` NGINX HTTP definitions - - `.declaration.layer4[]` NGINX TCP/UDP definitions - - `.declaration.resolvers[]` DNS resolvers definitions - -### API endpoints - -- `POST /v5.4/config/` - Publish a new declaration -- `PATCH /v5.4/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.4/config/{configUid}/submission/{submissionUid}` - Retrieve a submission (asynchronous `PATCH` request) status -- `GET /v5.4/config/{config_uid}` - Retrieve an existing declaration -- `DELETE /v5.4/config/{config_uid}` - Delete an existing declaration \ No newline at end of file diff --git a/contrib/gitops-examples/v5.4/NginxDefaultPolicy.json b/contrib/gitops-examples/v5.6/NginxDefaultPolicy.json similarity index 100% rename from contrib/gitops-examples/v5.4/NginxDefaultPolicy.json rename to contrib/gitops-examples/v5.6/NginxDefaultPolicy.json diff --git a/contrib/gitops-examples/v5.4/apigw.nginx.lab.crt b/contrib/gitops-examples/v5.6/apigw.nginx.lab.crt similarity index 100% rename from contrib/gitops-examples/v5.4/apigw.nginx.lab.crt rename to contrib/gitops-examples/v5.6/apigw.nginx.lab.crt diff --git a/contrib/gitops-examples/v5.4/apigw.nginx.lab.key b/contrib/gitops-examples/v5.6/apigw.nginx.lab.key similarity index 100% rename from contrib/gitops-examples/v5.4/apigw.nginx.lab.key rename to contrib/gitops-examples/v5.6/apigw.nginx.lab.key diff --git a/contrib/gitops-examples/v5.4/client.cert.pem b/contrib/gitops-examples/v5.6/client.cert.pem similarity index 100% rename from contrib/gitops-examples/v5.4/client.cert.pem rename to contrib/gitops-examples/v5.6/client.cert.pem diff --git a/contrib/gitops-examples/v5.4/client.key.pem b/contrib/gitops-examples/v5.6/client.key.pem similarity index 100% rename from contrib/gitops-examples/v5.4/client.key.pem rename to contrib/gitops-examples/v5.6/client.key.pem diff --git a/contrib/gitops-examples/v5.4/nap-policy-xss-allowed.json b/contrib/gitops-examples/v5.6/nap-policy-xss-allowed.json similarity index 100% rename from contrib/gitops-examples/v5.4/nap-policy-xss-allowed.json rename to contrib/gitops-examples/v5.6/nap-policy-xss-allowed.json diff --git a/contrib/gitops-examples/v5.4/nap-policy-xss-blocked-bot-allowed.json b/contrib/gitops-examples/v5.6/nap-policy-xss-blocked-bot-allowed.json similarity index 100% rename from contrib/gitops-examples/v5.4/nap-policy-xss-blocked-bot-allowed.json rename to contrib/gitops-examples/v5.6/nap-policy-xss-blocked-bot-allowed.json diff --git a/contrib/gitops-examples/v5.4/nap-policy-xss-blocked.json b/contrib/gitops-examples/v5.6/nap-policy-xss-blocked.json similarity index 100% rename from contrib/gitops-examples/v5.4/nap-policy-xss-blocked.json rename to contrib/gitops-examples/v5.6/nap-policy-xss-blocked.json diff --git a/contrib/gitops-examples/v5.4/testcert.chain b/contrib/gitops-examples/v5.6/testcert.chain similarity index 100% rename from contrib/gitops-examples/v5.4/testcert.chain rename to contrib/gitops-examples/v5.6/testcert.chain diff --git a/contrib/gitops-examples/v5.4/testcert.crt b/contrib/gitops-examples/v5.6/testcert.crt similarity index 100% rename from contrib/gitops-examples/v5.4/testcert.crt rename to contrib/gitops-examples/v5.6/testcert.crt diff --git a/contrib/gitops-examples/v5.4/testcert.key b/contrib/gitops-examples/v5.6/testcert.key similarity index 100% rename from contrib/gitops-examples/v5.4/testcert.key rename to contrib/gitops-examples/v5.6/testcert.key diff --git a/contrib/gitops-examples/v5.4/testcert2.chain b/contrib/gitops-examples/v5.6/testcert2.chain similarity index 100% rename from contrib/gitops-examples/v5.4/testcert2.chain rename to contrib/gitops-examples/v5.6/testcert2.chain diff --git a/contrib/gitops-examples/v5.4/testcert2.crt b/contrib/gitops-examples/v5.6/testcert2.crt similarity index 100% rename from contrib/gitops-examples/v5.4/testcert2.crt rename to contrib/gitops-examples/v5.6/testcert2.crt diff --git a/contrib/gitops-examples/v5.4/testcert2.key b/contrib/gitops-examples/v5.6/testcert2.key similarity index 100% rename from contrib/gitops-examples/v5.4/testcert2.key rename to contrib/gitops-examples/v5.6/testcert2.key diff --git a/etc/config.toml b/etc/config.toml index fac783b8..c7515fc0 100644 --- a/etc/config.toml +++ b/etc/config.toml @@ -3,7 +3,7 @@ # Main variables [main] banner = "NGINX Declarative API" -version = "5.5.0" +version = "5.6.0" url = "https://github.com/f5devcentral/NGINX-Declarative-API" # Templates diff --git a/openapi.json b/openapi.json deleted file mode 100644 index 1dc5a9ef..00000000 --- a/openapi.json +++ /dev/null @@ -1,6686 +0,0 @@ -{ - "openapi": "3.1.0", - "info": { - "title": "NGINX Declarative API", - "contact": { - "name": "GitHub", - "url": "https://github.com/f5devcentral/NGINX-Declarative-API" - }, - "version": "5.5.0" - }, - "paths": { - "/v5.4/config": { - "post": { - "summary": "Post Config V5 4", - "operationId": "post_config_v5_4_v5_4_config_post", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/V5_4_NginxConfigDeclaration__ConfigDeclaration" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "text/plain": { - "schema": { - "type": "string" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/v5.5/config": { - "post": { - "summary": "Post Config V5 5", - "operationId": "post_config_v5_5_v5_5_config_post", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ConfigDeclaration" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "text/plain": { - "schema": { - "type": "string" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/v5.4/config/{configuid}": { - "patch": { - "summary": "Patch Config V5 4", - "operationId": "patch_config_v5_4_v5_4_config__configuid__patch", - "parameters": [ - { - "name": "configuid", - "in": "path", - "required": true, - "schema": { - "type": "string", - "title": "Configuid" - } - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/V5_4_NginxConfigDeclaration__ConfigDeclaration" - } - } - } - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "text/plain": { - "schema": { - "type": "string" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - }, - "get": { - "summary": "Get Config Declaration V5 4", - "operationId": "get_config_declaration_v5_4_v5_4_config__configuid__get", - "parameters": [ - { - "name": "configuid", - "in": "path", - "required": true, - "schema": { - "type": "string", - "title": "Configuid" - } - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "text/plain": { - "schema": { - "type": "string" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - }, - "delete": { - "summary": "Delete Config", - "operationId": "delete_config_v5_4_config__configuid__delete", - "parameters": [ - { - "name": "configuid", - "in": "path", - "required": true, - "schema": { - "type": "string", - "title": "Configuid" - } - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "text/plain": { - "schema": { - "type": "string" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/v5.5/config/{configuid}": { - "patch": { - "summary": "Patch Config V5 5", - "operationId": "patch_config_v5_5_v5_5_config__configuid__patch", - "parameters": [ - { - "name": "configuid", - "in": "path", - "required": true, - "schema": { - "type": "string", - "title": "Configuid" - } - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ConfigDeclaration" - } - } - } - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "text/plain": { - "schema": { - "type": "string" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - }, - "get": { - "summary": "Get Config Declaration V5 5", - "operationId": "get_config_declaration_v5_5_v5_5_config__configuid__get", - "parameters": [ - { - "name": "configuid", - "in": "path", - "required": true, - "schema": { - "type": "string", - "title": "Configuid" - } - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "text/plain": { - "schema": { - "type": "string" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - }, - "delete": { - "summary": "Delete Config", - "operationId": "delete_config_v5_5_config__configuid__delete", - "parameters": [ - { - "name": "configuid", - "in": "path", - "required": true, - "schema": { - "type": "string", - "title": "Configuid" - } - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "text/plain": { - "schema": { - "type": "string" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/v5.5/config/{configuid}/status": { - "get": { - "summary": "Get Config Status", - "operationId": "get_config_status_v5_5_config__configuid__status_get", - "parameters": [ - { - "name": "configuid", - "in": "path", - "required": true, - "schema": { - "type": "string", - "title": "Configuid" - } - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "text/plain": { - "schema": { - "type": "string" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/v5.4/config/{configuid}/status": { - "get": { - "summary": "Get Config Status", - "operationId": "get_config_status_v5_4_config__configuid__status_get", - "parameters": [ - { - "name": "configuid", - "in": "path", - "required": true, - "schema": { - "type": "string", - "title": "Configuid" - } - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "text/plain": { - "schema": { - "type": "string" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/v5.4/config/{configuid}/submission/{submissionuid}": { - "get": { - "summary": "Get Submission Status", - "operationId": "get_submission_status_v5_4_config__configuid__submission__submissionuid__get", - "parameters": [ - { - "name": "configuid", - "in": "path", - "required": true, - "schema": { - "type": "string", - "title": "Configuid" - } - }, - { - "name": "submissionuid", - "in": "path", - "required": true, - "schema": { - "type": "string", - "title": "Submissionuid" - } - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "text/plain": { - "schema": { - "type": "string" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/v5.5/config/{configuid}/submission/{submissionuid}": { - "get": { - "summary": "Get Submission Status", - "operationId": "get_submission_status_v5_5_config__configuid__submission__submissionuid__get", - "parameters": [ - { - "name": "configuid", - "in": "path", - "required": true, - "schema": { - "type": "string", - "title": "Configuid" - } - }, - { - "name": "submissionuid", - "in": "path", - "required": true, - "schema": { - "type": "string", - "title": "Submissionuid" - } - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "text/plain": { - "schema": { - "type": "string" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - } - }, - "components": { - "schemas": { - "APIGatewayAuthentication": { - "properties": { - "client": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/LocationAuthClient" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Client", - "default": [] - }, - "enforceOnPaths": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Enforceonpaths", - "default": true - }, - "paths": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Paths", - "default": [] - } - }, - "additionalProperties": false, - "type": "object", - "title": "APIGatewayAuthentication" - }, - "APIGatewayAuthorization": { - "properties": { - "profile": { - "type": "string", - "title": "Profile" - }, - "enforceOnPaths": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Enforceonpaths", - "default": true - }, - "paths": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Paths", - "default": [] - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "profile" - ], - "title": "APIGatewayAuthorization" - }, - "APIGatewayCache": { - "properties": { - "profile": { - "type": "string", - "title": "Profile" - }, - "key": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Key", - "default": "$scheme$proxy_host$request_uri" - }, - "validity": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/CacheObjectTTL" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Validity", - "default": [] - }, - "enforceOnPaths": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Enforceonpaths", - "default": true - }, - "paths": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Paths", - "default": [] - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "profile" - ], - "title": "APIGatewayCache" - }, - "API_Gateway": { - "properties": { - "enabled": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Enabled", - "default": false - }, - "strip_uri": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Strip Uri", - "default": false - }, - "server_url": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Server Url", - "default": "" - } - }, - "additionalProperties": false, - "type": "object", - "title": "API_Gateway" - }, - "AcmeIssuers": { - "properties": { - "name": { - "type": "string", - "title": "Name", - "default": "" - }, - "uri": { - "type": "string", - "title": "Uri", - "default": "" - }, - "account_key": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Account Key", - "default": "" - }, - "contact": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Contact", - "default": "" - }, - "ssl_trusted_certificate": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Ssl Trusted Certificate", - "default": "" - }, - "ssl_verify": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Ssl Verify", - "default": false - }, - "state_path": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "State Path", - "default": "" - }, - "accept_terms_of_service": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Accept Terms Of Service", - "default": false - } - }, - "additionalProperties": false, - "type": "object", - "title": "AcmeIssuers" - }, - "AppProtect": { - "properties": { - "enabled": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Enabled", - "default": false - }, - "policy": { - "type": "string", - "title": "Policy", - "default": "" - }, - "log": { - "$ref": "#/components/schemas/AppProtectLog", - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "title": "AppProtect" - }, - "AppProtectLog": { - "properties": { - "enabled": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Enabled", - "default": false - }, - "profile_name": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Profile Name", - "default": "" - }, - "destination": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Destination", - "default": "" - } - }, - "additionalProperties": false, - "type": "object", - "title": "AppProtectLog" - }, - "AppProtectLogProfile": { - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "format": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Format", - "default": "default" - }, - "format_string": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Format String", - "default": "" - }, - "type": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Type", - "default": "blocked" - }, - "max_request_size": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Max Request Size", - "default": "any" - }, - "max_message_size": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Max Message Size", - "default": "5k" - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "name" - ], - "title": "AppProtectLogProfile" - }, - "AuthClientJWT": { - "properties": { - "realm": { - "type": "string", - "title": "Realm", - "default": "JWT Authentication" - }, - "key": { - "type": "string", - "title": "Key", - "default": "" - }, - "cachetime": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Cachetime", - "default": 0 - }, - "jwt_type": { - "type": "string", - "title": "Jwt Type", - "default": "signed" - }, - "token_location": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Token Location", - "default": "" - } - }, - "additionalProperties": false, - "type": "object", - "title": "AuthClientJWT" - }, - "AuthClientMtls": { - "properties": { - "enabled": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Enabled", - "default": "off" - }, - "client_certificates": { - "type": "string", - "title": "Client Certificates", - "default": "" - }, - "trusted_ca_certificates": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Trusted Ca Certificates", - "default": "" - }, - "ocsp": { - "anyOf": [ - { - "$ref": "#/components/schemas/Ocsp" - }, - { - "type": "null" - } - ], - "default": {} - }, - "stapling": { - "anyOf": [ - { - "$ref": "#/components/schemas/OcspStapling" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "title": "AuthClientMtls" - }, - "AuthClientOIDC": { - "properties": { - "issuer": { - "type": "string", - "title": "Issuer", - "default": "" - }, - "client_id": { - "type": "string", - "title": "Client Id", - "default": "" - }, - "client_secret": { - "type": "string", - "title": "Client Secret", - "default": "" - }, - "config_url": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Config Url", - "default": "" - }, - "cookie_name": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Cookie Name", - "default": "" - }, - "extra_auth_args": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Extra Auth Args", - "default": "" - }, - "redirect_uri": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Redirect Uri", - "default": "/oidc_callback" - }, - "logout_uri": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Logout Uri", - "default": "" - }, - "post_logout_uri": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Post Logout Uri", - "default": "" - }, - "logout_token_hint": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Logout Token Hint", - "default": false - }, - "scope": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Scope", - "default": "openid" - }, - "session_store": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Session Store", - "default": "" - }, - "session_timeout": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Session Timeout", - "default": "8h" - }, - "ssl_crl": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Ssl Crl", - "default": "" - }, - "ssl_trusted_certificate": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Ssl Trusted Certificate", - "default": "" - }, - "userinfo": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Userinfo", - "default": false - } - }, - "additionalProperties": false, - "type": "object", - "title": "AuthClientOIDC" - }, - "AuthServerMtls": { - "properties": { - "certificate": { - "type": "string", - "title": "Certificate", - "default": "" - }, - "key": { - "type": "string", - "title": "Key", - "default": "" - } - }, - "additionalProperties": false, - "type": "object", - "title": "AuthServerMtls" - }, - "AuthServerToken": { - "properties": { - "token": { - "type": "string", - "title": "Token", - "default": "" - }, - "type": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Type", - "default": "" - }, - "location": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Location", - "default": "" - }, - "username": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Username", - "default": "" - }, - "password": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Password", - "default": "" - } - }, - "additionalProperties": false, - "type": "object", - "title": "AuthServerToken" - }, - "Authentication": { - "properties": { - "client": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/Authentication_Client" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Client", - "default": [] - }, - "server": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/Authentication_Server" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Server", - "default": [] - } - }, - "additionalProperties": false, - "type": "object", - "title": "Authentication" - }, - "Authentication_Client": { - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "type": { - "type": "string", - "title": "Type" - }, - "jwt": { - "anyOf": [ - { - "$ref": "#/components/schemas/AuthClientJWT" - }, - { - "type": "null" - } - ], - "default": {} - }, - "mtls": { - "anyOf": [ - { - "$ref": "#/components/schemas/AuthClientMtls" - }, - { - "type": "null" - } - ], - "default": {} - }, - "oidc": { - "anyOf": [ - { - "$ref": "#/components/schemas/AuthClientOIDC" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "name", - "type" - ], - "title": "Authentication_Client" - }, - "Authentication_Server": { - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "type": { - "type": "string", - "title": "Type" - }, - "token": { - "anyOf": [ - { - "$ref": "#/components/schemas/AuthServerToken" - }, - { - "type": "null" - } - ], - "default": {} - }, - "mtls": { - "anyOf": [ - { - "$ref": "#/components/schemas/AuthServerMtls" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "name", - "type" - ], - "title": "Authentication_Server" - }, - "Authorization": { - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "type": { - "type": "string", - "title": "Type" - }, - "jwt": { - "anyOf": [ - { - "$ref": "#/components/schemas/AuthorizationJWT" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "name", - "type" - ], - "title": "Authorization" - }, - "AuthorizationJWT": { - "properties": { - "claims": { - "items": { - "$ref": "#/components/schemas/JwtAuthZNameValue" - }, - "type": "array", - "title": "Claims" - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "claims" - ], - "title": "AuthorizationJWT" - }, - "AuthorizationProfileReference": { - "properties": { - "profile": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Profile", - "default": "" - } - }, - "additionalProperties": false, - "type": "object", - "title": "AuthorizationProfileReference" - }, - "CacheItem": { - "properties": { - "profile": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Profile", - "default": "" - }, - "key": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Key", - "default": "$scheme$proxy_host$request_uri" - }, - "validity": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/CacheObjectTTL" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Validity", - "default": [] - } - }, - "additionalProperties": false, - "type": "object", - "title": "CacheItem" - }, - "CacheObjectTTL": { - "properties": { - "code": { - "type": "string", - "title": "Code", - "default": "any" - }, - "ttl": { - "type": "string", - "title": "Ttl", - "default": "10m" - } - }, - "additionalProperties": false, - "type": "object", - "title": "CacheObjectTTL" - }, - "CacheProfile": { - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "basepath": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Basepath", - "default": "/tmp" - }, - "size": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Size", - "default": "10m" - }, - "ttl": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Ttl", - "default": "10m" - }, - "max_size": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Max Size", - "default": "" - }, - "min_free": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Min Free", - "default": "" - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "name" - ], - "title": "CacheProfile" - }, - "CachingItem": { - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "key": { - "type": "string", - "title": "Key" - }, - "size": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Size", - "default": "10m" - }, - "valid": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/ValidItem" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Valid", - "default": [] - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "name", - "key" - ], - "title": "CachingItem" - }, - "ConfigDeclaration": { - "properties": { - "output": { - "$ref": "#/components/schemas/Output" - }, - "declaration": { - "anyOf": [ - { - "$ref": "#/components/schemas/V5_5_NginxConfigDeclaration__Declaration" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "output" - ], - "title": "ConfigDeclaration" - }, - "Declaration": { - "properties": { - "layer4": { - "anyOf": [ - { - "$ref": "#/components/schemas/Layer4" - }, - { - "type": "null" - } - ], - "default": {} - }, - "http": { - "anyOf": [ - { - "$ref": "#/components/schemas/Http" - }, - { - "type": "null" - } - ], - "default": {} - }, - "resolvers": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/Resolver" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Resolvers", - "default": [] - } - }, - "additionalProperties": false, - "type": "object", - "title": "Declaration" - }, - "DevPortal_Backstage": { - "properties": { - "name": { - "type": "string", - "title": "Name", - "default": "" - }, - "lifecycle": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Lifecycle", - "default": "production" - }, - "owner": { - "type": "string", - "title": "Owner", - "default": "" - }, - "system": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "System", - "default": "" - } - }, - "additionalProperties": false, - "type": "object", - "title": "DevPortal_Backstage" - }, - "DevPortal_Redocly": { - "properties": { - "uri": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Uri", - "default": "/devportal.html" - } - }, - "additionalProperties": false, - "type": "object", - "title": "DevPortal_Redocly" - }, - "DeveloperPortal": { - "properties": { - "enabled": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Enabled", - "default": false - }, - "type": { - "type": "string", - "title": "Type", - "default": "" - }, - "redocly": { - "anyOf": [ - { - "$ref": "#/components/schemas/DevPortal_Redocly" - }, - { - "type": "null" - } - ], - "default": {} - }, - "backstage": { - "anyOf": [ - { - "$ref": "#/components/schemas/DevPortal_Backstage" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "title": "DeveloperPortal" - }, - "HTTPHeader": { - "properties": { - "name": { - "type": "string", - "title": "Name", - "default": "" - }, - "value": { - "type": "string", - "title": "Value", - "default": "" - } - }, - "additionalProperties": false, - "type": "object", - "title": "HTTPHeader" - }, - "HTTPValidationError": { - "properties": { - "detail": { - "items": { - "$ref": "#/components/schemas/ValidationError" - }, - "type": "array", - "title": "Detail" - } - }, - "type": "object", - "title": "HTTPValidationError" - }, - "HealthCheck": { - "properties": { - "enabled": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Enabled", - "default": false - }, - "uri": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Uri", - "default": "/" - }, - "interval": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Interval", - "default": 5 - }, - "fails": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Fails", - "default": 1 - }, - "passes": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Passes", - "default": 1 - } - }, - "additionalProperties": false, - "type": "object", - "title": "HealthCheck" - }, - "Http": { - "properties": { - "servers": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/V5_4_NginxConfigDeclaration__Server" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Servers", - "default": [] - }, - "upstreams": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/V5_4_NginxConfigDeclaration__Upstream" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Upstreams", - "default": [] - }, - "caching": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/CachingItem" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Caching", - "default": [] - }, - "rate_limit": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/RateLimitItem" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Rate Limit", - "default": [] - }, - "nginx_plus_api": { - "anyOf": [ - { - "$ref": "#/components/schemas/NginxPlusApi" - }, - { - "type": "null" - } - ], - "default": {} - }, - "maps": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/Map" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Maps", - "default": [] - }, - "snippet": { - "anyOf": [ - { - "$ref": "#/components/schemas/ObjectFromSourceOfTruth" - }, - { - "type": "null" - } - ], - "default": {} - }, - "authentication": { - "anyOf": [ - { - "$ref": "#/components/schemas/V5_4_NginxConfigDeclaration__Authentication" - }, - { - "type": "null" - } - ], - "default": {} - }, - "authorization": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/V5_4_NginxConfigDeclaration__Authorization" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Authorization", - "default": [] - }, - "njs": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/V5_4_NginxConfigDeclaration__NjsHookHttpServer" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Njs", - "default": [] - }, - "njs_profiles": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/V5_4_NginxConfigDeclaration__NjsFile" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Njs Profiles", - "default": [] - }, - "cache": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/CacheProfile" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Cache", - "default": [] - }, - "logformats": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/LogFormat" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Logformats", - "default": [] - }, - "resolver": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Resolver", - "default": "" - }, - "acme_issuers": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/AcmeIssuers" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Acme Issuers", - "default": [] - } - }, - "additionalProperties": false, - "type": "object", - "title": "Http" - }, - "JwtAuthZNameValue": { - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "value": { - "items": { - "type": "string" - }, - "type": "array", - "title": "Value" - }, - "errorcode": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Errorcode", - "default": 401 - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "name", - "value" - ], - "title": "JwtAuthZNameValue" - }, - "L4Origin": { - "properties": { - "server": { - "type": "string", - "title": "Server" - }, - "weight": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Weight", - "default": 1 - }, - "max_fails": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Max Fails", - "default": 1 - }, - "fail_timeout": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Fail Timeout", - "default": "10s" - }, - "max_conns": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Max Conns", - "default": 0 - }, - "slow_start": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Slow Start", - "default": "0" - }, - "backup": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Backup", - "default": false - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "server" - ], - "title": "L4Origin" - }, - "L4Server": { - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "resolver": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Resolver", - "default": "" - }, - "listen": { - "anyOf": [ - { - "$ref": "#/components/schemas/V5_4_NginxConfigDeclaration__ListenL4" - }, - { - "type": "null" - } - ], - "default": {} - }, - "upstream": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Upstream", - "default": "" - }, - "snippet": { - "anyOf": [ - { - "$ref": "#/components/schemas/ObjectFromSourceOfTruth" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "name" - ], - "title": "L4Server" - }, - "L4Tls": { - "properties": { - "certificate": { - "type": "string", - "title": "Certificate", - "default": "" - }, - "key": { - "type": "string", - "title": "Key", - "default": "" - }, - "ciphers": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Ciphers", - "default": "" - }, - "protocols": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Protocols", - "default": [] - }, - "authentication": { - "anyOf": [ - { - "$ref": "#/components/schemas/LocationAuth" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "title": "L4Tls" - }, - "L4Upstream": { - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "resolver": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Resolver", - "default": "" - }, - "origin": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/L4Origin" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Origin", - "default": [] - }, - "snippet": { - "anyOf": [ - { - "$ref": "#/components/schemas/ObjectFromSourceOfTruth" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "name" - ], - "title": "L4Upstream" - }, - "Layer4": { - "properties": { - "servers": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/L4Server" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Servers", - "default": [] - }, - "upstreams": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/V5_4_NginxConfigDeclaration__L4Upstream" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Upstreams", - "default": [] - } - }, - "additionalProperties": false, - "type": "object", - "title": "Layer4" - }, - "License": { - "properties": { - "endpoint": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Endpoint", - "default": "product.connect.nginx.com" - }, - "token": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Token", - "default": "" - }, - "ssl_verify": { - "type": "boolean", - "title": "Ssl Verify", - "default": true - }, - "grace_period": { - "type": "boolean", - "title": "Grace Period", - "default": false - } - }, - "additionalProperties": false, - "type": "object", - "title": "License" - }, - "Listen": { - "properties": { - "address": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Address", - "default": "" - }, - "http2": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Http2", - "default": false - }, - "tls": { - "anyOf": [ - { - "$ref": "#/components/schemas/Tls" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "title": "Listen" - }, - "ListenL4": { - "properties": { - "address": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Address", - "default": "" - }, - "protocol": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Protocol", - "default": "tcp" - }, - "tls": { - "anyOf": [ - { - "$ref": "#/components/schemas/V5_5_NginxConfigDeclaration__L4Tls" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "title": "ListenL4" - }, - "Location": { - "properties": { - "uri": { - "type": "string", - "title": "Uri" - }, - "urimatch": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Urimatch", - "default": "prefix" - }, - "upstream": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Upstream", - "default": "" - }, - "log": { - "anyOf": [ - { - "$ref": "#/components/schemas/Log" - }, - { - "type": "null" - } - ], - "default": {} - }, - "apigateway": { - "anyOf": [ - { - "$ref": "#/components/schemas/V5_4_NginxConfigDeclaration__APIGateway" - }, - { - "type": "null" - } - ], - "default": {} - }, - "caching": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Caching", - "default": "" - }, - "rate_limit": { - "anyOf": [ - { - "$ref": "#/components/schemas/RateLimit" - }, - { - "type": "null" - } - ], - "default": {} - }, - "health_check": { - "anyOf": [ - { - "$ref": "#/components/schemas/HealthCheck" - }, - { - "type": "null" - } - ], - "default": {} - }, - "app_protect": { - "anyOf": [ - { - "$ref": "#/components/schemas/AppProtect" - }, - { - "type": "null" - } - ], - "default": {} - }, - "snippet": { - "anyOf": [ - { - "$ref": "#/components/schemas/ObjectFromSourceOfTruth" - }, - { - "type": "null" - } - ], - "default": {} - }, - "authentication": { - "anyOf": [ - { - "$ref": "#/components/schemas/LocationAuth" - }, - { - "type": "null" - } - ], - "default": {} - }, - "authorization": { - "anyOf": [ - { - "$ref": "#/components/schemas/AuthorizationProfileReference" - }, - { - "type": "null" - } - ], - "default": {} - }, - "headers": { - "anyOf": [ - { - "$ref": "#/components/schemas/LocationHeaders" - }, - { - "type": "null" - } - ], - "default": {} - }, - "njs": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/V5_4_NginxConfigDeclaration__NjsHookLocation" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Njs", - "default": [] - }, - "cache": { - "anyOf": [ - { - "$ref": "#/components/schemas/CacheItem" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "uri" - ], - "title": "Location" - }, - "LocationAuth": { - "properties": { - "client": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/LocationAuthClient" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Client", - "default": [] - }, - "server": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/LocationAuthServer" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Server", - "default": [] - } - }, - "additionalProperties": false, - "type": "object", - "title": "LocationAuth" - }, - "LocationAuthClient": { - "properties": { - "profile": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Profile", - "default": "" - } - }, - "additionalProperties": false, - "type": "object", - "title": "LocationAuthClient" - }, - "LocationAuthServer": { - "properties": { - "profile": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Profile", - "default": "" - } - }, - "additionalProperties": false, - "type": "object", - "title": "LocationAuthServer" - }, - "LocationHeaderToClient": { - "properties": { - "add": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/HTTPHeader" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Add", - "default": [] - }, - "delete": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Delete", - "default": [] - }, - "replace": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/HTTPHeader" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Replace", - "default": [] - } - }, - "additionalProperties": false, - "type": "object", - "title": "LocationHeaderToClient" - }, - "LocationHeaderToServer": { - "properties": { - "set": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/HTTPHeader" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Set", - "default": [] - }, - "delete": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Delete", - "default": [] - } - }, - "additionalProperties": false, - "type": "object", - "title": "LocationHeaderToServer" - }, - "LocationHeaders": { - "properties": { - "to_server": { - "anyOf": [ - { - "$ref": "#/components/schemas/LocationHeaderToServer" - }, - { - "type": "null" - } - ], - "default": {} - }, - "to_client": { - "anyOf": [ - { - "$ref": "#/components/schemas/LocationHeaderToClient" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "title": "LocationHeaders" - }, - "Log": { - "properties": { - "access": { - "anyOf": [ - { - "$ref": "#/components/schemas/LogAccess" - }, - { - "type": "null" - } - ], - "default": {} - }, - "error": { - "anyOf": [ - { - "$ref": "#/components/schemas/LogError" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "title": "Log" - }, - "LogAccess": { - "properties": { - "destination": { - "type": "string", - "title": "Destination" - }, - "format": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Format", - "default": "combined" - }, - "condition": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Condition", - "default": "" - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "destination" - ], - "title": "LogAccess" - }, - "LogError": { - "properties": { - "destination": { - "type": "string", - "title": "Destination" - }, - "level": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Level", - "default": "info" - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "destination" - ], - "title": "LogError" - }, - "LogFormat": { - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "escape": { - "type": "string", - "title": "Escape", - "default": "default" - }, - "format": { - "type": "string", - "title": "Format" - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "name", - "format" - ], - "title": "LogFormat" - }, - "LogProfile": { - "properties": { - "type": { - "type": "string", - "title": "Type" - }, - "app_protect": { - "anyOf": [ - { - "$ref": "#/components/schemas/AppProtectLogProfile" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "type" - ], - "title": "LogProfile" - }, - "Map": { - "properties": { - "match": { - "type": "string", - "title": "Match" - }, - "variable": { - "type": "string", - "title": "Variable" - }, - "entries": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/MapEntry" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Entries", - "default": [] - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "match", - "variable" - ], - "title": "Map" - }, - "MapEntry": { - "properties": { - "key": { - "type": "string", - "title": "Key" - }, - "keymatch": { - "type": "string", - "title": "Keymatch" - }, - "value": { - "type": "string", - "title": "Value" - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "key", - "keymatch", - "value" - ], - "title": "MapEntry" - }, - "NGINXPolicy": { - "properties": { - "type": { - "type": "string", - "title": "Type", - "default": "" - }, - "name": { - "type": "string", - "title": "Name", - "default": "" - }, - "active_tag": { - "type": "string", - "title": "Active Tag", - "default": "" - }, - "versions": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/NGINXPolicyVersion" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Versions", - "default": [] - } - }, - "additionalProperties": false, - "type": "object", - "title": "NGINXPolicy" - }, - "NGINXPolicyVersion": { - "properties": { - "tag": { - "type": "string", - "title": "Tag", - "default": "" - }, - "displayName": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Displayname", - "default": "" - }, - "description": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Description", - "default": "" - }, - "contents": { - "anyOf": [ - { - "$ref": "#/components/schemas/ObjectFromSourceOfTruth" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "title": "NGINXPolicyVersion" - }, - "NginxPlusApi": { - "properties": { - "write": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Write", - "default": false - }, - "listen": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Listen", - "default": "" - }, - "allow_acl": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Allow Acl", - "default": "" - } - }, - "additionalProperties": false, - "type": "object", - "title": "NginxPlusApi" - }, - "NjsFile": { - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "file": { - "$ref": "#/components/schemas/ObjectFromSourceOfTruth" - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "name", - "file" - ], - "title": "NjsFile" - }, - "NjsHookHttpServer": { - "properties": { - "hook": { - "$ref": "#/components/schemas/NjsHookHttpServerDetails" - }, - "profile": { - "type": "string", - "title": "Profile" - }, - "function": { - "type": "string", - "title": "Function" - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "hook", - "profile", - "function" - ], - "title": "NjsHookHttpServer" - }, - "NjsHookHttpServerDetails": { - "properties": { - "type": { - "type": "string", - "title": "Type" - }, - "js_preload_object": { - "anyOf": [ - { - "$ref": "#/components/schemas/NjsHook_js_preload_object" - }, - { - "type": "null" - } - ], - "default": {} - }, - "js_set": { - "anyOf": [ - { - "$ref": "#/components/schemas/NjsHook_js_set" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "type" - ], - "title": "NjsHookHttpServerDetails" - }, - "NjsHookLocationDetails": { - "properties": { - "type": { - "type": "string", - "title": "Type" - }, - "js_preload_object": { - "anyOf": [ - { - "$ref": "#/components/schemas/NjsHook_js_preload_object" - }, - { - "type": "null" - } - ], - "default": {} - }, - "js_set": { - "anyOf": [ - { - "$ref": "#/components/schemas/NjsHook_js_set" - }, - { - "type": "null" - } - ], - "default": {} - }, - "js_body_filter": { - "anyOf": [ - { - "$ref": "#/components/schemas/NjsHook_js_body_filter" - }, - { - "type": "null" - } - ], - "default": {} - }, - "js_periodic": { - "anyOf": [ - { - "$ref": "#/components/schemas/NjsHook_js_periodic" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "type" - ], - "title": "NjsHookLocationDetails" - }, - "NjsHook_js_body_filter": { - "properties": { - "buffer_type": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Buffer Type", - "default": "" - } - }, - "additionalProperties": false, - "type": "object", - "title": "NjsHook_js_body_filter" - }, - "NjsHook_js_periodic": { - "properties": { - "interval": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Interval", - "default": "" - }, - "jitter": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Jitter", - "default": 0 - }, - "worker_affinity": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Worker Affinity", - "default": "" - } - }, - "additionalProperties": false, - "type": "object", - "title": "NjsHook_js_periodic" - }, - "NjsHook_js_preload_object": { - "properties": { - "file": { - "type": "string", - "title": "File" - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "file" - ], - "title": "NjsHook_js_preload_object" - }, - "NjsHook_js_set": { - "properties": { - "variable": { - "type": "string", - "title": "Variable" - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "variable" - ], - "title": "NjsHook_js_set" - }, - "NmsCertificate": { - "properties": { - "type": { - "type": "string", - "title": "Type" - }, - "name": { - "type": "string", - "title": "Name" - }, - "contents": { - "anyOf": [ - { - "$ref": "#/components/schemas/ObjectFromSourceOfTruth" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "type", - "name" - ], - "title": "NmsCertificate" - }, - "ObjectFromSourceOfTruth": { - "properties": { - "content": { - "type": "string", - "title": "Content", - "default": "" - }, - "authentication": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/LocationAuthServer" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Authentication", - "default": [] - } - }, - "additionalProperties": false, - "type": "object", - "title": "ObjectFromSourceOfTruth" - }, - "Ocsp": { - "properties": { - "enabled": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Enabled", - "default": "off" - }, - "responder": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Responder", - "default": "" - } - }, - "additionalProperties": false, - "type": "object", - "title": "Ocsp" - }, - "OcspStapling": { - "properties": { - "enabled": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Enabled", - "default": false - }, - "verify": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Verify", - "default": false - }, - "responder": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Responder", - "default": "" - } - }, - "additionalProperties": false, - "type": "object", - "title": "OcspStapling" - }, - "Origin": { - "properties": { - "server": { - "type": "string", - "title": "Server" - }, - "weight": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Weight", - "default": 1 - }, - "max_fails": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Max Fails", - "default": 1 - }, - "fail_timeout": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Fail Timeout", - "default": "10s" - }, - "max_conns": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Max Conns", - "default": 0 - }, - "slow_start": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Slow Start", - "default": "0" - }, - "backup": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Backup", - "default": false - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "server" - ], - "title": "Origin" - }, - "Output": { - "properties": { - "type": { - "type": "string", - "title": "Type" - }, - "synchronous": { - "type": "boolean", - "title": "Synchronous", - "default": true - }, - "license": { - "anyOf": [ - { - "$ref": "#/components/schemas/V5_5_NginxConfigDeclaration__License" - }, - { - "type": "null" - } - ], - "default": {} - }, - "nms": { - "anyOf": [ - { - "$ref": "#/components/schemas/V5_5_NginxConfigDeclaration__OutputNMS" - }, - { - "type": "null" - } - ], - "default": {} - }, - "nginxone": { - "anyOf": [ - { - "$ref": "#/components/schemas/OutputNGINXOne" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "type" - ], - "title": "Output" - }, - "OutputNGINXOne": { - "properties": { - "url": { - "type": "string", - "title": "Url", - "default": "" - }, - "namespace": { - "type": "string", - "title": "Namespace", - "default": "" - }, - "token": { - "type": "string", - "title": "Token", - "default": "" - }, - "configsyncgroup": { - "type": "string", - "title": "Configsyncgroup", - "default": "" - }, - "synctime": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Synctime", - "default": 0 - }, - "modules": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Modules", - "default": [] - }, - "certificates": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/V5_5_NginxConfigDeclaration__NmsCertificate" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Certificates", - "default": [] - }, - "policies": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/NGINXPolicy" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Policies", - "default": [] - }, - "log_profiles": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/LogProfile" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Log Profiles", - "default": [] - } - }, - "additionalProperties": false, - "type": "object", - "title": "OutputNGINXOne" - }, - "OutputNMS": { - "properties": { - "url": { - "type": "string", - "title": "Url", - "default": "" - }, - "username": { - "type": "string", - "title": "Username", - "default": "" - }, - "password": { - "type": "string", - "title": "Password", - "default": "" - }, - "instancegroup": { - "type": "string", - "title": "Instancegroup", - "default": "" - }, - "synctime": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Synctime", - "default": 0 - }, - "modules": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Modules", - "default": [] - }, - "certificates": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/NmsCertificate" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Certificates", - "default": [] - }, - "policies": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/V5_4_NginxConfigDeclaration__NGINXPolicy" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Policies", - "default": [] - }, - "log_profiles": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/LogProfile" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Log Profiles", - "default": [] - } - }, - "additionalProperties": false, - "type": "object", - "title": "OutputNMS" - }, - "RateLimit": { - "properties": { - "profile": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Profile", - "default": "" - }, - "httpcode": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Httpcode", - "default": 429 - }, - "burst": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Burst", - "default": 0 - }, - "delay": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Delay", - "default": 0 - } - }, - "additionalProperties": false, - "type": "object", - "title": "RateLimit" - }, - "RateLimitApiGw": { - "properties": { - "profile": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Profile", - "default": "" - }, - "httpcode": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Httpcode", - "default": 429 - }, - "burst": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Burst", - "default": 0 - }, - "delay": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Delay", - "default": 0 - }, - "enforceOnPaths": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Enforceonpaths", - "default": true - }, - "paths": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Paths", - "default": [] - } - }, - "additionalProperties": false, - "type": "object", - "title": "RateLimitApiGw" - }, - "RateLimitItem": { - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "key": { - "type": "string", - "title": "Key" - }, - "size": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Size", - "default": "" - }, - "rate": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Rate", - "default": "" - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "name", - "key" - ], - "title": "RateLimitItem" - }, - "Resolver": { - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "address": { - "type": "string", - "title": "Address" - }, - "valid": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Valid", - "default": "" - }, - "ipv4": { - "type": "boolean", - "title": "Ipv4", - "default": true - }, - "ipv6": { - "type": "boolean", - "title": "Ipv6", - "default": true - }, - "timeout": { - "type": "string", - "title": "Timeout", - "default": "30s" - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "name", - "address" - ], - "title": "Resolver" - }, - "Server": { - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "names": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Names", - "default": [] - }, - "resolver": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Resolver", - "default": "" - }, - "listen": { - "anyOf": [ - { - "$ref": "#/components/schemas/Listen" - }, - { - "type": "null" - } - ], - "default": {} - }, - "log": { - "anyOf": [ - { - "$ref": "#/components/schemas/Log" - }, - { - "type": "null" - } - ], - "default": {} - }, - "locations": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/V5_5_NginxConfigDeclaration__Location" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Locations", - "default": [] - }, - "app_protect": { - "anyOf": [ - { - "$ref": "#/components/schemas/AppProtect" - }, - { - "type": "null" - } - ], - "default": {} - }, - "snippet": { - "anyOf": [ - { - "$ref": "#/components/schemas/ObjectFromSourceOfTruth" - }, - { - "type": "null" - } - ], - "default": {} - }, - "headers": { - "anyOf": [ - { - "$ref": "#/components/schemas/V5_5_NginxConfigDeclaration__LocationHeaders" - }, - { - "type": "null" - } - ], - "default": {} - }, - "njs": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/NjsHookHttpServer" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Njs", - "default": [] - }, - "authentication": { - "anyOf": [ - { - "$ref": "#/components/schemas/LocationAuth" - }, - { - "type": "null" - } - ], - "default": {} - }, - "authorization": { - "anyOf": [ - { - "$ref": "#/components/schemas/AuthorizationProfileReference" - }, - { - "type": "null" - } - ], - "default": {} - }, - "cache": { - "anyOf": [ - { - "$ref": "#/components/schemas/CacheItem" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "name" - ], - "title": "Server" - }, - "Sticky": { - "properties": { - "cookie": { - "type": "string", - "title": "Cookie", - "default": "" - }, - "expires": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Expires", - "default": "" - }, - "domain": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Domain", - "default": "" - }, - "path": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Path", - "default": "" - } - }, - "additionalProperties": false, - "type": "object", - "title": "Sticky" - }, - "Tls": { - "properties": { - "certificate": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Certificate", - "default": "" - }, - "key": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Key", - "default": "" - }, - "acme_issuer": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Acme Issuer", - "default": "" - }, - "ciphers": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Ciphers", - "default": "" - }, - "protocols": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Protocols", - "default": [] - }, - "authentication": { - "anyOf": [ - { - "$ref": "#/components/schemas/LocationAuth" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "title": "Tls" - }, - "Upstream": { - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "resolver": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Resolver", - "default": "" - }, - "origin": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/Origin" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Origin", - "default": [] - }, - "sticky": { - "anyOf": [ - { - "$ref": "#/components/schemas/Sticky" - }, - { - "type": "null" - } - ], - "default": {} - }, - "snippet": { - "anyOf": [ - { - "$ref": "#/components/schemas/ObjectFromSourceOfTruth" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "name" - ], - "title": "Upstream" - }, - "V5_4_NginxConfigDeclaration__APIGateway": { - "properties": { - "openapi_schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/ObjectFromSourceOfTruth" - }, - { - "type": "null" - } - ], - "default": {} - }, - "api_gateway": { - "anyOf": [ - { - "$ref": "#/components/schemas/API_Gateway" - }, - { - "type": "null" - } - ], - "default": {} - }, - "developer_portal": { - "anyOf": [ - { - "$ref": "#/components/schemas/DeveloperPortal" - }, - { - "type": "null" - } - ], - "default": {} - }, - "visibility": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/Visibility" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Visibility", - "default": [] - }, - "rate_limit": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/RateLimitApiGw" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Rate Limit", - "default": [] - }, - "authentication": { - "anyOf": [ - { - "$ref": "#/components/schemas/APIGatewayAuthentication" - }, - { - "type": "null" - } - ], - "default": {} - }, - "authorization": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/APIGatewayAuthorization" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Authorization", - "default": [] - }, - "cache": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/APIGatewayCache" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Cache", - "default": [] - }, - "log": { - "anyOf": [ - { - "$ref": "#/components/schemas/Log" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "title": "APIGateway" - }, - "V5_4_NginxConfigDeclaration__Authentication": { - "properties": { - "client": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/V5_4_NginxConfigDeclaration__Authentication_Client" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Client", - "default": [] - }, - "server": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/Authentication_Server" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Server", - "default": [] - } - }, - "additionalProperties": false, - "type": "object", - "title": "Authentication" - }, - "V5_4_NginxConfigDeclaration__Authentication_Client": { - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "type": { - "type": "string", - "title": "Type" - }, - "jwt": { - "anyOf": [ - { - "$ref": "#/components/schemas/AuthClientJWT" - }, - { - "type": "null" - } - ], - "default": {} - }, - "mtls": { - "anyOf": [ - { - "$ref": "#/components/schemas/AuthClientMtls" - }, - { - "type": "null" - } - ], - "default": {} - }, - "oidc": { - "anyOf": [ - { - "$ref": "#/components/schemas/AuthClientOIDC" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "name", - "type" - ], - "title": "Authentication_Client" - }, - "V5_4_NginxConfigDeclaration__Authorization": { - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "type": { - "type": "string", - "title": "Type" - }, - "jwt": { - "anyOf": [ - { - "$ref": "#/components/schemas/AuthorizationJWT" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "name", - "type" - ], - "title": "Authorization" - }, - "V5_4_NginxConfigDeclaration__ConfigDeclaration": { - "properties": { - "output": { - "$ref": "#/components/schemas/V5_4_NginxConfigDeclaration__Output" - }, - "declaration": { - "anyOf": [ - { - "$ref": "#/components/schemas/Declaration" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "output" - ], - "title": "ConfigDeclaration" - }, - "V5_4_NginxConfigDeclaration__L4Upstream": { - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "resolver": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Resolver", - "default": "" - }, - "origin": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/L4Origin" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Origin", - "default": [] - }, - "snippet": { - "anyOf": [ - { - "$ref": "#/components/schemas/ObjectFromSourceOfTruth" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "name" - ], - "title": "L4Upstream" - }, - "V5_4_NginxConfigDeclaration__Listen": { - "properties": { - "address": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Address", - "default": "" - }, - "http2": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Http2", - "default": false - }, - "tls": { - "anyOf": [ - { - "$ref": "#/components/schemas/V5_4_NginxConfigDeclaration__Tls" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "title": "Listen" - }, - "V5_4_NginxConfigDeclaration__ListenL4": { - "properties": { - "address": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Address", - "default": "" - }, - "protocol": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Protocol", - "default": "tcp" - }, - "tls": { - "anyOf": [ - { - "$ref": "#/components/schemas/L4Tls" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "title": "ListenL4" - }, - "V5_4_NginxConfigDeclaration__NGINXPolicy": { - "properties": { - "type": { - "type": "string", - "title": "Type", - "default": "" - }, - "name": { - "type": "string", - "title": "Name", - "default": "" - }, - "active_tag": { - "type": "string", - "title": "Active Tag", - "default": "" - }, - "versions": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/V5_4_NginxConfigDeclaration__NGINXPolicyVersion" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Versions", - "default": [] - } - }, - "additionalProperties": false, - "type": "object", - "title": "NGINXPolicy" - }, - "V5_4_NginxConfigDeclaration__NGINXPolicyVersion": { - "properties": { - "tag": { - "type": "string", - "title": "Tag", - "default": "" - }, - "displayName": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Displayname", - "default": "" - }, - "description": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Description", - "default": "" - }, - "contents": { - "anyOf": [ - { - "$ref": "#/components/schemas/ObjectFromSourceOfTruth" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "title": "NGINXPolicyVersion" - }, - "V5_4_NginxConfigDeclaration__NjsFile": { - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "file": { - "$ref": "#/components/schemas/ObjectFromSourceOfTruth" - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "name", - "file" - ], - "title": "NjsFile" - }, - "V5_4_NginxConfigDeclaration__NjsHookHttpServer": { - "properties": { - "hook": { - "$ref": "#/components/schemas/NjsHookHttpServerDetails" - }, - "profile": { - "type": "string", - "title": "Profile" - }, - "function": { - "type": "string", - "title": "Function" - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "hook", - "profile", - "function" - ], - "title": "NjsHookHttpServer" - }, - "V5_4_NginxConfigDeclaration__NjsHookLocation": { - "properties": { - "hook": { - "$ref": "#/components/schemas/NjsHookLocationDetails" - }, - "profile": { - "type": "string", - "title": "Profile" - }, - "function": { - "type": "string", - "title": "Function" - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "hook", - "profile", - "function" - ], - "title": "NjsHookLocation" - }, - "V5_4_NginxConfigDeclaration__Output": { - "properties": { - "type": { - "type": "string", - "title": "Type" - }, - "synchronous": { - "type": "boolean", - "title": "Synchronous", - "default": true - }, - "license": { - "anyOf": [ - { - "$ref": "#/components/schemas/License" - }, - { - "type": "null" - } - ], - "default": {} - }, - "nms": { - "anyOf": [ - { - "$ref": "#/components/schemas/OutputNMS" - }, - { - "type": "null" - } - ], - "default": {} - }, - "nginxone": { - "anyOf": [ - { - "$ref": "#/components/schemas/V5_4_NginxConfigDeclaration__OutputNGINXOne" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "type" - ], - "title": "Output" - }, - "V5_4_NginxConfigDeclaration__OutputNGINXOne": { - "properties": { - "url": { - "type": "string", - "title": "Url", - "default": "" - }, - "namespace": { - "type": "string", - "title": "Namespace", - "default": "" - }, - "token": { - "type": "string", - "title": "Token", - "default": "" - }, - "configsyncgroup": { - "type": "string", - "title": "Configsyncgroup", - "default": "" - }, - "synctime": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Synctime", - "default": 0 - }, - "modules": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Modules", - "default": [] - }, - "certificates": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/NmsCertificate" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Certificates", - "default": [] - }, - "policies": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/V5_4_NginxConfigDeclaration__NGINXPolicy" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Policies", - "default": [] - }, - "log_profiles": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/LogProfile" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Log Profiles", - "default": [] - } - }, - "additionalProperties": false, - "type": "object", - "title": "OutputNGINXOne" - }, - "V5_4_NginxConfigDeclaration__Server": { - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "names": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Names", - "default": [] - }, - "resolver": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Resolver", - "default": "" - }, - "listen": { - "anyOf": [ - { - "$ref": "#/components/schemas/V5_4_NginxConfigDeclaration__Listen" - }, - { - "type": "null" - } - ], - "default": {} - }, - "log": { - "anyOf": [ - { - "$ref": "#/components/schemas/Log" - }, - { - "type": "null" - } - ], - "default": {} - }, - "locations": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/Location" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Locations", - "default": [] - }, - "app_protect": { - "anyOf": [ - { - "$ref": "#/components/schemas/AppProtect" - }, - { - "type": "null" - } - ], - "default": {} - }, - "snippet": { - "anyOf": [ - { - "$ref": "#/components/schemas/ObjectFromSourceOfTruth" - }, - { - "type": "null" - } - ], - "default": {} - }, - "headers": { - "anyOf": [ - { - "$ref": "#/components/schemas/LocationHeaders" - }, - { - "type": "null" - } - ], - "default": {} - }, - "njs": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/V5_4_NginxConfigDeclaration__NjsHookHttpServer" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Njs", - "default": [] - }, - "authentication": { - "anyOf": [ - { - "$ref": "#/components/schemas/LocationAuth" - }, - { - "type": "null" - } - ], - "default": {} - }, - "authorization": { - "anyOf": [ - { - "$ref": "#/components/schemas/AuthorizationProfileReference" - }, - { - "type": "null" - } - ], - "default": {} - }, - "cache": { - "anyOf": [ - { - "$ref": "#/components/schemas/CacheItem" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "name" - ], - "title": "Server" - }, - "V5_4_NginxConfigDeclaration__Tls": { - "properties": { - "certificate": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Certificate", - "default": "" - }, - "key": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Key", - "default": "" - }, - "acme_issuer": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Acme Issuer", - "default": "" - }, - "ciphers": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Ciphers", - "default": "" - }, - "protocols": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Protocols", - "default": [] - }, - "authentication": { - "anyOf": [ - { - "$ref": "#/components/schemas/LocationAuth" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "title": "Tls" - }, - "V5_4_NginxConfigDeclaration__Upstream": { - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "resolver": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Resolver", - "default": "" - }, - "origin": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/Origin" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Origin", - "default": [] - }, - "sticky": { - "anyOf": [ - { - "$ref": "#/components/schemas/Sticky" - }, - { - "type": "null" - } - ], - "default": {} - }, - "snippet": { - "anyOf": [ - { - "$ref": "#/components/schemas/ObjectFromSourceOfTruth" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "name" - ], - "title": "Upstream" - }, - "V5_5_NginxConfigDeclaration__APIGateway": { - "properties": { - "openapi_schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/ObjectFromSourceOfTruth" - }, - { - "type": "null" - } - ], - "default": {} - }, - "api_gateway": { - "anyOf": [ - { - "$ref": "#/components/schemas/API_Gateway" - }, - { - "type": "null" - } - ], - "default": {} - }, - "developer_portal": { - "anyOf": [ - { - "$ref": "#/components/schemas/DeveloperPortal" - }, - { - "type": "null" - } - ], - "default": {} - }, - "visibility": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/Visibility" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Visibility", - "default": [] - }, - "rate_limit": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/RateLimitApiGw" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Rate Limit", - "default": [] - }, - "authentication": { - "anyOf": [ - { - "$ref": "#/components/schemas/APIGatewayAuthentication" - }, - { - "type": "null" - } - ], - "default": {} - }, - "authorization": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/APIGatewayAuthorization" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Authorization", - "default": [] - }, - "cache": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/APIGatewayCache" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Cache", - "default": [] - }, - "log": { - "anyOf": [ - { - "$ref": "#/components/schemas/Log" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "title": "APIGateway" - }, - "V5_5_NginxConfigDeclaration__Declaration": { - "properties": { - "layer4": { - "anyOf": [ - { - "$ref": "#/components/schemas/V5_5_NginxConfigDeclaration__Layer4" - }, - { - "type": "null" - } - ], - "default": {} - }, - "http": { - "anyOf": [ - { - "$ref": "#/components/schemas/V5_5_NginxConfigDeclaration__Http" - }, - { - "type": "null" - } - ], - "default": {} - }, - "resolvers": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/Resolver" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Resolvers", - "default": [] - } - }, - "additionalProperties": false, - "type": "object", - "title": "Declaration" - }, - "V5_5_NginxConfigDeclaration__Http": { - "properties": { - "servers": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/Server" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Servers", - "default": [] - }, - "upstreams": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/Upstream" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Upstreams", - "default": [] - }, - "caching": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/CachingItem" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Caching", - "default": [] - }, - "rate_limit": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/RateLimitItem" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Rate Limit", - "default": [] - }, - "nginx_plus_api": { - "anyOf": [ - { - "$ref": "#/components/schemas/NginxPlusApi" - }, - { - "type": "null" - } - ], - "default": {} - }, - "maps": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/Map" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Maps", - "default": [] - }, - "snippet": { - "anyOf": [ - { - "$ref": "#/components/schemas/ObjectFromSourceOfTruth" - }, - { - "type": "null" - } - ], - "default": {} - }, - "authentication": { - "anyOf": [ - { - "$ref": "#/components/schemas/Authentication" - }, - { - "type": "null" - } - ], - "default": {} - }, - "authorization": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/Authorization" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Authorization", - "default": [] - }, - "njs": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/NjsHookHttpServer" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Njs", - "default": [] - }, - "njs_profiles": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/NjsFile" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Njs Profiles", - "default": [] - }, - "cache": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/CacheProfile" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Cache", - "default": [] - }, - "logformats": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/LogFormat" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Logformats", - "default": [] - }, - "resolver": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Resolver", - "default": "" - }, - "acme_issuers": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/AcmeIssuers" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Acme Issuers", - "default": [] - } - }, - "additionalProperties": false, - "type": "object", - "title": "Http" - }, - "V5_5_NginxConfigDeclaration__L4Server": { - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "resolver": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Resolver", - "default": "" - }, - "listen": { - "anyOf": [ - { - "$ref": "#/components/schemas/ListenL4" - }, - { - "type": "null" - } - ], - "default": {} - }, - "upstream": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Upstream", - "default": "" - }, - "snippet": { - "anyOf": [ - { - "$ref": "#/components/schemas/ObjectFromSourceOfTruth" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "name" - ], - "title": "L4Server" - }, - "V5_5_NginxConfigDeclaration__L4Tls": { - "properties": { - "certificate": { - "type": "string", - "title": "Certificate", - "default": "" - }, - "key": { - "type": "string", - "title": "Key", - "default": "" - }, - "ciphers": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Ciphers", - "default": "" - }, - "protocols": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Protocols", - "default": [] - }, - "authentication": { - "anyOf": [ - { - "$ref": "#/components/schemas/LocationAuth" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "title": "L4Tls" - }, - "V5_5_NginxConfigDeclaration__Layer4": { - "properties": { - "servers": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/V5_5_NginxConfigDeclaration__L4Server" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Servers", - "default": [] - }, - "upstreams": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/L4Upstream" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Upstreams", - "default": [] - } - }, - "additionalProperties": false, - "type": "object", - "title": "Layer4" - }, - "V5_5_NginxConfigDeclaration__License": { - "properties": { - "endpoint": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Endpoint", - "default": "product.connect.nginx.com" - }, - "token": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Token", - "default": "" - }, - "ssl_verify": { - "type": "boolean", - "title": "Ssl Verify", - "default": true - }, - "grace_period": { - "type": "boolean", - "title": "Grace Period", - "default": false - }, - "proxy": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Proxy", - "default": "" - }, - "proxy_username": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Proxy Username", - "default": "" - }, - "proxy_password": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Proxy Password", - "default": "" - } - }, - "additionalProperties": false, - "type": "object", - "title": "License" - }, - "V5_5_NginxConfigDeclaration__Location": { - "properties": { - "uri": { - "type": "string", - "title": "Uri" - }, - "urimatch": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Urimatch", - "default": "prefix" - }, - "upstream": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Upstream", - "default": "" - }, - "log": { - "anyOf": [ - { - "$ref": "#/components/schemas/Log" - }, - { - "type": "null" - } - ], - "default": {} - }, - "apigateway": { - "anyOf": [ - { - "$ref": "#/components/schemas/V5_5_NginxConfigDeclaration__APIGateway" - }, - { - "type": "null" - } - ], - "default": {} - }, - "caching": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Caching", - "default": "" - }, - "rate_limit": { - "anyOf": [ - { - "$ref": "#/components/schemas/RateLimit" - }, - { - "type": "null" - } - ], - "default": {} - }, - "health_check": { - "anyOf": [ - { - "$ref": "#/components/schemas/HealthCheck" - }, - { - "type": "null" - } - ], - "default": {} - }, - "app_protect": { - "anyOf": [ - { - "$ref": "#/components/schemas/AppProtect" - }, - { - "type": "null" - } - ], - "default": {} - }, - "snippet": { - "anyOf": [ - { - "$ref": "#/components/schemas/ObjectFromSourceOfTruth" - }, - { - "type": "null" - } - ], - "default": {} - }, - "authentication": { - "anyOf": [ - { - "$ref": "#/components/schemas/LocationAuth" - }, - { - "type": "null" - } - ], - "default": {} - }, - "authorization": { - "anyOf": [ - { - "$ref": "#/components/schemas/AuthorizationProfileReference" - }, - { - "type": "null" - } - ], - "default": {} - }, - "headers": { - "anyOf": [ - { - "$ref": "#/components/schemas/V5_5_NginxConfigDeclaration__LocationHeaders" - }, - { - "type": "null" - } - ], - "default": {} - }, - "njs": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/V5_5_NginxConfigDeclaration__NjsHookLocation" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Njs", - "default": [] - }, - "cache": { - "anyOf": [ - { - "$ref": "#/components/schemas/CacheItem" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "uri" - ], - "title": "Location" - }, - "V5_5_NginxConfigDeclaration__LocationHeaders": { - "properties": { - "to_server": { - "anyOf": [ - { - "$ref": "#/components/schemas/LocationHeaderToServer" - }, - { - "type": "null" - } - ], - "default": {} - }, - "to_client": { - "anyOf": [ - { - "$ref": "#/components/schemas/LocationHeaderToClient" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "title": "LocationHeaders" - }, - "V5_5_NginxConfigDeclaration__NjsHookLocation": { - "properties": { - "hook": { - "$ref": "#/components/schemas/NjsHookLocationDetails" - }, - "profile": { - "type": "string", - "title": "Profile" - }, - "function": { - "type": "string", - "title": "Function" - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "hook", - "profile", - "function" - ], - "title": "NjsHookLocation" - }, - "V5_5_NginxConfigDeclaration__NmsCertificate": { - "properties": { - "type": { - "type": "string", - "title": "Type" - }, - "name": { - "type": "string", - "title": "Name" - }, - "contents": { - "anyOf": [ - { - "$ref": "#/components/schemas/ObjectFromSourceOfTruth" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "required": [ - "type", - "name" - ], - "title": "NmsCertificate" - }, - "V5_5_NginxConfigDeclaration__OutputNMS": { - "properties": { - "url": { - "type": "string", - "title": "Url", - "default": "" - }, - "username": { - "type": "string", - "title": "Username", - "default": "" - }, - "password": { - "type": "string", - "title": "Password", - "default": "" - }, - "instancegroup": { - "type": "string", - "title": "Instancegroup", - "default": "" - }, - "synctime": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "title": "Synctime", - "default": 0 - }, - "modules": { - "anyOf": [ - { - "items": { - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Modules", - "default": [] - }, - "certificates": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/V5_5_NginxConfigDeclaration__NmsCertificate" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Certificates", - "default": [] - }, - "policies": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/NGINXPolicy" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Policies", - "default": [] - }, - "log_profiles": { - "anyOf": [ - { - "items": { - "$ref": "#/components/schemas/LogProfile" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Log Profiles", - "default": [] - } - }, - "additionalProperties": false, - "type": "object", - "title": "OutputNMS" - }, - "ValidItem": { - "properties": { - "codes": { - "anyOf": [ - { - "items": { - "type": "integer" - }, - "type": "array" - }, - { - "type": "null" - } - ], - "title": "Codes", - "default": [ - 200 - ] - }, - "ttl": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Ttl", - "default": 60 - } - }, - "additionalProperties": false, - "type": "object", - "title": "ValidItem" - }, - "ValidationError": { - "properties": { - "loc": { - "items": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "integer" - } - ] - }, - "type": "array", - "title": "Location" - }, - "msg": { - "type": "string", - "title": "Message" - }, - "type": { - "type": "string", - "title": "Error Type" - } - }, - "type": "object", - "required": [ - "loc", - "msg", - "type" - ], - "title": "ValidationError" - }, - "Visibility": { - "properties": { - "enabled": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ], - "title": "Enabled", - "default": false - }, - "type": { - "type": "string", - "title": "Type", - "default": "" - }, - "moesif": { - "anyOf": [ - { - "$ref": "#/components/schemas/Visibility_Moesif" - }, - { - "type": "null" - } - ], - "default": {} - } - }, - "additionalProperties": false, - "type": "object", - "title": "Visibility" - }, - "Visibility_Moesif": { - "properties": { - "application_id": { - "type": "string", - "title": "Application Id", - "default": "" - }, - "plugin_path": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Plugin Path", - "default": "/usr/local/share/lua/5.1/resty/moesif" - } - }, - "additionalProperties": false, - "type": "object", - "title": "Visibility_Moesif" - } - } - } -} \ No newline at end of file diff --git a/src/V5_4_CreateConfig.py b/src/V5_4_CreateConfig.py deleted file mode 100644 index 56fbfd60..00000000 --- a/src/V5_4_CreateConfig.py +++ /dev/null @@ -1,898 +0,0 @@ -""" -Configuration creation based on jinja2 templates -""" - -import base64 -import json -import pickle -from urllib.parse import urlparse - -import requests -import schedule -from fastapi.responses import Response, JSONResponse -from jinja2 import Environment, FileSystemLoader -from pydantic import ValidationError -from requests.packages.urllib3.exceptions import InsecureRequestWarning - -import v5_4.APIGateway -import v5_4.DevPortal -import v5_4.DeclarationPatcher -import v5_4.GitOps -import v5_4.MiscUtils -import v5_4.NIMOutput -import v5_4.NGINXOneOutput - -# NGINX App Protect helper functions -import v5_4.NIMNAPUtils -import v5_4.NIMUtils - -# NGINX Declarative API modules -from NcgConfig import NcgConfig -from NcgRedis import NcgRedis - -# pydantic models -from V5_4_NginxConfigDeclaration import * - -# Tolerates self-signed TLS certificates -requests.packages.urllib3.disable_warnings(InsecureRequestWarning) - - -def configautosync(configUid): - print("Autosyncing configuid [" + configUid + "]") - - declaration = '' - declFromRedis = NcgRedis.redis.get(f'ncg.declaration.{configUid}') - - if declFromRedis is not None: - declaration = pickle.loads(declFromRedis) - apiversion = NcgRedis.redis.get(f'ncg.apiversion.{configUid}').decode() - - createconfig(declaration=declaration, apiversion=apiversion, runfromautosync=True, configUid=configUid) - - -# Create the given declarative configuration -# Return a JSON string: -# { "status_code": nnn, "headers": {}, "message": {} } -def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosync: bool = False, configUid: str = ""): - # Building NGINX configuration for the given declaration - - # NGINX configuration files for staged config - configFiles = {'files': []} - - # NGINX auxiliary files for staged config - auxFiles = {'files': []} - - # Extra manifests to be returned to the caller - extraOutputManifests = [] - - try: - # Pydantic JSON validation - ConfigDeclaration(**declaration.model_dump()) - except ValidationError as e: - print(f'Invalid declaration {e}') - - d = declaration.model_dump() - decltype = d['output']['type'] - - j2_env = Environment(loader=FileSystemLoader(NcgConfig.config['templates']['root_dir'] + '/' + apiversion), - trim_blocks=True, extensions=["jinja2_base64_filters.Base64Filters"]) - j2_env.filters['regex_replace'] = v5_4.MiscUtils.regex_replace - - # Check resolver profiles validity and creates resolver config files - if 'resolvers' in d['declaration']: - all_resolver_profiles = [] - - d_resolver_profiles = v5_4.MiscUtils.getDictKey(d, 'declaration.resolvers') - if d_resolver_profiles is not None: - # Render all resolver profiles - for i in range(len(d_resolver_profiles)): - resolver_profile = d_resolver_profiles[i] - - # Add the rendered resolver configuration snippet as a config file in the staged configuration - templateName = NcgConfig.config['templates']['resolver'] - renderedResolverProfile = j2_env.get_template(templateName).render( - resolverprofile=resolver_profile, ncgconfig=NcgConfig.config) - - b64renderedResolverProfile = base64.b64encode(bytes(renderedResolverProfile, 'utf-8')).decode( - 'utf-8') - configFileName = NcgConfig.config['nms']['resolver_dir'] + '/' + resolver_profile['name'].replace(' ', - '_') + ".conf" - resolverProfileConfigFile = {'contents': b64renderedResolverProfile, - 'name': configFileName} - - all_resolver_profiles.append(resolver_profile['name']) - auxFiles['files'].append(resolverProfileConfigFile) - - if 'http' in d['declaration']: - if 'snippet' in d['declaration']['http']: - status, snippet = v5_4.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}} - - d['declaration']['http']['snippet'] = snippet - - # Check HTTP upstreams validity - all_upstreams = [] - http = d['declaration']['http'] - - if 'upstreams' in http: - for i in range(len(http['upstreams'])): - upstream = http['upstreams'][i] - - if upstream['resolver'] and upstream['resolver'] not in all_resolver_profiles: - return {"status_code": 422, - "message": {"status_code": status, "message": - {"code": status, - "content": f"invalid resolver profile [{upstream['resolver']}] in HTTP upstream [{upstream['name']}], must be one of {all_resolver_profiles}"}}} - - if upstream['snippet']: - status, snippet = v5_4.GitOps.getObjectFromRepo(object = upstream['snippet'], authProfiles = d['declaration']['http']['authentication']) - - if status != 200: - return {"status_code": 422, "message": {"status_code": status, "message": snippet}} - - d['declaration']['http']['upstreams'][i]['snippet'] = snippet - - # Add the rendered upstream configuration snippet as a config file in the staged configuration - templateName = NcgConfig.config['templates']['upstream_http'] - renderedUpstreamProfile = j2_env.get_template(templateName).render( - u=upstream, ncgconfig=NcgConfig.config) - - b64renderedUpstreamProfile = base64.b64encode(bytes(renderedUpstreamProfile, 'utf-8')).decode( - 'utf-8') - configFileName = NcgConfig.config['nms']['upstream_http_dir'] + '/' + upstream['name'].replace(' ', '_') + ".conf" - upstreamProfileConfigFile = {'contents': b64renderedUpstreamProfile, - 'name': configFileName} - - auxFiles['files'].append(upstreamProfileConfigFile) - all_upstreams.append(http['upstreams'][i]['name']) - - http = d['declaration']['http'] - - # Check HTTP rate_limit profiles validity - all_ratelimits = [] - - d_rate_limit = v5_4.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']) - - # Check HTTP cache profiles validity - all_cache_profiles = [] - - d_cache_profiles = v5_4.MiscUtils.getDictKey(d, 'declaration.http.cache') - if d_cache_profiles is not None: - for i in range(len(d_cache_profiles)): - all_cache_profiles.append(d_cache_profiles[i]['name']) - - # Check authentication profiles validity and creates authentication config files - - # List of all auth client & server profile names - all_auth_client_profiles = [] - all_auth_server_profiles = [] - - d_auth_profiles = v5_4.MiscUtils.getDictKey(d, 'declaration.http.authentication') - if d_auth_profiles is not None: - if 'client' in d_auth_profiles: - # Render all client authentication profiles - - auth_client_profiles = d_auth_profiles['client'] - for i in range(len(auth_client_profiles)): - auth_profile = auth_client_profiles[i] - - match auth_profile['type']: - case 'jwt': - # Add the rendered authentication configuration snippet as a config file in the staged configuration - jwt template - templateName = NcgConfig.config['templates']['auth_client_root']+"/jwt.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) - - # Add the rendered authentication configuration snippet as a config file in the staged configuration - jwks template - templateName = NcgConfig.config['templates']['auth_client_root']+"/jwks.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'] + '/jwks_'+auth_profile['name'].replace(' ','_')+".conf" - authProfileConfigFile = {'contents': b64renderedClientAuthProfile, - 'name': configFileName } - - 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) - - case 'oidc': - # Add the rendered authentication configuration snippet as a config file in the staged configuration - OpenID Connect template - templateName = NcgConfig.config['templates']['auth_client_root'] + "/oidc.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'] + '/oidc/' + 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 - - auth_server_profiles = d_auth_profiles['server'] - for i in range(len(auth_server_profiles)): - auth_profile = auth_server_profiles[i] - - match auth_profile['type']: - case 'token': - # 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) - - 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) - - 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_4.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} - - auxFiles['files'].append(authProfileConfigFile) - - # NGINX Javascript profiles - all_njs_profiles = [] - d_njs_files = v5_4.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_4.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) - - # NGINX ACME issuer profiles - d_acme_issuers = v5_4.MiscUtils.getDictKey(d, 'declaration.http.acme_issuers') - all_acme_issuers = [] - if d_acme_issuers is not None: - # Render all ACME issuer profiles - for i in range(len(d_acme_issuers)): - acme_issuer = d_acme_issuers[i] - - # Add the rendered resolver configuration snippet as a config file in the staged configuration - templateName = NcgConfig.config['templates']['acme_issuer'] - renderedAcmeIssuerProfile = j2_env.get_template(templateName).render( - acmeprofile=acme_issuer, ncgconfig=NcgConfig.config) - - b64renderedAcmeProfile = base64.b64encode(bytes(renderedAcmeIssuerProfile, 'utf-8')).decode( - 'utf-8') - configFileName = NcgConfig.config['nms']['acme_dir'] + '/' + acme_issuer['name'].replace( - ' ','_') + ".conf" - acmeProfileConfigFile = {'contents': b64renderedAcmeProfile, - 'name': configFileName} - - all_acme_issuers.append(acme_issuer['name']) - auxFiles['files'].append(acmeProfileConfigFile) - - # HTTP level Javascript hooks - d_http_njs_hooks = v5_4.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}"}}} - - # HTTP level resolver validity check - d_http_resolver = v5_4.MiscUtils.getDictKey(d, 'declaration.http.resolver') - if d_http_resolver: - if d_http_resolver not in all_resolver_profiles: - return {"status_code": 422, - "message": {"status_code": status, "message": - {"code": status, - "content": f"invalid resolver profile [{d_http_resolver}] in HTTP context, must be one of {all_resolver_profiles}"}}} - - # Parse HTTP servers - d_servers = v5_4.MiscUtils.getDictKey(d, 'declaration.http.servers') - if d_servers is not None: - for server in d_servers: - serverSnippet = '' - - # Server level resolver name validity check - if server['resolver']: - if server['resolver'] not in all_resolver_profiles: - return {"status_code": 422, - "message": {"status_code": status, "message": - {"code": status, - "content": f"invalid resolver profile [{server['resolver']}] in HTTP server [{server['name']}], must be one of {all_resolver_profiles}"}}} - - # Server level cache profile name validity - if server['cache']: - if server['cache']['profile'] not in all_cache_profiles and server['cache']['profile'] != "": - return {"status_code": 422, - "message": {"status_code": status, "message": - {"code": status, - "content": f"invalid cache profile [{server['cache']['profile']}] in HTTP server [{server['name']}], must be one of {all_cache_profiles}"}}} - - # 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}"}}} - - # Server 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}"}}} - - # ACME issuers name validity check - if 'acme_issuer' in server['listen']['tls']: - acmeIssuer = server['listen']['tls']['acme_issuer'] - if acmeIssuer and acmeIssuer not in all_acme_issuers: - return {"status_code": 422, - "message": {"status_code": status, "message": - {"code": status, - "content": f"invalid ACME issuer [{acmeIssuer}] in server [{server['name']}] must be one of {all_acme_issuers}"}}} - - if server['snippet']: - status, serverSnippet = v5_4.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}} - - serverSnippet = serverSnippet['content'] - - # Create HTTP server configuration file - httpServerConf = j2_env.get_template(NcgConfig.config['templates']['server_http']).render(declaration=d['declaration']['http'], s=server, ncgconfig=NcgConfig.config) - httpServerConfb64 = base64.b64encode(bytes(httpServerConf, 'utf-8')).decode('utf-8') - newHttpServerAuxFile = {'contents': httpServerConfb64, 'name': NcgConfig.config['nms']['server_http_dir'] + - '/' + server['name'].replace(' ', '_') + ".conf"} - auxFiles['files'].append(newHttpServerAuxFile) - - 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 = v5_4.GitOps.getObjectFromRepo(object = loc['snippet'], authProfiles = d['declaration']['http']['authentication']) - - if status != 200: - return {"status_code": 422, "message": {"status_code": status, "message": snippet}} - - loc['snippet'] = snippet - - # Location upstream name validity check - if 'upstream' in loc and loc['upstream'] and urlparse(loc['upstream']).netloc not in all_upstreams: - return {"status_code": 422, - "message": {"status_code": status, "message": - {"code": status, "content": f"invalid HTTP upstream [{loc['upstream']}]"}}} - - # Location client authentication name validity check - if 'authentication' in loc and loc['authentication']: - locAuthClientProfiles = loc['authentication']['client'] - - for authClientProfile in locAuthClientProfiles: - 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']}] 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']: - locAuthServerProfiles = loc['authentication']['server'] - - for authServerProfile in locAuthServerProfiles: - if authServerProfile['profile'] not in all_auth_server_profiles: - return {"status_code": 422, - "message": {"status_code": status, "message": - {"code": status, "content": f"invalid server authentication profile [{authServerProfile['profile']}] in location [{loc['uri']}]"}}} - - # API Gateway visualization integrations - apiGwVisibilityIntegrations = {} - - if loc['apigateway'] and loc['apigateway']['visibility']: - visibility_integrations = loc['apigateway']['visibility'] - for i in range(len(visibility_integrations)): - vis = visibility_integrations[i] - - if vis['enabled'] == True: - apiGwVisibilityIntegrations[ vis['type'] ] = True - - if vis['type'].lower() == 'moesif': - # Moesif integration - - # Add the rendered Moesif visibility configuration snippet as a config file in the staged configuration - HTTP context - templateName = NcgConfig.config['templates'][ - 'visibility_root'] + "/moesif/http.tmpl" - renderedMoesifHTTP = j2_env.get_template(templateName).render( - vis=vis, loc=loc, ncgconfig=NcgConfig.config) - - b64renderedMoesifHTTP = base64.b64encode( - bytes(renderedMoesifHTTP, 'utf-8')).decode( - 'utf-8') - moesifHTTPConfigFile = {'contents': b64renderedMoesifHTTP, - 'name': NcgConfig.config['nms'][ - 'visibility_dir'] + - loc['uri'] + "-moesif-http.conf"} - - auxFiles['files'].append(moesifHTTPConfigFile) - - # Add the rendered Moesif visibility configuration snippet as a config file in the staged configuration - server context - templateName = NcgConfig.config['templates'][ - 'visibility_root'] + "/moesif/server.tmpl" - renderedMoesifServer = j2_env.get_template(templateName).render( - vis=vis, loc=loc, ncgconfig=NcgConfig.config) - - b64renderedMoesifServer = base64.b64encode( - bytes(renderedMoesifServer, 'utf-8')).decode( - 'utf-8') - moesifServerConfigFile = {'contents': b64renderedMoesifServer, - 'name': NcgConfig.config['nms'][ - 'visibility_dir'] + - loc['uri'] + "-moesif-server.conf"} - - auxFiles['files'].append(moesifServerConfigFile) - - # API Gateway provisioning - if loc['apigateway'] and loc['apigateway']['api_gateway'] and loc['apigateway']['api_gateway']['enabled'] and loc['apigateway']['api_gateway']['enabled'] == True: - - # API Gateway authentication profile names validity check - if loc['apigateway']['authentication'] and loc['apigateway']['authentication']['client']: - apigw_authn_profiles = loc['apigateway']['authentication']['client'] - for i in range(len(apigw_authn_profiles)): - if apigw_authn_profiles[i]['profile'] not in all_auth_client_profiles: - return {"status_code": 422, - "message": {"status_code": status, "message": - {"code": status, - "content": f"invalid API Gateway authentication profile [{apigw_authn_profiles[i]['profile']}] for OpenAPI schema [{loc['apigateway']['openapi_schema']['content']}] must be one of {all_auth_client_profiles}"}}} - - # API Gateway authorization profile names validity check - if loc['apigateway']['authorization']: - apigw_authz_profiles = loc['apigateway']['authorization'] - for i in range(len(apigw_authz_profiles)): - if apigw_authz_profiles[i]['profile'] not in all_authz_client_profiles: - return {"status_code": 422, - "message": {"status_code": status, "message": - {"code": status, - "content": f"invalid API Gateway authorization profile [{apigw_authz_profiles[i]['profile']}] for OpenAPI schema [{loc['apigateway']['openapi_schema']['content']}] must be one of {all_authz_client_profiles}"}}} - - # API Gateway rate limiting profile names validity check - if loc['apigateway']['rate_limit']: - apigw_rl_profiles = loc['apigateway']['rate_limit'] - for i in range(len(apigw_rl_profiles)): - if apigw_rl_profiles[i]['profile'] not in all_ratelimits: - return {"status_code": 422, - "message": {"status_code": status, "message": - {"code": status, - "content": f"invalid API Gateway rate limit profile [{apigw_authz_profiles[i]['profile']}] for OpenAPI schema [{loc['apigateway']['openapi_schema']['content']}] must be one of {all_ratelimits}"}}} - - openApiAuthProfile = loc['apigateway']['openapi_schema']['authentication'] - if openApiAuthProfile and openApiAuthProfile[0]['profile'] not in all_auth_server_profiles: - return {"status_code": 422, - "message": {"status_code": status, "message": - {"code": status, - "content": f"invalid server authentication profile [{openApiAuthProfile[0]['profile']}] for OpenAPI schema [{loc['apigateway']['openapi_schema']['content']}]"}}} - - status, apiGatewayConfigDeclaration, openAPISchemaJSON = v5_4.APIGateway.createAPIGateway(locationDeclaration = loc, authProfiles = loc['apigateway']['openapi_schema']['authentication']) - - # API Gateway configuration template rendering - if apiGatewayConfigDeclaration: - apiGatewaySnippet = j2_env.get_template(NcgConfig.config['templates']['apigwconf']).render( - declaration=apiGatewayConfigDeclaration, enabledVisibility=apiGwVisibilityIntegrations, ncgconfig=NcgConfig.config) - apiGatewaySnippetb64 = base64.b64encode(bytes(apiGatewaySnippet, 'utf-8')).decode('utf-8') - - newAuxFile = {'contents': apiGatewaySnippetb64, 'name': NcgConfig.config['nms']['apigw_dir'] + - '/' + server['names'][0] + - 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: - - if loc['apigateway']['developer_portal']['type'].lower() == 'redocly': - ### Redocly developer portal - Add optional API Developer portal HTML files - status, devPortalHTML = v5_4.DevPortal.createDevPortal(locationDeclaration=loc, - authProfiles= - d['declaration']['http'][ - 'authentication']) - - if status != 200: - return {"status_code": 412, - "message": {"status_code": status, "message": - {"code": status, - "content": f"Developer Portal creation failed for {loc['uri']}"}}} - - newAuxFile = {'contents': devPortalHTML, 'name': NcgConfig.config['nms']['devportal_dir'] + - loc['apigateway']['developer_portal']['redocly']['uri']} - auxFiles['files'].append(newAuxFile) - - ### / Redocly developer portal - Add optional API Developer portal HTML files - elif loc['apigateway']['developer_portal']['type'].lower() == 'backstage': - ### Backstage developer portal - Create Kubernetes Backstage manifest - backstageManifest = j2_env.get_template(f"{NcgConfig.config['templates']['devportal_root']}/backstage.tmpl").render( - declaration=loc['apigateway']['developer_portal']['backstage'], openAPISchema = v5_4.MiscUtils.json_to_yaml(openAPISchemaJSON), ncgconfig=NcgConfig.config) - - extraOutputManifests.append(backstageManifest) - ### / Backstage developer portal - Create Kubernetes Backstage manifest - - # Check location-level rate limit profile name validity - if loc['rate_limit'] is not None: - if 'profile' in loc['rate_limit'] and loc['rate_limit']['profile'] and loc['rate_limit'][ - 'profile'] not in all_ratelimits: - return {"status_code": 422, - "message": { - "status_code": status, - "message": - {"code": status, - "content": - f"invalid rate_limit profile [{loc['rate_limit']['profile']}]"}}} - - # Check location-level cache profile name validity - if loc['cache'] is not None: - if 'profile' in loc['cache'] and loc['cache']['profile'] and loc['cache'][ - 'profile'] not in all_cache_profiles and loc['cache'][ - 'profile'] != "": - return {"status_code": 422, - "message": { - "status_code": status, - "message": - {"code": status, - "content": - f"invalid cache profile [{loc['cache']['profile']}]"}}} - - 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 = v5_4.MiscUtils.getDictKey(d, 'declaration.layer4.upstreams') - if d_upstreams is not None: - for i in range(len(d_upstreams)): - upstream = d_upstreams[i] - - if upstream['resolver'] and upstream['resolver'] not in all_resolver_profiles: - return {"status_code": 422, - "message": {"status_code": status, "message": - {"code": status, - "content": f"invalid resolver profile [{upstream['resolver']}] in stream upstream [{upstream['name']}], must be one of {all_resolver_profiles}"}}} - - if upstream['snippet']: - status, snippet = v5_4.GitOps.getObjectFromRepo(object = upstream['snippet'], authProfiles = d['declaration']['http']['authentication']) - - if status != 200: - return {"status_code": 422, "message": {"status_code": status, "message": snippet}} - - d['declaration']['layer4']['upstreams'][i]['snippet'] = snippet - - # Add the rendered upstream configuration snippet as a config file in the staged configuration - templateName = NcgConfig.config['templates']['upstream_stream'] - renderedUpstreamProfile = j2_env.get_template(templateName).render( - u=upstream, ncgconfig=NcgConfig.config) - - b64renderedUpstreamProfile = base64.b64encode(bytes(renderedUpstreamProfile, 'utf-8')).decode( - 'utf-8') - configFileName = NcgConfig.config['nms']['upstream_stream_dir'] + '/' + upstream['name'].replace(' ', '_') + ".conf" - upstreamProfileConfigFile = {'contents': b64renderedUpstreamProfile, - 'name': configFileName} - - auxFiles['files'].append(upstreamProfileConfigFile) - - all_upstreams.append(d_upstreams[i]['name']) - - d_servers = v5_4.MiscUtils.getDictKey(d, 'declaration.layer4.servers') - if d_servers is not None: - for server in d_servers: - - # Server level resolver name validity check - if server['resolver']: - if server['resolver'] not in all_resolver_profiles: - return {"status_code": 422, - "message": {"status_code": status, "message": - {"code": status, - "content": f"invalid resolver profile [{server['resolver'] }] in stream server [{server['name']}], must be one of {all_resolver_profiles}"}}} - - if server['snippet']: - status, snippet = v5_4.GitOps.getObjectFromRepo(object = server['snippet'], authProfiles = d['declaration']['http']['authentication']) - - if status != 200: - return {"status_code": 422, "message": {"status_code": status, "message": snippet}} - - server['snippet'] = snippet - - if 'upstream' in server and server['upstream'] and server['upstream'] not in all_upstreams: - return {"status_code": 422, - "message": { - "status_code": status, - "message": - {"code": status, "content": f"invalid Layer4 upstream {server['upstream']}"}}} - - # Create Stream server configuration file - streamServerConf = j2_env.get_template(NcgConfig.config['templates']['server_stream']).render(s=server, ncgconfig=NcgConfig.config) - streamServerConfb64 = base64.b64encode(bytes(streamServerConf, 'utf-8')).decode('utf-8') - newStreamServerAuxFile = {'contents': streamServerConfb64, 'name': NcgConfig.config['nms']['server_stream_dir'] + - '/' + server['name'].replace(' ', '_') + ".conf"} - auxFiles['files'].append(newStreamServerAuxFile) - - # HTTP configuration template rendering - httpConf = j2_env.get_template(NcgConfig.config['templates']['httpconf']).render( - declaration=d['declaration']['http'], ncgconfig=NcgConfig.config) if 'http' in d['declaration'] else '' - - # Stream configuration template rendering - streamConf = j2_env.get_template(NcgConfig.config['templates']['streamconf']).render( - declaration=d['declaration']['layer4'], ncgconfig=NcgConfig.config) if 'layer4' in d['declaration'] else '' - - b64HttpConf = str(base64.b64encode(httpConf.encode("utf-8")), "utf-8") - b64StreamConf = str(base64.b64encode(streamConf.encode("utf-8")), "utf-8") - - if decltype.lower() == 'nms': - # Output to NGINX Instance Manager - - # NGINX configuration files for staged config - configFiles['rootDir'] = NcgConfig.config['nms']['config_dir'] - - # NGINX auxiliary files for staged config - auxFiles['rootDir'] = NcgConfig.config['nms']['config_dir'] - - finalReply = v5_4.NIMOutput.NIMOutput(d = d, declaration = declaration, apiversion = apiversion, - b64HttpConf = b64HttpConf, b64StreamConf = b64StreamConf, - configFiles = configFiles, - auxFiles = auxFiles, - runfromautosync = runfromautosync, configUid = configUid ) - - if finalReply['status_code'] == 200: - if len(extraOutputManifests) > 0: - finalReply['message']['message']['content']['manifests'] = extraOutputManifests - - return finalReply - - elif decltype.lower() == 'nginxone': - # Output to NGINX One Console - - # NGINX configuration files for staged config - configFiles['name'] = NcgConfig.config['nms']['config_dir'] - - # NGINX auxiliary files for staged config - auxFiles['name'] = NcgConfig.config['nms']['config_dir'] - - finalReply = v5_4.NGINXOneOutput.NGINXOneOutput(d = d, declaration = declaration, apiversion = apiversion, - b64HttpConf = b64HttpConf, b64StreamConf = b64StreamConf, - configFiles = configFiles, - auxFiles = auxFiles, - runfromautosync = runfromautosync, configUid = configUid ) - - if finalReply['status_code'] == 200: - if len(extraOutputManifests) > 0: - finalReply['message']['message']['content']['manifests'] = extraOutputManifests - - return finalReply - else: - return {"status_code": 422, "message": {"status_code": 422, "message": f"output type {decltype} unknown"}} - - -def patch_config(declaration: ConfigDeclaration, configUid: str, apiversion: str): - # Patch a declaration - if configUid not in NcgRedis.declarationsList: - return JSONResponse( - status_code=404, - content={'code': 404, 'details': {'message': f'declaration {configUid} not found'}}, - headers={'Content-Type': 'application/json'} - ) - - # The declaration sections to be patched - declarationToPatch = declaration.model_dump() - - # The currently applied declaration - status_code, currentDeclaration = get_declaration(configUid=configUid) - - # Handle policy updates - d_policies = v5_4.MiscUtils.getDictKey(declarationToPatch, 'output.nms.policies') - if d_policies is not None: - # NGINX App Protect WAF policy updates - for p in d_policies: - currentDeclaration = v5_4.DeclarationPatcher.patchNAPPolicies( - sourceDeclaration=currentDeclaration, patchedNAPPolicies=p) - - # Handle certificate updates - d_certificates = v5_4.MiscUtils.getDictKey(declarationToPatch, 'output.nms.certificates') - if d_certificates is not None: - # TLS certificate/key updates - for p in d_certificates: - currentDeclaration = v5_4.DeclarationPatcher.patchCertificates( - sourceDeclaration=currentDeclaration, patchedCertificates=p) - - # Handle declaration updates - if 'declaration' in declarationToPatch: - # HTTP - d_upstreams = v5_4.MiscUtils.getDictKey(declarationToPatch, 'declaration.http.upstreams') - if d_upstreams: - # HTTP upstream patch - for u in d_upstreams: - currentDeclaration = v5_4.DeclarationPatcher.patchHttpUpstream( - sourceDeclaration=currentDeclaration, patchedHttpUpstream=u) - - d_servers = v5_4.MiscUtils.getDictKey(declarationToPatch, 'declaration.http.servers') - if d_servers: - # HTTP servers patch - for s in d_servers: - currentDeclaration = v5_4.DeclarationPatcher.patchHttpServer( - sourceDeclaration=currentDeclaration, patchedHttpServer=s) - - # Stream / Layer4 - d_upstreams = v5_4.MiscUtils.getDictKey(declarationToPatch, 'declaration.layer4.upstreams') - if d_upstreams: - # Stream upstream patch - for u in d_upstreams: - currentDeclaration = v5_4.DeclarationPatcher.patchStreamUpstream( - sourceDeclaration=currentDeclaration, patchedStreamUpstream=u) - - d_servers = v5_4.MiscUtils.getDictKey(declarationToPatch, 'declaration.layer4.servers') - if d_servers: - # Stream servers patch - for s in d_servers: - currentDeclaration = v5_4.DeclarationPatcher.patchStreamServer( - sourceDeclaration=currentDeclaration, patchedStreamServer=s) - - # Apply the updated declaration - configDeclaration = ConfigDeclaration.model_validate_json(json.dumps(currentDeclaration)) - - r = createconfig(declaration=configDeclaration, apiversion=apiversion, - runfromautosync=True, configUid=configUid) - - # Return the updated declaration - message = r['message'] - - if r['status_code'] != 200: - currentDeclaration = {} - # message = f'declaration {configUid} update failed'; - - responseContent = {'code': r['status_code'], 'details': {'message': message}, - 'declaration': currentDeclaration, 'configUid': configUid} - - return JSONResponse( - status_code=r['status_code'], - content=responseContent, - headers={'Content-Type': 'application/json'} - ) - - -# Gets the given declaration. Returns status_code and body -def get_declaration(configUid: str): - cfg = NcgRedis.redis.get('ncg.declaration.' + configUid) - - if cfg is None: - return 404, "" - - return 200, pickle.loads(cfg).dict() diff --git a/src/V5_4_NginxConfigDeclaration.py b/src/V5_4_NginxConfigDeclaration.py deleted file mode 100644 index 56246485..00000000 --- a/src/V5_4_NginxConfigDeclaration.py +++ /dev/null @@ -1,1038 +0,0 @@ -""" -JSON declaration structure -""" - -from __future__ import annotations -from typing import List, Optional -from pydantic import BaseModel, model_validator - -import re - -# Regexp to check names -alphanumRegexp = r'^[a-zA-Z0-9\ \-\_]+$' - - -class NmsCertificate(BaseModel, extra="forbid"): - type: str - name: str - contents: Optional[ObjectFromSourceOfTruth] = {} - - @model_validator(mode='after') - def check_type(self) -> 'NmsCertificate': - _type = self.type - - valid = ['certificate', 'key'] - if _type not in valid: - raise ValueError(f"Invalid certificate type [{_type}] must be one of {str(valid)}") - - return self - - -class NGINXPolicyVersion(BaseModel, extra="forbid"): - tag: str = "" - displayName: Optional[str] = "" - description: Optional[str] = "" - contents: Optional[ObjectFromSourceOfTruth] = {} - - -class NGINXPolicy(BaseModel, extra="forbid"): - type: str = "" - name: str = "" # Name must be identical to the policy name used in the App Protect policy JSON file - active_tag: str = "" - versions: Optional[List[NGINXPolicyVersion]] = [] - - @model_validator(mode='after') - def check_type(self) -> 'NGINXPolicy': - _type = self.type - - valid = ['app_protect'] - if _type not in valid: - raise ValueError(f"Invalid policy type [{_type}] must be one of {str(valid)}") - - return self - - -class AppProtectLogProfile(BaseModel, extra="forbid"): - name: str - format: Optional[str] = "default" - format_string: Optional[str] = "" - type: Optional[str] = "blocked" - max_request_size: Optional[str] = "any" - max_message_size: Optional[str] = "5k" - - @model_validator(mode='after') - def check_type(self) -> 'AppProtectLogProfile': - _type, _format, _format_string = self.type, self.format, self.format_string - - valid = ['all', 'illegal', 'blocked'] - if _type not in valid: - raise ValueError(f"Invalid NGINX App Protect log type [{_type}] must be one of {str(valid)}") - - valid = ['default', 'grpc', 'arcsight', 'splunk', 'user-defined'] - if _format not in valid: - raise ValueError(f"Invalid NGINX App Protect log format [{_format}] must be one of {str(valid)}") - - if _format == 'user-defined' and _format_string == "": - raise ValueError(f"NGINX App Protect log format {_format} requires format_string") - - return self - - -class LogProfile(BaseModel, extra="forbid"): - type: str - app_protect: Optional[AppProtectLogProfile] = {} - - @model_validator(mode='after') - def check_type(self) -> 'LogProfile': - _type, app_protect = self.type, self.app_protect - - valid = ['app_protect'] - if _type not in valid: - raise ValueError(f"Invalid log profile type [{_type}] must be one of {str(valid)}") - - isError = False - if _type == 'app_protect': - if app_protect is None: - isError = True - - if isError: - raise ValueError(f"Invalid log profile data for type [{_type}]") - - return self - - -class OutputNMS(BaseModel, extra="forbid"): - url: str = "" - username: str = "" - password: str = "" - instancegroup: str = "" - synctime: Optional[int] = 0 - modules: Optional[List[str]] = [] - certificates: Optional[List[NmsCertificate]] = [] - policies: Optional[List[NGINXPolicy]] = [] - log_profiles: Optional[List[LogProfile]] = [] - - -class OutputNGINXOne(BaseModel, extra="forbid"): - url: str = "" - namespace: str = "" - token: str = "" - configsyncgroup: str = "" - synctime: Optional[int] = 0 - modules: Optional[List[str]] = [] - certificates: Optional[List[NmsCertificate]] = [] - policies: Optional[List[NGINXPolicy]] = [] - log_profiles: Optional[List[LogProfile]] = [] - - -class License(BaseModel, extra="forbid"): - endpoint: Optional[str] = "product.connect.nginx.com" - token: Optional[str] = "" - ssl_verify: bool = True - grace_period: bool = False - - -class Output(BaseModel, extra="forbid"): - type: str - synchronous: bool = True - license: Optional[License] = {} - nms: Optional[OutputNMS] = {} - nginxone: Optional[OutputNGINXOne] = {} - - @model_validator(mode='after') - def check_type(self) -> 'Output': - _type,nms, nginxone = self.type, self.nms, self.nginxone - - valid = ['nms', 'nginxone'] - if _type not in valid: - raise ValueError(f"Invalid output type [{_type}] must be one of {str(valid)}") - - isError = False - - if _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}]") - - return self - - -class OcspStapling(BaseModel, extra="forbid"): - enabled: Optional[bool] = False - verify: Optional[bool] = False - responder: Optional[str] = "" - - -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 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) -> 'AuthClientMtls': - _enabled = self.enabled - - valid = ['on', 'off', 'optional', 'optional_no_ca'] - if _enabled not in valid: - raise ValueError(f"Invalid mTLS type [{_enabled}] must be one of {str(valid)}") - - return self - - -class L4Tls(BaseModel, extra="forbid"): - certificate: str = "" - key: str = "" - ciphers: Optional[str] = "" - protocols: Optional[List[str]] = [] - authentication: Optional[LocationAuth] = {} - - -class Tls(BaseModel, extra="forbid"): - certificate: Optional[str] = "" - key: Optional[str] = "" - acme_issuer: Optional[str] = "" - ciphers: Optional[str] = "" - protocols: Optional[List[str]] = [] - authentication: Optional[LocationAuth] = {} - - @model_validator(mode='after') - def check_type(self) -> 'Tls': - certificate, key, acme_issuer = self.certificate, self.key, self.acme_issuer - - if acme_issuer and (certificate or key): - raise ValueError(f"Certificate and key not allowed when ACME is used") - - if not acme_issuer and (not certificate or not key): - raise ValueError(f"Certificate and key required") - - return self - -class Listen(BaseModel, extra="forbid"): - address: Optional[str] = "" - http2: Optional[bool] = False - tls: Optional[Tls] = {} - - -class ListenL4(BaseModel, extra="forbid"): - address: Optional[str] = "" - protocol: Optional[str] = "tcp" - tls: Optional[L4Tls] = {} - - @model_validator(mode='after') - def check_type(self) -> 'ListenL4': - protocol, tls = self.protocol, self.tls - - valid = ['tcp', 'udp'] - if protocol not in valid: - raise ValueError(f"Invalid protocol [{protocol}] must be one of {str(valid)}") - - if protocol != 'tcp' and tls and tls.certificate: - raise ValueError("TLS termination over UDP is not supported") - - return self - - -class Log(BaseModel, extra="forbid"): - access: Optional[LogAccess] = {} - error: Optional[LogError] = {} - - -class LogAccess(BaseModel, extra="forbid"): - destination: str - format: Optional[str] = "combined" - condition: Optional[str] = "" - - -class LogError(BaseModel, extra="forbid"): - destination: str - level: Optional[str] = "info" - - @model_validator(mode='after') - def check_type(self) -> 'LogError': - level = self.level - - valid = ['debug','info','notice','warn','error','crit','alert','emerg'] - if level not in valid: - raise ValueError(f"Invalid error log level [{level}] must be one of {str(valid)}") - - return self - -class RateLimit(BaseModel, extra="forbid"): - profile: Optional[str] = "" - httpcode: Optional[int] = 429 - burst: Optional[int] = 0 - delay: Optional[int] = 0 - - -class LocationAuthClient(BaseModel, extra="forbid"): - profile: Optional[str] = "" - - -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 - burst: Optional[int] = 0 - delay: Optional[int] = 0 - enforceOnPaths: Optional[bool] = True - paths: Optional[List[str]] = [] - -class APIGatewayAuthentication(BaseModel, extra="forbid"): - client: Optional[List[LocationAuthClient]] = [] - enforceOnPaths: Optional[bool] = True - paths: Optional[List[str]] = [] - - -class APIGatewayAuthorization(BaseModel, extra="forbid"): - profile: str - enforceOnPaths: Optional[bool] = True - paths: Optional[List[str]] = [] - - -class APIGatewayCache(BaseModel, extra="forbid"): - profile: str - key: Optional[str] = "$scheme$proxy_host$request_uri"; - validity: Optional[List[CacheObjectTTL]] = [] - enforceOnPaths: Optional[bool] = True - paths: Optional[List[str]] = [] - - @model_validator(mode='after') - def check_type(self) -> 'APIGatewayCache': - profile = self.profile - - if not re.search(alphanumRegexp,profile): - raise ValueError(f"Invalid cache item [{profile}] should match regexp {alphanumRegexp}") - - return self - - -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") - - valid = ['signed', 'encrypted', 'nested'] - if jwt_type not in valid: - raise ValueError(f"Invalid JWT type [{jwt_type}] must be one of {str(valid)}") - - return self - - -class AcmeIssuers(BaseModel, extra="forbid"): - name: str = "" - uri: str = "" - account_key: Optional[str] = "" - contact: Optional[str] = "" - ssl_trusted_certificate: Optional[str] = "" - ssl_verify: Optional[bool] = False - state_path: Optional[str] = "" - accept_terms_of_service: Optional[bool] = False - - -class AuthClientOIDC(BaseModel, extra="forbid"): - issuer: str = "" - client_id: str = "" - client_secret: str = "" - config_url: Optional[str] = "" - cookie_name: Optional[str] = "" - extra_auth_args: Optional[str] = "" - redirect_uri: Optional[str] = "/oidc_callback" - logout_uri: Optional[str] = "" - post_logout_uri: Optional[str] = "" - logout_token_hint: Optional[bool] = False - scope: Optional[str] = "openid" - session_store: Optional[str] = "" - session_timeout: Optional[str] = "8h" - ssl_crl: Optional[str] = "" - ssl_trusted_certificate: Optional[str] = "" - userinfo: Optional[bool] = False - - -class AuthServerToken(BaseModel, extra="forbid"): - token: str = "" - type: Optional[str] = "" - location: Optional[str] = "" - username: Optional[str] = "" - password: Optional[str] = "" - - @model_validator(mode='after') - def check_type(self) -> 'AuthServerToken': - 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 = "" - - -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] = "/" - interval: Optional[int] = 5 - fails: Optional[int] = 1 - passes: Optional[int] = 1 - - -class AppProtectLog(BaseModel, extra="forbid"): - enabled: Optional[bool] = False - profile_name: Optional[str] = "" - destination: Optional[str] = "" - - -class AppProtect(BaseModel, extra="forbid"): - enabled: Optional[bool] = False - policy: str = "" - log: AppProtectLog = {} - - -class Location(BaseModel, extra="forbid"): - uri: str - urimatch: Optional[str] = "prefix" - upstream: Optional[str] = "" - log: Optional[Log] = {} - apigateway: Optional[APIGateway] = {} - caching: Optional[str] = "" - rate_limit: Optional[RateLimit] = {} - health_check: Optional[HealthCheck] = {} - app_protect: Optional[AppProtect] = {} - snippet: Optional[ObjectFromSourceOfTruth] = {} - authentication: Optional[LocationAuth] = {} - authorization: Optional[AuthorizationProfileReference] = {} - headers: Optional[LocationHeaders] = {} - njs: Optional[List[NjsHookLocation]] = [] - cache: Optional[CacheItem] = {} - - @model_validator(mode='after') - def check_type(self) -> 'Location': - urimatch = self.urimatch - upstream = self.upstream - - valid = ['prefix', 'exact', 'regex', 'iregex', 'best'] - if urimatch not in valid: - raise ValueError(f"Invalid URI match type [{urimatch}] must be one of {str(valid)}") - - prefixes = ["http://", "https://"] - if upstream != "" and not upstream.lower().startswith(tuple(prefixes)): - raise ValueError(f"Upstream must start with one of {str(prefixes)}") - - return self - - -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]] = [] - resolver: Optional[str] = "" - listen: Optional[Listen] = {} - log: Optional[Log] = {} - locations: Optional[List[Location]] = [] - app_protect: Optional[AppProtect] = {} - snippet: Optional[ObjectFromSourceOfTruth] = {} - headers: Optional[LocationHeaders] = {} - njs: Optional[List[NjsHookHttpServer]] = [] - authentication: Optional[LocationAuth] = {} - authorization: Optional[AuthorizationProfileReference] = {} - cache: Optional[CacheItem] = {} - - @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"): - name: str - resolver: Optional[str] = "" - listen: Optional[ListenL4] = {} - 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 = "" - expires: Optional[str] = "" - domain: Optional[str] = "" - path: Optional[str] = "" - - -class Origin(BaseModel, extra="forbid"): - server: str - weight: Optional[int] = 1 - max_fails: Optional[int] = 1 - fail_timeout: Optional[str] = "10s" - max_conns: Optional[int] = 0 - slow_start: Optional[str] = "0" - backup: Optional[bool] = False - - -class L4Origin(BaseModel, extra="forbid"): - server: str - weight: Optional[int] = 1 - max_fails: Optional[int] = 1 - fail_timeout: Optional[str] = "10s" - max_conns: Optional[int] = 0 - slow_start: Optional[str] = "0" - backup: Optional[bool] = False - - -class Upstream(BaseModel, extra="forbid"): - name: str - resolver: Optional[str] = "" - origin: Optional[List[Origin]] = [] - 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 - resolver: Optional[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] - ttl: Optional[str] = 60 - - -class CachingItem(BaseModel, extra="forbid"): - name: str - key: str - 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 - key: str - 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 - listen: Optional[str] = "" - allow_acl: Optional[str] = "" - - -class MapEntry(BaseModel, extra="forbid"): - key: str - keymatch: str - value: str - - @model_validator(mode='after') - def check_type(self) -> 'MapEntry': - keymatch = self.keymatch - - valid = ['exact', 'regex', 'iregex'] - if keymatch not in valid: - raise ValueError(f"Invalid key match type [{keymatch}] must be one of {str(valid)}") - - return self - - -class Map(BaseModel, extra="forbid"): - match: str - variable: str - entries: Optional[List[MapEntry]] = [] - - -class Layer4(BaseModel, extra="forbid"): - servers: Optional[List[L4Server]] = [] - upstreams: Optional[List[L4Upstream]] = [] - - -class Resolver(BaseModel, extra="forbid"): - name: str - address: str - valid: Optional[str] = "" - ipv4: bool = True - ipv6: bool = True - timeout: str = "30s" - - @model_validator(mode='after') - def check_type(self) -> 'Resolver': - name = self.name - - if not re.search(alphanumRegexp,name): - raise ValueError(f"Invalid resolver name [{name}] should match regexp {alphanumRegexp}") - - return self - -class LogFormat(BaseModel, extra="forbid"): - name: str - escape: str = "default" - format: str - - @model_validator(mode='after') - def check_type(self) -> 'LogFormat': - escape = self.escape - - valid = ['default', 'json', 'none'] - if escape not in valid: - raise ValueError(f"Invalid escape mode [{escape}] must be one of {str(valid)}") - - return self - - -class CacheProfile(BaseModel, extra="forbid"): - name: str - basepath: Optional[str] = "/tmp" - size: Optional[str] = "10m" - ttl: Optional[str] = "10m" - max_size: Optional[str] = "" - min_free: Optional[str] = "" - - @model_validator(mode='after') - def check_type(self) -> 'CacheProfile': - name = self.name - - if not re.search(alphanumRegexp,name): - raise ValueError(f"Invalid cache name [{name}] should match regexp {alphanumRegexp}") - - return self - - -class CacheObjectTTL(BaseModel, extra="forbid"): - code: str = "any" - ttl: str = "10m" - - @model_validator(mode='after') - def check_type(self) -> 'CacheObjectTTL': - code = self.code - - if (code.isdigit() and (int(code) < 100 or int(code) >= 600)) or (not code.isdigit() and code!="any"): - raise ValueError(f"Invalid cache HTTP code [{code}] should be an integer between 100 and 599 or 'any'") - - return self - - -class CacheItem(BaseModel, extra="forbid"): - profile: Optional[str] = "" - key: Optional[str] = "$scheme$proxy_host$request_uri"; - validity: Optional[List[CacheObjectTTL]] = [] - - @model_validator(mode='after') - def check_type(self) -> 'CacheItem': - profile = self.profile - - if not re.search(alphanumRegexp,profile) and profile != "": - raise ValueError(f"Invalid cache item [{profile}] should match regexp {alphanumRegexp}") - - return self - - -class Authentication_Client(BaseModel, extra="forbid"): - name: str - type: str - - jwt: Optional[AuthClientJWT] = {} - mtls: Optional[AuthClientMtls] = {} - oidc: Optional[AuthClientOIDC] = {} - - @model_validator(mode='after') - def check_type(self) -> 'Authentication_Client': - _type, name = self.type, self.name - - valid = ['jwt', 'mtls', 'oidc'] - 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 - - -class Authentication_Server(BaseModel, extra="forbid"): - name: str - 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', '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 - - -class Authentication(BaseModel, extra="forbid"): - client: Optional[List[Authentication_Client]] = [] - 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]] = [] - caching: Optional[List[CachingItem]] = [] - rate_limit: Optional[List[RateLimitItem]] = [] - nginx_plus_api: Optional[NginxPlusApi] = {} - maps: Optional[List[Map]] = [] - snippet: Optional[ObjectFromSourceOfTruth] = {} - authentication: Optional[Authentication] = {} - authorization: Optional[List[Authorization]] = [] - njs: Optional[List[NjsHookHttpServer]] = [] - njs_profiles: Optional[List[NjsFile]] = [] - cache: Optional[List[CacheProfile]] = [] - logformats: Optional[List[LogFormat]] = [] - resolver: Optional[str] = "" - acme_issuers: Optional[List[AcmeIssuers]] = [] - - -class Declaration(BaseModel, extra="forbid"): - layer4: Optional[Layer4] = {} - http: Optional[Http] = {} - resolvers: Optional[List[Resolver]] = [] - - -class API_Gateway(BaseModel, extra="forbid"): - enabled: Optional[bool] = False - strip_uri: Optional[bool] = False - server_url: Optional[str] = "" - - -class DevPortal_Redocly(BaseModel, extra="forbid"): - uri: Optional[str] = "/devportal.html" - - -class DevPortal_Backstage(BaseModel, extra="forbid"): - name: str = "" - lifecycle: Optional[str] = "production" - owner: str = "" - system: Optional[str] = "" - - @model_validator(mode='after') - def check_type(self) -> 'DevPortal_Backstage': - _lifecycle = self.lifecycle - - valid = ['experimental', 'production', 'deprecated'] - if _lifecycle not in valid: - raise ValueError(f"Invalid developer portal type [{_lifecycle}] must be one of {str(valid)}") - - return self - - -class DeveloperPortal(BaseModel, extra="forbid"): - enabled: Optional[bool] = False - type: str = "" - redocly: Optional[DevPortal_Redocly] = {} - backstage: Optional[DevPortal_Backstage] = {} - - @model_validator(mode='after') - def check_type(self) -> 'DeveloperPortal': - _enabled, _type, _redocly, _backstage = self.enabled, self.type, self.redocly, self.backstage - - valid = ['redocly', 'backstage'] - - if _enabled == True and _type not in valid: - raise ValueError(f"Invalid developer portal type [{_type}] must be one of {str(valid)}") - - isError = False - - if _type == 'redocly' and not _redocly: - isError = True - - if _type == 'backstage' and not _backstage: - isError = True - - if isError: - raise ValueError(f"Missing developer portal data for type [{_type}]") - - return self - - -class Visibility_Moesif(BaseModel, extra="forbid"): - application_id: str = "" - plugin_path: Optional[str] = "/usr/local/share/lua/5.1/resty/moesif" - - -class Visibility(BaseModel, extra="forbid"): - enabled: Optional[bool] = False - type: str = "" - moesif: Optional[Visibility_Moesif] = {} - - @model_validator(mode='after') - def check_type(self) -> 'Visibility': - _enabled, _type, _moesif = self.enabled, self.type, self.moesif - - valid = ['moesif'] - - if _enabled == True and _type not in valid: - raise ValueError(f"Invalid visibility type [{_type}] must be one of {str(valid)}") - - isError = False - - if _type == 'moesif' and not _moesif: - isError = True - - if isError: - raise ValueError(f"Missing visibility data for type [{_type}]") - - return self - -class APIGateway(BaseModel, extra="forbid"): - openapi_schema: Optional[ObjectFromSourceOfTruth] = {} - api_gateway: Optional[API_Gateway] = {} - developer_portal: Optional[DeveloperPortal] = {} - visibility: Optional[List[Visibility]] = [] - rate_limit: Optional[List[RateLimitApiGw]] = [] - authentication: Optional[APIGatewayAuthentication] = {} - authorization: Optional[List[APIGatewayAuthorization]] = [] - cache: Optional[List[APIGatewayCache]] = [] - log: Optional[Log] = {} - - -class ConfigDeclaration(BaseModel, extra="forbid"): - output: Output - declaration: Optional[Declaration] = {} diff --git a/src/main.py b/src/main.py index 20088723..f1a6fc9b 100644 --- a/src/main.py +++ b/src/main.py @@ -6,7 +6,6 @@ import json import threading import time -import queue import schedule import uvicorn @@ -17,14 +16,14 @@ import NcgConfig from NcgRedis import NcgRedis -import V5_4_CreateConfig -import V5_4_NginxConfigDeclaration -import v5_4.Asynchronous - import V5_5_CreateConfig import V5_5_NginxConfigDeclaration import v5_5.Asynchronous +import V5_6_CreateConfig +import V5_6_NginxConfigDeclaration +import v5_6.Asynchronous + cfg = NcgConfig.NcgConfig(configFile="../etc/config.toml") redis = NcgRedis(host=cfg.config['redis']['host'], port=cfg.config['redis']['port']) @@ -53,23 +52,20 @@ def runAsynchronousWorker(): print(f"Processing asynchronous declaration: API [{item['apiVersion']}] method [{item['method']}] configUid [{item['configUid']}] submissionUid [{item['submissionUid']}]") declaration = item['declaration'] - if item['apiVersion'] == 'v5.4': - response = V5_4_CreateConfig.patch_config(declaration = declaration, configUid = item['configUid'], apiversion = item['apiVersion']) - elif item['apiVersion'] == 'v5.5': + if item['apiVersion'] == 'v5.5': response = V5_5_CreateConfig.patch_config(declaration = declaration, configUid = item['configUid'], apiversion = item['apiVersion']) + elif item['apiVersion'] == 'v5.6': + response = V5_6_CreateConfig.patch_config(declaration = declaration, configUid = item['configUid'], apiversion = item['apiVersion']) NcgRedis.redis.set(f"ncg.async.submission.{item['submissionUid']}", response.body.decode("utf-8")) redis.asyncQueue.task_done() -# Submit declaration using v5.4 API -@app.post("/v5.4/config", status_code=200, response_class=PlainTextResponse) -def post_config_v5_4(d: V5_4_NginxConfigDeclaration.ConfigDeclaration, response: Response): - output = V5_4_CreateConfig.createconfig(declaration=d, apiversion='v5.4') - #if type(output) in [Response, str]: - # # ConfigMap or plaintext response - # return output +# Submit declaration using v5.5 API +@app.post("/v5.5/config", status_code=200, response_class=PlainTextResponse) +def post_config_v5_5(d: V5_5_NginxConfigDeclaration.ConfigDeclaration, response: Response): + output = V5_5_CreateConfig.createconfig(declaration=d, apiversion='v5.5') headers = output['message']['headers'] if 'headers' in output['message'] else {'Content-Type': 'application/json'} @@ -84,14 +80,10 @@ def post_config_v5_4(d: V5_4_NginxConfigDeclaration.ConfigDeclaration, response: return JSONResponse(content=response, status_code=output['status_code'], headers=headers) -# Submit declaration using v5.5 API -@app.post("/v5.5/config", status_code=200, response_class=PlainTextResponse) -def post_config_v5_5(d: V5_5_NginxConfigDeclaration.ConfigDeclaration, response: Response): - output = V5_5_CreateConfig.createconfig(declaration=d, apiversion='v5.5') - - #if type(output) in [Response, str]: - # # ConfigMap or plaintext response - # return output +# Submit declaration using v5.6 API +@app.post("/v5.6/config", status_code=200, response_class=PlainTextResponse) +def post_config_v5_6(d: V5_6_NginxConfigDeclaration.ConfigDeclaration, response: Response): + output = V5_6_CreateConfig.createconfig(declaration=d, apiversion='v5.6') headers = output['message']['headers'] if 'headers' in output['message'] else {'Content-Type': 'application/json'} @@ -106,34 +98,34 @@ def post_config_v5_5(d: V5_5_NginxConfigDeclaration.ConfigDeclaration, response: return JSONResponse(content=response, status_code=output['status_code'], headers=headers) -# Modify declaration using v5.4 API -@app.patch("/v5.4/config/{configuid}", status_code=200, response_class=PlainTextResponse) -def patch_config_v5_4(d: V5_4_NginxConfigDeclaration.ConfigDeclaration, response: Response, configuid: str): - retcode, response = v5_4.Asynchronous.checkIfAsynch(declaration = d, method = 'PATCH', apiVersion = 'v5.4', configUid = configuid) +# Modify declaration using v5.5 API +@app.patch("/v5.5/config/{configuid}", status_code=200, response_class=PlainTextResponse) +def patch_config_v5_5(d: V5_5_NginxConfigDeclaration.ConfigDeclaration, response: Response, configuid: str): + retcode, response = v5_5.Asynchronous.checkIfAsynch(declaration = d, method = 'PATCH', apiVersion = 'v5.5', configUid = configuid) if retcode is not None: # Request was asynchronous and it has been submitted to the FIFO queue return JSONResponse(content=response, status_code = retcode, headers = {'Content-Type': 'application/json'}) - return V5_4_CreateConfig.patch_config(declaration=d, configUid=configuid, apiversion='v5.4') + return V5_5_CreateConfig.patch_config(declaration=d, configUid=configuid, apiversion='v5.5') -# Modify declaration using v5.5 API -@app.patch("/v5.5/config/{configuid}", status_code=200, response_class=PlainTextResponse) -def patch_config_v5_5(d: V5_5_NginxConfigDeclaration.ConfigDeclaration, response: Response, configuid: str): - retcode, response = v5_5.Asynchronous.checkIfAsynch(declaration = d, method = 'PATCH', apiVersion = 'v5.5', configUid = configuid) +# Modify declaration using v5.6 API +@app.patch("/v5.6/config/{configuid}", status_code=200, response_class=PlainTextResponse) +def patch_config_v5_6(d: V5_6_NginxConfigDeclaration.ConfigDeclaration, response: Response, configuid: str): + retcode, response = v5_6.Asynchronous.checkIfAsynch(declaration = d, method = 'PATCH', apiVersion = 'v5.6', configUid = configuid) if retcode is not None: # Request was asynchronous and it has been submitted to the FIFO queue return JSONResponse(content=response, status_code = retcode, headers = {'Content-Type': 'application/json'}) - return V5_5_CreateConfig.patch_config(declaration=d, configUid=configuid, apiversion='v5.5') + return V5_6_CreateConfig.patch_config(declaration=d, configUid=configuid, apiversion='v5.6') -# Get declaration - v5.4 API -@app.get("/v5.4/config/{configuid}", status_code=200, response_class=PlainTextResponse) -def get_config_declaration_v5_4(configuid: str): - status_code, content = V5_4_CreateConfig.get_declaration(configUid=configuid) +# Get declaration - v5.5 API +@app.get("/v5.5/config/{configuid}", status_code=200, response_class=PlainTextResponse) +def get_config_declaration_v5_5(configuid: str): + status_code, content = V5_5_CreateConfig.get_declaration(configUid=configuid) if status_code == 404: return JSONResponse( @@ -149,10 +141,10 @@ def get_config_declaration_v5_4(configuid: str): ) -# Get declaration - v5.5 API -@app.get("/v5.5/config/{configuid}", status_code=200, response_class=PlainTextResponse) -def get_config_declaration_v5_5(configuid: str): - status_code, content = V5_5_CreateConfig.get_declaration(configUid=configuid) +# Get declaration - v5.6 API +@app.get("/v5.6/config/{configuid}", status_code=200, response_class=PlainTextResponse) +def get_config_declaration_v5_6(configuid: str): + status_code, content = V5_6_CreateConfig.get_declaration(configUid=configuid) if status_code == 404: return JSONResponse( @@ -169,8 +161,8 @@ def get_config_declaration_v5_5(configuid: str): # Get declaration status -@app.get("/v5.4/config/{configuid}/status", status_code=200, response_class=PlainTextResponse) @app.get("/v5.5/config/{configuid}/status", status_code=200, response_class=PlainTextResponse) +@app.get("/v5.6/config/{configuid}/status", status_code=200, response_class=PlainTextResponse) def get_config_status(configuid: str): status = redis.redis.get('ncg.status.' + configuid) @@ -188,8 +180,8 @@ def get_config_status(configuid: str): ) -# Get asynchronous submission status - v5.4 API -@app.get("/v5.4/config/{configuid}/submission/{submissionuid}", status_code=200, response_class=PlainTextResponse) +# Get asynchronous submission status - v5.5 API +@app.get("/v5.5/config/{configuid}/submission/{submissionuid}", status_code=200, response_class=PlainTextResponse) def get_submission_status(configuid: str, submissionuid: str): status = redis.redis.get('ncg.async.submission.' + submissionuid) @@ -215,8 +207,8 @@ def get_submission_status(configuid: str, submissionuid: str): ) -# Get asynchronous submission status - v5.5 API -@app.get("/v5.5/config/{configuid}/submission/{submissionuid}", status_code=200, response_class=PlainTextResponse) +# Get asynchronous submission status - v5.6 API +@app.get("/v5.6/config/{configuid}/submission/{submissionuid}", status_code=200, response_class=PlainTextResponse) def get_submission_status(configuid: str, submissionuid: str): status = redis.redis.get('ncg.async.submission.' + submissionuid) @@ -243,8 +235,8 @@ def get_submission_status(configuid: str, submissionuid: str): # Delete declaration -@app.delete("/v5.4/config/{configuid}", status_code=200, response_class=PlainTextResponse) @app.delete("/v5.5/config/{configuid}", status_code=200, response_class=PlainTextResponse) +@app.delete("/v5.6/config/{configuid}", status_code=200, response_class=PlainTextResponse) def delete_config(configuid: str = ""): if configuid not in redis.declarationsList: return JSONResponse( @@ -283,6 +275,29 @@ def get_schema_v5_5(): return JSONResponse(content=schema, headers={'Content-Type': 'application/json'}) +if __name__ == '__main__': + print(f"{cfg.config['main']['banner']} {cfg.config['main']['version']}") + + print("Starting GitOps scheduler") + threading.Thread(target=runGitOpsScheduler).start() + + print("Starting Asynchronous declarations scheduler") + threading.Thread(target=runAsynchronousWorker, daemon=True).start() + + apiServerHost = cfg.config['apiserver']['host'] + apiServerPort = cfg.config['apiserver']['port'] + + print(f"Starting API server on {apiServerHost}:{apiServerPort}") + uvicorn.run("main:app", host=apiServerHost, port=apiServerPort) + + +# Get JSON schema for the v5.6 ConfigDeclaration - used by the Web UI editor for IntelliSense +@app.get("/v5.6/schema", status_code=200) +def get_schema_v5_6(): + schema = V5_6_NginxConfigDeclaration.ConfigDeclaration.model_json_schema() + return JSONResponse(content=schema, headers={'Content-Type': 'application/json'}) + + if __name__ == '__main__': print(f"{cfg.config['main']['banner']} {cfg.config['main']['version']}") diff --git a/src/v5_4/APIGateway.py b/src/v5_4/APIGateway.py deleted file mode 100644 index e3a187e3..00000000 --- a/src/v5_4/APIGateway.py +++ /dev/null @@ -1,37 +0,0 @@ -""" -API Gateway support functions -""" - -import json - -import v5_4.GitOps -import v5_4.MiscUtils -from v5_4.OpenAPIParser import OpenAPIParser - -# pydantic models -from V5_4_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_4.GitOps.getObjectFromRepo(object=locationDeclaration['apigateway']['openapi_schema'], - authProfiles = authProfiles['server'] if 'server' in authProfiles else {}, base64Encode=False) - - if v5_4.MiscUtils.yaml_or_json(apiSchemaString['content']) == 'yaml': - # YAML to JSON conversion - apiSchemaString['content'] = v5_4.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, apiSchemaString['content'] \ No newline at end of file diff --git a/src/v5_4/Asynchronous.py b/src/v5_4/Asynchronous.py deleted file mode 100644 index 707a8385..00000000 --- a/src/v5_4/Asynchronous.py +++ /dev/null @@ -1,36 +0,0 @@ -"""" -Asynchronous declarations support -""" -import json -import pickle - -import v5_4.MiscUtils -from NcgRedis import NcgRedis - -# pydantic models -from V5_4_NginxConfigDeclaration import ConfigDeclaration - -# -# Check if the incoming request is asynchronous -# -def checkIfAsynch(declaration: ConfigDeclaration, method: str, apiVersion: str, configUid: str): - djson = declaration.model_dump() - - if djson['output']['synchronous']: - # Synchronous declaration, normal processing - return None, None - - # Asynchronous declaration, submit to FIFO queue - submissionUid = str(v5_4.MiscUtils.getuniqueid()) - submissionPayload = {'declaration': declaration, 'method': method, 'configUid': configUid, "apiVersion": apiVersion, "submissionUid": submissionUid} - NcgRedis.asyncQueue.put(submissionPayload) - - response = {} - response['code'] = 202 - response['message'] = f'Declaration submitted' - response['configUid'] = configUid - response['submissionUid'] = submissionUid - - NcgRedis.redis.set(f'ncg.async.submission.{submissionUid}', json.dumps(response)) - - return 202, response \ No newline at end of file diff --git a/src/v5_4/DeclarationPatcher.py b/src/v5_4/DeclarationPatcher.py deleted file mode 100644 index 51260a4c..00000000 --- a/src/v5_4/DeclarationPatcher.py +++ /dev/null @@ -1,238 +0,0 @@ -""" -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'] \ - 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, '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 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_4/DevPortal.py b/src/v5_4/DevPortal.py deleted file mode 100644 index a61be855..00000000 --- a/src/v5_4/DevPortal.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -API Gateway Developer Portal support functions -""" - -import json -import requests -import base64 - -# NGINX Declarative API modules -from NcgConfig import NcgConfig -import v5_4.GitOps -import v5_4.MiscUtils - -# pydantic models -from V5_4_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_4.GitOps.getObjectFromRepo( - object = locationDeclaration['apigateway']['openapi_schema'], authProfiles = authProfiles['server'] if 'server' in authProfiles else {}, base64Encode = False) - - if v5_4.MiscUtils.yaml_or_json(apiSchemaString['content']) == 'yaml': - # YAML to JSON conversion - status, devportalJSON = buildDevPortal(openapischema = v5_4.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/v5_4/GitOps.py b/src/v5_4/GitOps.py deleted file mode 100644 index bf990dd2..00000000 --- a/src/v5_4/GitOps.py +++ /dev/null @@ -1,83 +0,0 @@ -""" -GitOps support functions -""" - -import base64 -import requests - -from requests import ReadTimeout, HTTPError, Timeout, ConnectionError, ConnectTimeout - -import v5_4.MiscUtils - -# pydantic models -from V5_4_NginxConfigDeclaration import * - - -# Fetches a URL content -def __fetchfromsourceoftruth__(url, headers = {} ): - # Object is fetched from external repository - - try: - reply = requests.get(url = url, headers = headers, verify=False) - except (ConnectTimeout, HTTPError, ReadTimeout, Timeout, ConnectionError): - return 408, "URL " + url + " unreachable" - - return reply.status_code, reply.text - - -# If content starts with http(s):// fetches the object and return it b64-encoded by default. -# base64Encode to be set to False to disable b64 encoding -# Returns the status original content otherwise. -# Return is a tuple: status_code, content -def getObjectFromRepo(object: ObjectFromSourceOfTruth, authProfiles: Authentication={}, base64Encode: bool=True): - status_code = 200 - response = object - - if object: - if object['content'].lower().startswith(("http://","https://")): - # Object is fetched from external repository - headers = {} - - # Set server authentication if needed - 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': - - authToken = authP['token']['token'] - authTokenType = authP['token']['type'] - - 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) - - if status_code == 200: - if base64Encode == True: - fetchedContent = base64.b64encode(bytes(fetchedContent, 'utf-8')).decode('utf-8') - else: - fetchedContent = bytes(fetchedContent, 'utf-8').decode("utf-8") - else: - fetchedContent = f"Error fetching {object['content']}" - - response['content'] = fetchedContent - - else: - # Object is specified directly into the JSON payload, perform base64 decoding if needed - if not base64Encode: - if v5_4.MiscUtils.isBase64(object['content']): - response['content'] = base64.b64decode(object['content']).decode(); - else: - response['content'] = object['content'] - - return status_code, response \ No newline at end of file diff --git a/src/v5_4/MiscUtils.py b/src/v5_4/MiscUtils.py deleted file mode 100644 index ced5b9f0..00000000 --- a/src/v5_4/MiscUtils.py +++ /dev/null @@ -1,67 +0,0 @@ -""" -Support functions -""" - -import re -import json -import yaml -import uuid -import socket -import base64 - - -# Searches for a nested key in a dictionary and returns its value, or None if nothing was found. -# key_lookup must be a string where each key is deparated by a given "separator" character, which by default is a dot -def getDictKey(_dict: dict, key_lookup: str, separator='.'): - keys = key_lookup.split(separator) - subdict = _dict - - for k in keys: - subdict = subdict[k] if k in subdict else None - if subdict is None: - return None - - return subdict - -# Jinja2 regexp filter -def regex_replace(s, find, replace): - return re.sub(find, replace, s) - -# JSON/YAML detection -def yaml_or_json(document: str): - try: - json.load(document) - return 'json' - except Exception: - return 'yaml' - -# YAML to JSON conversion -def yaml_to_json(document: str): - return json.dumps(yaml.safe_load(document)) - - -# JSON TO YAML conversion -def json_to_yaml(document: str): - return yaml.dump(json.loads(document)) - - -# Returns a unique ID -def getuniqueid(): - return uuid.uuid4() - - -# Test DNS resolution -# Returns {True,IP address} if successful and {False,error description} for NXDOMAIN/if DNS resolution failed -def resolveFQDN(fqdn:str): - try: - return True,socket.gethostbyname(fqdn) - except Exception as e: - return False,e - - -# Check for base64 encoding, return True if s is base64-encoded, False otherwise -def isBase64(s): - try: - return base64.b64encode(base64.b64decode(s)) == bytes(s,"utf-8") - except Exception: - return False \ No newline at end of file diff --git a/src/v5_4/NGINXOneNAPUtils.py b/src/v5_4/NGINXOneNAPUtils.py deleted file mode 100644 index 9eecd999..00000000 --- a/src/v5_4/NGINXOneNAPUtils.py +++ /dev/null @@ -1,256 +0,0 @@ -""" -NGINX App Protect support functions -""" - -import requests -import json -import base64 - -import v5_4.GitOps - -from NcgConfig import NcgConfig - -from fastapi.responses import Response, JSONResponse - -available_log_profiles = ['log_all', 'log_blocked', 'log_illegal', 'secops_dashboard'] - - -# Define (create/update) a NGINX App Protect policy on NMS. -# If policyUid is not empty a the policy update is performed -# Returns a tuple {status_code,text}. status_code is 201 if successful -def __definePolicyOnNGINXOne__(nginxOneUrl: str, nginxOneToken: str, nginxOneNamespace: str, policyJson: str): - policyName = json.loads(policyJson)['policy']['name'] - - # Payload for NGINX One Console - # policyBody holds the base64-encoded policy JSON definition - # Control plane-compiled policy bundles are supported. Create the NGINX App Protect policy on NGINX One Console - # POST {nginxOneUrl}/api/nginx/one/namespaces/{nginxOneNamespace}/app-protect/policies - # { - # "policy": "" - # } - policyCreationPayload = {} - policyCreationPayload['policy'] = base64.b64encode(bytes(policyJson, 'utf-8')).decode('utf-8') - - # Retrieve the full policy list from NGINX One Console - allExistingPolicies = __getAllPolicies__(nginxOneUrl = nginxOneUrl, nginxOneToken = nginxOneToken, nginxOneNamespace=nginxOneNamespace) - polId = __getPolicyId__(json.loads(allExistingPolicies.text), policyName) - - if polId != "": - # This is a new version for an existing policy - r = requests.put(url=f"{nginxOneUrl}/api/nginx/one/namespaces/{nginxOneNamespace}/app-protect/policies/{polId}", - data=json.dumps(policyCreationPayload), - headers={'Content-Type': 'application/json', - "Authorization": f"Bearer APIToken {nginxOneToken}"}, - verify=False) - else: - # New policy creation - r = requests.post(url=f"{nginxOneUrl}/api/nginx/one/namespaces/{nginxOneNamespace}/app-protect/policies", - data=json.dumps(policyCreationPayload), - headers={'Content-Type': 'application/json', "Authorization": f"Bearer APIToken {nginxOneToken}"}, - verify=False) - - return r - - -# Retrieve security policies information -def __getAllPolicies__(nginxOneUrl: str, nginxOneToken: str, nginxOneNamespace: str): - return requests.get(url=f"{nginxOneUrl}/api/nginx/one/namespaces/{nginxOneNamespace}/app-protect/policies?paginated=false", - headers={"Authorization": f"Bearer APIToken {nginxOneToken}"}, verify=False) - - -# Return the policy ID for the given policyName. allPoliciesJSON is the JSON output from __getAllPolicies__ -def __getPolicyId__(allPoliciesJSON: dict, policyName: str): - if 'items' in allPoliciesJSON: - for p in allPoliciesJSON['items']: - if policyName == p['name']: - return p['object_id'] - - return "" - - -# Delete security policies from control plane -def __deletePolicy__(nginxOneUrl: str, nginxOneToken: str, nginxOneNamespace: str, policyUids: list): - jsonPayload = [] - - for polId in policyUids: - item = {} - item['object_id'] = polId - item['action'] = "delete" - jsonPayload.append(item) - - return requests.patch(url=f'{nginxOneUrl}/api/nginx/one/namespaces/{nginxOneNamespace}/app-protect/policies', - headers={"Content-Type": "application/json", "Authorization": f"Bearer APIToken {nginxOneToken}"}, verify=False, - data=json.dumps(jsonPayload)) - - -# Check NAP policies names validity for the given declaration -# Return a tuple: status, description. If status = 200 checks were successful -def checkDeclarationPolicies(declaration: dict): - # NGINX App Protect policies check - duplicated policy names - - # all policy names as defined in the declaration - # { 'policyName': 'activeTag', ... } - allPolicyNames = {} - - if 'policies' not in declaration['output']['nginxone']: - return 200, "" - - for policy in declaration['output']['nginxone']['policies']: - # print(f"Found NAP Policy [{policy['name']}] active tag [{policy['active_tag']}]") - - if policy['name'] and policy['name'] in allPolicyNames: - return 422, f"Duplicated NGINX App Protect WAF policy [{policy['name']}]" - - allPolicyNames[policy['name']] = policy['active_tag'] - - # Check policy releases for non-univoque tags - allPolicyVersionTags = {} - for policyVersion in policy['versions']: - if policyVersion['tag'] and policyVersion['tag'] in allPolicyVersionTags: - return 422, f"Duplicated NGINX App Protect WAF policy tag [{policyVersion['tag']}] " \ - f"for policy [{policy['name']}]" - - allPolicyVersionTags[policyVersion['tag']] = "found" - - if policy['active_tag'] and policy['active_tag'] not in allPolicyVersionTags: - return 422, f"Invalid active tag [{policy['active_tag']}] for policy [{policy['name']}]" - - # Check policy names referenced by the declaration inside HTTP servers[]: they must be valid - if 'http' in declaration['declaration'] and 'servers' in declaration['declaration']['http']: - for httpServer in declaration['declaration']['http']['servers']: - if 'app_protect' in httpServer: - if 'policy' in httpServer['app_protect'] and httpServer['app_protect']['policy'] \ - and httpServer['app_protect']['policy'] not in allPolicyNames: - return 422, f"Unknown NGINX App Protect WAF policy [{httpServer['app_protect']['policy']}] " \ - f"referenced by HTTP server [{httpServer['name']}]" - - if 'log' in httpServer['app_protect'] \ - and 'profile_name' in httpServer['app_protect']['log'] \ - and httpServer['app_protect']['log']['profile_name'] \ - and httpServer['app_protect']['log']['profile_name'] \ - not in available_log_profiles: - return 422, f"Invalid NGINX App Protect WAF log profile " \ - f"[{httpServer['app_protect']['log']['profile_name']}] referenced by HTTP server " \ - f"[{httpServer['name']}]" - - # Check policy names referenced in HTTP servers[].locations[] - for location in httpServer['locations']: - if 'app_protect' in location: - if 'policy' in location['app_protect'] and location['app_protect']['policy'] \ - and location['app_protect']['policy'] not in allPolicyNames: - return 422, f"Unknown NGINX App Protect WAF policy [{location['app_protect']['policy']}] " \ - f"referenced by HTTP server [{httpServer['name']}] location [{location['uri']}]" - - if 'log' in httpServer['app_protect'] and httpServer['app_protect']['log'] \ - and httpServer['app_protect']['log']['profile_name'] \ - and httpServer['app_protect']['log']['profile_name'] \ - not in available_log_profiles: - return 422, f"Invalid NGINX App Protect WAF log profile " \ - f"[{httpServer['app_protect']['log']['profile_name']}] referenced by HTTP server " \ - f"[{httpServer['name']}] location [{location['uri']}]" - - return 200, "" - - -# For the given declaration creates/updates NGINX App Protect WAF policies on NGINX Instance Manager -# making sure that they are in sync with what is defined in the JSON declaration -# Returns a JSON with status code and content -def provisionPolicies(nginxOneUrl: str, nginxOneToken: str, nginxOneNamespace: str, declaration: dict): - # NGINX App Protect policies - each policy supports multiple tagged versions - - # Policy names and all tag/uid pairs - # {'prod-policy': [{'tag': 'v1', 'uid': 'ebcf9c7e-0930-450d-8108-7cad30e59661'}, - # {'tag': 'v2', 'uid': 'd18c2eb7-814e-4e4d-90fc-54014eef199e'}], - # 'staging-policy': [{'tag': 'block', 'uid': '9794faa7-5b6c-4ce5-9e68-946f04766bb4'}, - # {'tag': 'xss-ok', 'uid': '7b4b850a-ff9e-42a0-85d0-850171474224'}]} - all_policy_names_and_versions = {} - - # Policy names and active tag uids - # { 'prod-policy': 'ebcf9c7e-0930-450d-8108-7cad30e59661', - # 'staging-policy': '7b4b850a-ff9e-42a0-85d0-850171474224' } - all_policy_active_names_and_uids = {} - - for p in declaration['output']['nginxone']['policies']: - policy_name = p['name'] - if policy_name: - policy_active_tag = p['active_tag'] - - # Iterates over all NGINX App Protect policies - if p['type'] == 'app_protect': - # Iterates over all policy versions - - # Remove pre-existing policy versions - allPoliciesJSON = __getAllPolicies__(nginxOneUrl=nginxOneUrl, nginxOneToken=nginxOneToken, nginxOneNamespace=nginxOneNamespace) - polId = __getPolicyId__(allPoliciesJSON = json.loads(allPoliciesJSON.text), policyName=policy_name) - if polId != "": - __deletePolicy__(nginxOneUrl=nginxOneUrl, nginxOneToken=nginxOneToken, nginxOneNamespace=nginxOneNamespace, policyUids=[polId]) - - # Create all policy versions - for policyVersion in p['versions']: - status, policyBody = v5_4.GitOps.getObjectFromRepo(policyVersion['contents'],base64Encode=False) - - if status != 200: - return JSONResponse( - status_code=422, - content={"code": status, - "details": policyBody['content']} - ) - - # Create the NGINX App Protect policy on NGINX One Console - r = __definePolicyOnNGINXOne__( - nginxOneUrl=nginxOneUrl, nginxOneToken=nginxOneToken, nginxOneNamespace=nginxOneNamespace, - policyJson=policyBody['content'] - ) - - # Check for errors creating NGINX App Protect policy - if r.status_code != 201: - return JSONResponse( - status_code=r.status_code, - content={"code": r.status_code, "details": json.loads(r.text)} - ) - else: - # Policy was created, retrieve metadata.uid for each policy version - if policy_name not in all_policy_names_and_versions: - all_policy_names_and_versions[policy_name] = [] - - # Stores the policy version - uid = json.loads(r.text)['latest']['object_id'] - tag = policyVersion['tag'] - - if policy_active_tag == tag: - all_policy_active_names_and_uids[policy_name] = uid - - all_policy_names_and_versions[policy_name].append({'tag': tag, 'uid': uid}) - - return JSONResponse(status_code=200, content={"all_policy_names_and_versions": all_policy_names_and_versions, - "all_policy_active_names_and_uids": all_policy_active_names_and_uids}) - - -# Publish a NGINX App Protect WAF policy making it active -# activePolicyUids is a dict { "policy_name": "active_uid", [...] } -# Return True if at least one policy was enabled, False otherwise -def makePolicyActive(nginxOneUrl: str, nginxOneToken: str, nginxOneNamespace: str, activePolicyUids: dict, instanceGroupUid: str): - doWeHavePolicies = False - - for policyName in activePolicyUids: - body = { - "publications": [ - { - "policyContent": { - "name": f'{policyName}', - "uid": f'{activePolicyUids[policyName]}' - }, - "instanceGroups": [ - f'{instanceGroupUid}' - ] - } - ] - } - - doWeHavePolicies = True - r = requests.post(url=f'{nginxOneUrl}/api/platform/v1/security/publish', - data=json.dumps(body), - headers={'Content-Type': 'application/json', "Authorization": f"Bearer APIToken {nginxOneToken}"}, - verify=False) - - return doWeHavePolicies \ No newline at end of file diff --git a/src/v5_4/NGINXOneOutput.py b/src/v5_4/NGINXOneOutput.py deleted file mode 100644 index 9d78c5a0..00000000 --- a/src/v5_4/NGINXOneOutput.py +++ /dev/null @@ -1,379 +0,0 @@ -""" -Output to NGINX One console -""" - -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_4_CreateConfig - -import v5_4.APIGateway -import v5_4.DevPortal -import v5_4.DeclarationPatcher -import v5_4.GitOps -import v5_4.MiscUtils -import v5_4.NGINXOneUtils - -# pydantic models -from V5_4_NginxConfigDeclaration import * - -# NGINX App Protect helper functions -# NGINX App Protect helper functions -import v5_4.NGINXOneNAPUtils - -# NGINX Declarative API modules -from NcgConfig import NcgConfig -from NcgRedis import NcgRedis - -def NGINXOneOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpConf: str, - b64StreamConf: str,configFiles = {}, auxFiles = {}, - runfromautosync: bool = False, - configUid: str = ""): - # NGINX One Console Staged Configuration publish - - nOneToken = v5_4.MiscUtils.getDictKey(d, 'output.nginxone.token') - nOneConfigSyncGroup = v5_4.MiscUtils.getDictKey(d, 'output.nginxone.configsyncgroup') - nOneNamespace = v5_4.MiscUtils.getDictKey(d, 'output.nginxone.namespace') - - nOneSynctime = v5_4.MiscUtils.getDictKey(d, 'output.nginxone.synctime') - - nOneUrlFromJson = v5_4.MiscUtils.getDictKey(d, 'output.nginxone.url') - urlCheck = urlparse(nOneUrlFromJson) - - 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 One URL {nOneUrlFromJson}"}}, - "headers": {'Content-Type': 'application/json'}} - - # DNS resolution check - dnsOutcome, dnsReply = v5_4.MiscUtils.resolveFQDN(urlCheck.netloc) - if not dnsOutcome: - return {"status_code": 400, - "message": {"status_code": 400, "message": {"code": 400, - "content": f"DNS resolution failed for {urlCheck.netloc}: {dnsReply}"}}, - "headers": {'Content-Type': 'application/json'}} - - nOneUrl = f"{urlCheck.scheme}://{urlCheck.netloc}" - - if nOneSynctime < 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_4.MiscUtils.getDictKey(d, 'output.nginxone.policies') - if d_policies is not None: - for policy in d_policies: - if 'versions' in policy: - for policyVersion in policy['versions']: - status, content = v5_4.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_4.MiscUtils.getDictKey(d, 'output.nginxone.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 - - # TLS certificates and key names validity checks for servers - d_servers = v5_4.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_4.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']) + "] must be one of [" + ",".join(all_tls['certificate']) + "]"} - }} - - cert_key = v5_4.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']) + "] must be one of [" + ",".join(all_tls['key']) + "]"} - }} - - trusted_cert_name = v5_4.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']) - + "] must be one of [" + ",".join(all_tls['certificate']) + "]"} - }} - - # TLS certificates and key names validity checks or ACME issuer profiles - d_acmeissuers = v5_4.MiscUtils.getDictKey(d, 'declaration.http.acme_issuers') - if d_acmeissuers is not None: - for issuer in d_acmeissuers: - cert_name = issuer['ssl_trusted_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 ACME issuer [" + str( - issuer['name']) +"] must be one of [" + ",".join(all_tls['certificate']) + "]"} - }} - - # Add optional certificates specified under output.nginxone.certificates - extensions_map = {'certificate': '.crt', 'key': '.key'} - - d_certificates = v5_4.MiscUtils.getDictKey(d, 'output.nginxone.certificates') - if d_certificates is not None: - for c in d_certificates: - status, certContent = v5_4.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.nginxone.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={'mainhttpfile': NcgConfig.config['nms']['staged_config_http_filename'], - 'mainstreamfile': NcgConfig.config['nms']['staged_config_stream_filename'], - 'modules': v5_4.MiscUtils.getDictKey(d, 'output.nginxone.modules'), - 'license': v5_4.MiscUtils.getDictKey(d, 'output.license')}, - d={'http': v5_4.MiscUtils.getDictKey(d, 'declaration.http')}) - - # Base64-encoded NGINX main configuration (/etc/nginx/nginx.conf) - b64NginxMain = str(base64.urlsafe_b64encode(nginxMainConf.encode("utf-8")), "utf-8") - - # NGINX License file - licenseJwtFile = j2_env.get_template(NcgConfig.config['templates']['license']).render( - nginxconf={'license': v5_4.MiscUtils.getDictKey(d, 'output.license')}) - - # Base64-encoded license file (/etc/nginx/license.jwt) - b64licenseJwtFile = str(base64.urlsafe_b64encode(licenseJwtFile.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'} - filesLicenseFile = {'contents': b64licenseJwtFile, 'name': NcgConfig.config['nms']['config_dir'] + '/license.jwt'} - 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) - - # If no R33+ license token was specified in the JSON declaration, it is assumed a token already exists - # on the NGINX instances and it won't be overwritten - if v5_4.MiscUtils.getDictKey(d, 'output.license.token') != "": - configFiles['files'].append(filesLicenseFile) - - # Staged config - baseStagedConfig = {'aux': [ { 'files': configFiles } ] } - stagedConfig = {'conf_path': NcgConfig.config['nms']['config_dir'] + '/nginx.conf', - 'configs': [ configFiles, auxFiles ]} - - 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 NGINX One needed - print( - f'Declaration [{configUid}] changed, publishing' if configUid else f'New declaration created, publishing') - - # Get the config sync group id nOneUrl: str, nOneTokenUsername: str, nameSpace: str, clusterName: str - returnCode, igUid = v5_4.NGINXOneUtils.getConfigSyncGroupId(nOneUrl = nOneUrl, nOneToken = nOneToken, - nameSpace = nOneNamespace, configSyncGroupName = nOneConfigSyncGroup) - - # Invalid config sync group - if returnCode != 200: - return {"status_code": 404, - "message": {"status_code": 404, "message": {"code": returnCode, - "content": igUid}}, - "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_4.NGINXOneNAPUtils.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 - ppReply = v5_4.NGINXOneNAPUtils.provisionPolicies( - nginxOneUrl = nOneUrl, nginxOneToken = nOneToken, nginxOneNamespace = nOneNamespace, declaration=d) - - if ppReply.status_code >= 400: - return {"status_code": ppReply.status_code, - "message": {"status_code": ppReply.status_code, "message": {"code": ppReply.status_code, "content": ppReply.content} }} - - napPolicies = json.loads(ppReply.body) - provisionedNapPolicies = napPolicies['all_policy_names_and_versions'] - activePolicyUids = napPolicies['all_policy_active_names_and_uids'] - - ### / NGINX App Protect policies support - - ### Publish staged config to config sync group - returnHttpCode = 422 - - r = requests.put(url=f'{nOneUrl}/api/nginx/one/namespaces/{nOneNamespace}/config-sync-groups/{igUid}/config', - data=json.dumps(stagedConfig), - headers={'Content-Type': 'application/json', "Authorization": f"Bearer APIToken {nOneToken}"}, - verify=False) - - if r.status_code not in [200, 202]: - # Configuration publish failed - return {"status_code": r.status_code, - "message": {"status_code": r.status_code, "message": r.text}, - "headers": {'Content-Type': 'application/json'}} - - if r.status_code == 202: - # Configuration has been submitted to NGINX One Console, fetch the deployment status - reply was HTTP/202 - publishResponse = json.loads(r.text) - publication_id = publishResponse['object_id'] - - # Wait for either NGINX One Cloud Console 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=f'{nOneUrl}/api/nginx/one/namespaces/{nOneNamespace}/config-sync-groups/{igUid}/publications/{publication_id}', - headers={"Authorization": f"Bearer APIToken {nOneToken}"}, - verify=False) - - checkJson = json.loads(deploymentCheck.text) - - if not checkJson['status'] == 'pending': - isPending = False - - if checkJson['status'] == "failed": - # Staged config publish to NGINX One failed - jsonResponse = checkJson['status_reasons'][0] - returnHttpCode = 422 - elif checkJson['status'] == "succeeded": - jsonResponse = { "message": "Config successfully applied", "status": checkJson['status'] } - returnHttpCode = 200 - - else: - # Staged config publish to NGINX One succeeded - reply was HTTP/200 - jsonResponse = json.loads(r.text) - returnHttpCode = 200 - - # if nmsSynctime > 0 and runfromautosync == False: - if runfromautosync == False: - # No configuration is found, generate one - configUid = str(v5_4.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_4.NGINXOneNAPUtils.makePolicyActive(nginxOneUrl=nOneUrl, - nginxOneToken=nOneToken, - nginxOneNamespace=nOneNamespace, - 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_4.NGINXOneNAPUtils.cleanPolicyLeftovers(nginxOneUrl=nOneUrl,nginxOneToken=nOneToken, - # nginxOneNamespace=nOneNamespace, - # currentPolicies=provisionedNapPolicies) - - # If deploying a new configuration in GitOps mode start autosync - if nOneSynctime == 0: - NcgRedis.declarationsList[configUid] = "static" - elif not runfromautosync: - # GitOps autosync - print(f'Starting autosync for configUid {configUid} every {nOneSynctime} seconds') - - job = schedule.every(nOneSynctime).seconds.do(lambda: v5_4_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': returnHttpCode, '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": returnHttpCode, - "message": {"status_code": returnHttpCode, - "message": responseContent}, - "headers": {'Content-Type': 'application/json'} - } \ No newline at end of file diff --git a/src/v5_4/NGINXOneUtils.py b/src/v5_4/NGINXOneUtils.py deleted file mode 100644 index 48c4a902..00000000 --- a/src/v5_4/NGINXOneUtils.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -NGINX One support functions -""" - -import requests -import json - - -# Fetch a cluster ID from NGINX One -# Return None if not found -def getConfigSyncGroupId(nOneUrl: str, nOneToken: str, nameSpace: str, configSyncGroupName: str): - # Retrieve config sync group uid - cSyncGroup = requests.get(url=f'{nOneUrl}/api/nginx/one/namespaces/{nameSpace}/config-sync-groups?paginated=false', - verify=False, headers = {"Authorization": f"Bearer APIToken {nOneToken}"}) - - if cSyncGroup.status_code != 200: - if cSyncGroup.status_code == 401: - return cSyncGroup.status_code, "NGINX One authentication failed" - else: - return cSyncGroup.status_code, f"Error fetching config sync group uid: {cSyncGroup.text}" - - # Get the instance group id - igUid = None - igJson = json.loads(cSyncGroup.text) - for i in igJson['items']: - if i['name'] == configSyncGroupName: - igUid = i['object_id'] - - if igUid is None: - return 404, f"config sync group [{configSyncGroupName}] not found" - - return 200, igUid diff --git a/src/v5_4/NIMNAPUtils.py b/src/v5_4/NIMNAPUtils.py deleted file mode 100644 index eee72cc3..00000000 --- a/src/v5_4/NIMNAPUtils.py +++ /dev/null @@ -1,272 +0,0 @@ -""" -NGINX App Protect support functions -""" - -import requests -import json -import base64 - -import v5_4.GitOps - -from NcgConfig import NcgConfig - -from fastapi.responses import Response, JSONResponse - -available_log_profiles = ['log_all', 'log_blocked', 'log_illegal', 'secops_dashboard'] - - -# Define (create/update) a NGINX App Protect policy on NMS. -# If policyUid is not empty a the policy update is performed -# Returns a tuple {status_code,text}. status_code is 201 if successful -def __definePolicyOnNMS__(nmsUrl: str, nmsUsername: str, nmsPassword: str, policyName: str, policyDisplayName: str, - policyDescription: str, policyJson: str, policyUid: str = ""): - # policyJson holds the base64-encoded policy JSON definition - # Control plane-compiled policy bundles are supported. Create the NGINX App Protect policy on NGINX Instance Manager - # POST https://IP_ADDRESS/api/platform/v1/security/policies - # { - # "metadata": { - # "name": "prod-policy", - # "displayName": "Production Policy - blocking", - # "description": "Production-ready policy - blocking" - # }, - # "content": "" - # } - - policyCreationPayload = {'metadata': {}} - policyCreationPayload['metadata']['name'] = policyName - policyCreationPayload['metadata']['displayName'] = policyDisplayName - policyCreationPayload['metadata']['description'] = policyDescription - policyCreationPayload['content'] = policyJson - - if policyUid != "": - # Existing policy update - r = requests.put(url=f"{nmsUrl}/api/platform/v1/security/policies/{policyUid}", - data=json.dumps(policyCreationPayload), - headers={'Content-Type': 'application/json'}, - auth=(nmsUsername, nmsPassword), - verify=False) - else: - # New policy creation - first try to create it as a new revision for an existing policy - # The response code is 201 if successful and 404 if there is no policy with the given name - r = requests.post(url=f"{nmsUrl}/api/platform/v1/security/policies?isNewRevision=true", - data=json.dumps(policyCreationPayload), - headers={'Content-Type': 'application/json'}, - auth=(nmsUsername, nmsPassword), - verify=False) - - # Check if this is a new policy with no existing versions. If this is true create its initial version - if r.status_code == 404: - r = requests.post(url=f"{nmsUrl}/api/platform/v1/security/policies", - data=json.dumps(policyCreationPayload), - headers={'Content-Type': 'application/json'}, - auth=(nmsUsername, nmsPassword), - verify=False) - - return r - - -# Retrieve security policies information -def __getAllPolicies__(nmsUrl: str, nmsUsername: str, nmsPassword: str): - return requests.get(url=f'{nmsUrl}/api/platform/v1/security/policies', - auth=(nmsUsername, nmsPassword), verify=False) - - -# Delete security policy from control plane -def __deletePolicy__(nmsUrl: str, nmsUsername: str, nmsPassword: str, policyUid: str): - return requests.delete(url=f'{nmsUrl}/api/platform/v1/security/policies/{policyUid}', - auth=(nmsUsername, nmsPassword), verify=False) - - -# Check NAP policies names validity for the given declaration -# Return a tuple: status, description. If status = 200 checks were successful -def checkDeclarationPolicies(declaration: dict): - # NGINX App Protect policies check - duplicated policy names - - # all policy names as defined in the declaration - # { 'policyName': 'activeTag', ... } - allPolicyNames = {} - - if 'policies' not in declaration['output']['nms']: - return 200, "" - - for policy in declaration['output']['nms']['policies']: - # print(f"Found NAP Policy [{policy['name']}] active tag [{policy['active_tag']}]") - - if policy['name'] and policy['name'] in allPolicyNames: - return 422, f"Duplicated NGINX App Protect WAF policy [{policy['name']}]" - - allPolicyNames[policy['name']] = policy['active_tag'] - - # Check policy releases for non-univoque tags - allPolicyVersionTags = {} - for policyVersion in policy['versions']: - if policyVersion['tag'] and policyVersion['tag'] in allPolicyVersionTags: - return 422, f"Duplicated NGINX App Protect WAF policy tag [{policyVersion['tag']}] " \ - f"for policy [{policy['name']}]" - - allPolicyVersionTags[policyVersion['tag']] = "found" - - if policy['active_tag'] and policy['active_tag'] not in allPolicyVersionTags: - return 422, f"Invalid active tag [{policy['active_tag']}] for policy [{policy['name']}]" - - # Check policy names referenced by the declaration inside HTTP servers[]: they must be valid - if 'http' in declaration['declaration'] and 'servers' in declaration['declaration']['http']: - for httpServer in declaration['declaration']['http']['servers']: - if 'app_protect' in httpServer: - if 'policy' in httpServer['app_protect'] and httpServer['app_protect']['policy'] \ - and httpServer['app_protect']['policy'] not in allPolicyNames: - return 422, f"Unknown NGINX App Protect WAF policy [{httpServer['app_protect']['policy']}] " \ - f"referenced by HTTP server [{httpServer['name']}]" - - if 'log' in httpServer['app_protect'] \ - and 'profile_name' in httpServer['app_protect']['log'] \ - and httpServer['app_protect']['log']['profile_name'] \ - and httpServer['app_protect']['log']['profile_name'] \ - not in available_log_profiles: - return 422, f"Invalid NGINX App Protect WAF log profile " \ - f"[{httpServer['app_protect']['log']['profile_name']}] referenced by HTTP server " \ - f"[{httpServer['name']}]" - - # Check policy names referenced in HTTP servers[].locations[] - for location in httpServer['locations']: - if 'app_protect' in location: - if 'policy' in location['app_protect'] and location['app_protect']['policy'] \ - and location['app_protect']['policy'] not in allPolicyNames: - return 422, f"Unknown NGINX App Protect WAF policy [{location['app_protect']['policy']}] " \ - f"referenced by HTTP server [{httpServer['name']}] location [{location['uri']}]" - - if 'log' in httpServer['app_protect'] and httpServer['app_protect']['log'] \ - and httpServer['app_protect']['log']['profile_name'] \ - and httpServer['app_protect']['log']['profile_name'] \ - not in available_log_profiles: - return 422, f"Invalid NGINX App Protect WAF log profile " \ - f"[{httpServer['app_protect']['log']['profile_name']}] referenced by HTTP server " \ - f"[{httpServer['name']}] location [{location['uri']}]" - - return 200, "" - - -# For the given declaration creates/updates NGINX App Protect WAF policies on NGINX Instance Manager -# making sure that they are in sync with what is defined in the JSON declaration -# Returns a JSON with status code and content -def provisionPolicies(nmsUrl: str, nmsUsername: str, nmsPassword: str, declaration: dict): - # NGINX App Protect policies - each policy supports multiple tagged versions - - # Policy names and all tag/uid pairs - # {'prod-policy': [{'tag': 'v1', 'uid': 'ebcf9c7e-0930-450d-8108-7cad30e59661'}, - # {'tag': 'v2', 'uid': 'd18c2eb7-814e-4e4d-90fc-54014eef199e'}], - # 'staging-policy': [{'tag': 'block', 'uid': '9794faa7-5b6c-4ce5-9e68-946f04766bb4'}, - # {'tag': 'xss-ok', 'uid': '7b4b850a-ff9e-42a0-85d0-850171474224'}]} - all_policy_names_and_versions = {} - - # Policy names and active tag uids - # { 'prod-policy': 'ebcf9c7e-0930-450d-8108-7cad30e59661', - # 'staging-policy': '7b4b850a-ff9e-42a0-85d0-850171474224' } - all_policy_active_names_and_uids = {} - - for p in declaration['output']['nms']['policies']: - policy_name = p['name'] - if policy_name: - policy_active_tag = p['active_tag'] - - # Iterates over all NGINX App Protect policies - if p['type'] == 'app_protect': - # Iterates over all policy versions - for policyVersion in p['versions']: - status, policyBody = v5_4.GitOps.getObjectFromRepo(policyVersion['contents']) - - if status != 200: - return JSONResponse( - status_code=422, - content={"code": status, - "details": policyBody['content']} - ) - - # Create the NGINX App Protect policy on NMS - r = __definePolicyOnNMS__( - nmsUrl=nmsUrl, nmsUsername=nmsUsername, nmsPassword=nmsPassword, - policyName=policy_name, - policyDisplayName=policyVersion['displayName'], - policyDescription=policyVersion['description'], - policyJson=policyBody['content'] - ) - - # Check for errors creating NGINX App Protect policy - if r.status_code != 201: - return JSONResponse( - status_code=r.status_code, - content={"code": r.status_code, "details": json.loads(r.text)} - ) - else: - # Policy was created, retrieve metadata.uid for each policy version - if policy_name not in all_policy_names_and_versions: - all_policy_names_and_versions[policy_name] = [] - - # Stores the policy version - uid = json.loads(r.text)['metadata']['uid'] - tag = policyVersion['tag'] - - if policy_active_tag == tag: - all_policy_active_names_and_uids[policy_name] = uid - - all_policy_names_and_versions[policy_name].append({'tag': tag, 'uid': uid}) - - return JSONResponse(status_code=200, content={"all_policy_names_and_versions": all_policy_names_and_versions, - "all_policy_active_names_and_uids": all_policy_active_names_and_uids}) - - -# Publish a NGINX App Protect WAF policy making it active -# activePolicyUids is a dict { "policy_name": "active_uid", [...] } -# Return True if at least one policy was enabled, False otherwise -def makePolicyActive(nmsUrl: str, nmsUsername: str, nmsPassword: str, activePolicyUids: dict, instanceGroupUid: str): - doWeHavePolicies = False - - for policyName in activePolicyUids: - body = { - "publications": [ - { - "policyContent": { - "name": f'{policyName}', - "uid": f'{activePolicyUids[policyName]}' - }, - "instanceGroups": [ - f'{instanceGroupUid}' - ] - } - ] - } - - doWeHavePolicies = True - r = requests.post(url=f'{nmsUrl}/api/platform/v1/security/publish', auth=(nmsUsername, nmsPassword), - data=json.dumps(body), headers={'Content-Type': 'application/json'}, verify=False) - - return doWeHavePolicies - - -# For the given declaration creates/updates NGINX App Protect WAF policies on NGINX Instance Manager -# making sure that they are in sync with what is defined in the JSON declaration -# Returns a tuple: status, response payload -def cleanPolicyLeftovers(nmsUrl: str, nmsUsername: str, nmsPassword: str, currentPolicies: dict): - # Fetch all policies currently defined on the control plane - allNMSPolicies = __getAllPolicies__(nmsUrl=nmsUrl, nmsUsername=nmsUsername, nmsPassword=nmsPassword) - allNMSPoliciesJson = json.loads(allNMSPolicies.text) - - # Build a list of all uids for policies currently available on the control plane whose names match - # currentPolicies (policies that have just been pushed to data plane) - allUidsOnNMS = [] - for p in allNMSPoliciesJson['items']: - if p['metadata']['name'] in currentPolicies: - allUidsOnNMS.append(p['metadata']['uid']) - - allCurrentPoliciesUIDs = [] - for policyName in currentPolicies: - if policyName: - for tag in currentPolicies[policyName]: - allCurrentPoliciesUIDs.append(tag['uid']) - - uidsToRemove = list(set(allUidsOnNMS) - set(allCurrentPoliciesUIDs)) - - for uid in uidsToRemove: - __deletePolicy__(nmsUrl=nmsUrl, nmsUsername=nmsUsername, nmsPassword=nmsPassword, policyUid=uid) - - return \ No newline at end of file diff --git a/src/v5_4/NIMOutput.py b/src/v5_4/NIMOutput.py deleted file mode 100644 index 20a0b8d7..00000000 --- a/src/v5_4/NIMOutput.py +++ /dev/null @@ -1,370 +0,0 @@ -""" -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_4_CreateConfig - -import v5_4.APIGateway -import v5_4.DevPortal -import v5_4.DeclarationPatcher -import v5_4.GitOps -import v5_4.MiscUtils -import v5_4.NIMOutput -import v5_4.NIMUtils - -# pydantic models -from V5_4_NginxConfigDeclaration import * - -# NGINX App Protect helper functions -import v5_4.NIMNAPUtils - -# NGINX Declarative API modules -from NcgConfig import NcgConfig -from NcgRedis import NcgRedis - -def NIMOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpConf: str, - b64StreamConf: str,configFiles = {}, auxFiles = {}, - runfromautosync: bool = False, - configUid: str = ""): - # NGINX Instance Manager Staged Configuration publish - - nmsUsername = v5_4.MiscUtils.getDictKey(d, 'output.nms.username') - nmsPassword = v5_4.MiscUtils.getDictKey(d, 'output.nms.password') - nmsInstanceGroup = v5_4.MiscUtils.getDictKey(d, 'output.nms.instancegroup') - nmsSynctime = v5_4.MiscUtils.getDictKey(d, 'output.nms.synctime') - - nmsUrlFromJson = v5_4.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'}} - - # DNS resolution check - dnsOutcome, dnsReply = v5_4.MiscUtils.resolveFQDN(urlCheck.netloc) - if not dnsOutcome: - return {"status_code": 400, - "message": {"status_code": 400, "message": {"code": 400, - "content": f"DNS resolution failed for {urlCheck.netloc}: {dnsReply}"}}, - "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_4.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_4.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_4.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 - - # TLS certificates and key names validity checks for servers - d_servers = v5_4.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_4.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']) + "] must be one of [" + ",".join(all_tls['certificate']) + "]"} - }} - - cert_key = v5_4.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']) + "] must be one of [" + ",".join(all_tls['key']) + "]"} - }} - - trusted_cert_name = v5_4.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']) - + "] must be one of [" + ",".join(all_tls['certificate']) + "]"} - }} - - # TLS certificates and key names validity checks or ACME issuer profiles - d_acmeissuers = v5_4.MiscUtils.getDictKey(d, 'declaration.http.acme_issuers') - if d_acmeissuers is not None: - for issuer in d_acmeissuers: - cert_name = issuer['ssl_trusted_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 ACME issuer [" + str( - issuer['name']) +"] must be one of [" + ",".join(all_tls['certificate']) + "]"} - }} - - # Add optional certificates specified under output.nms.certificates - extensions_map = {'certificate': '.crt', 'key': '.key'} - - d_certificates = v5_4.MiscUtils.getDictKey(d, 'output.nms.certificates') - if d_certificates is not None: - for c in d_certificates: - status, certContent = v5_4.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={'mainhttpfile': NcgConfig.config['nms']['staged_config_http_filename'], - 'mainstreamfile': NcgConfig.config['nms']['staged_config_stream_filename'], - 'modules': v5_4.MiscUtils.getDictKey(d, 'output.nms.modules'), - 'license': v5_4.MiscUtils.getDictKey(d, 'output.license')}, - d={'http': v5_4.MiscUtils.getDictKey(d, 'declaration.http')}) - - # Base64-encoded NGINX main configuration (/etc/nginx/nginx.conf) - b64NginxMain = str(base64.urlsafe_b64encode(nginxMainConf.encode("utf-8")), "utf-8") - - # NGINX License file - licenseJwtFile = j2_env.get_template(NcgConfig.config['templates']['license']).render( - nginxconf={'license': v5_4.MiscUtils.getDictKey(d, 'output.license')}) - - # Base64-encoded license file (/etc/nginx/license.jwt) - b64licenseJwtFile = str(base64.urlsafe_b64encode(licenseJwtFile.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'} - filesLicenseFile = {'contents': b64licenseJwtFile, 'name': NcgConfig.config['nms']['config_dir'] + '/license.jwt'} - 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) - - # If no R33+ license token was specified in the JSON declaration, it is assumed a token already exists - # on the NGINX instances and it won't be overwritten - if v5_4.MiscUtils.getDictKey(d, 'output.license.token') != "": - configFiles['files'].append(filesLicenseFile) - - # 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_4.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_4.NIMNAPUtils.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 - ppReply = v5_4.NIMNAPUtils.provisionPolicies( - nmsUrl=nmsUrl, nmsUsername=nmsUsername, nmsPassword=nmsPassword, declaration=d) - - if ppReply.status_code >= 400: - return {"status_code": ppReply.status_code, - "message": {"status_code": ppReply.status_code, "message": {"code": ppReply.status_code, "content": ppReply} }} - - napPolicies = json.loads(ppReply.body) - provisionedNapPolicies = napPolicies['all_policy_names_and_versions'] - activePolicyUids = napPolicies['all_policy_active_names_and_uids'] - - ### / 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_4.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_4.NIMNAPUtils.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_4.NIMNAPUtils.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_4_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_4/NIMUtils.py b/src/v5_4/NIMUtils.py deleted file mode 100644 index de1b9a96..00000000 --- a/src/v5_4/NIMUtils.py +++ /dev/null @@ -1,26 +0,0 @@ -""" -NGINX Instance Manager support functions -""" - -import requests -import json - - -# Fetch an instance group UID from NGINX Instance Manager -# Return None if not found -def getNIMInstanceGroupUid(nmsUrl: str, nmsUsername: str, nmsPassword: str, instanceGroupName: str): - # Retrieve instance group uid - ig = requests.get(url=f'{nmsUrl}/api/platform/v1/instance-groups', auth=(nmsUsername, nmsPassword), - verify=False) - - if ig.status_code != 200: - return None - - # Get the instance group id - igUid = None - igJson = json.loads(ig.text) - for i in igJson['items']: - if i['name'] == instanceGroupName: - igUid = i['uid'] - - return igUid diff --git a/src/v5_4/OpenAPIParser.py b/src/v5_4/OpenAPIParser.py deleted file mode 100644 index 6c65195c..00000000 --- a/src/v5_4/OpenAPIParser.py +++ /dev/null @@ -1,73 +0,0 @@ -""" -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): - if 'info' in self.openAPISchema: - return self.openAPISchema['info'] - - return None - - 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: - 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 diff --git a/src/v5_5/NGINXOneNAPUtils.py b/src/v5_5/NGINXOneNAPUtils.py index 9eecd999..c6421122 100644 --- a/src/v5_5/NGINXOneNAPUtils.py +++ b/src/v5_5/NGINXOneNAPUtils.py @@ -6,7 +6,7 @@ import json import base64 -import v5_4.GitOps +import v5_5.GitOps from NcgConfig import NcgConfig @@ -187,7 +187,7 @@ def provisionPolicies(nginxOneUrl: str, nginxOneToken: str, nginxOneNamespace: s # Create all policy versions for policyVersion in p['versions']: - status, policyBody = v5_4.GitOps.getObjectFromRepo(policyVersion['contents'],base64Encode=False) + status, policyBody = v5_5.GitOps.getObjectFromRepo(policyVersion['contents'],base64Encode=False) if status != 200: return JSONResponse( diff --git a/src/v5_5/NGINXOneOutput.py b/src/v5_5/NGINXOneOutput.py index 5e49eea0..3201b077 100644 --- a/src/v5_5/NGINXOneOutput.py +++ b/src/v5_5/NGINXOneOutput.py @@ -87,7 +87,7 @@ def NGINXOneOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpCo # Check TLS items validity all_tls = {'certificate': {}, 'key': {}} - d_certs = v5_5.MiscUtils.getDictKey(d, 'output.nginxone.certificates') + d_certs = v5_5.MiscUtils.getDictKey(d, 'declaration.http.certificates') if d_certs is not None: for i in range(len(d_certs)): if d_certs[i]['name']: @@ -146,10 +146,10 @@ def NGINXOneOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpCo issuer['name']) +"] must be one of [" + ",".join(all_tls['certificate']) + "]"} }} - # Add optional certificates specified under output.nginxone.certificates + # Add optional certificates specified under declaration.http.certificates extensions_map = {'certificate': '.crt', 'key': '.key'} - d_certificates = v5_5.MiscUtils.getDictKey(d, 'output.nginxone.certificates') + d_certificates = v5_5.MiscUtils.getDictKey(d, 'declaration.http.certificates') if d_certificates is not None: for c in d_certificates: status, certContent = v5_5.GitOps.getObjectFromRepo(object=c['contents'], @@ -163,7 +163,7 @@ def NGINXOneOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpCo '/' + c['name'] + extensions_map[c['type']]} auxFiles['files'].append(newAuxFile) - ### / Add optional certificates specified under output.nginxone.certificates + ### / Add optional certificates specified under declaration.http.certificates # NGINX main configuration file through template j2_env = Environment(loader=FileSystemLoader(NcgConfig.config['templates']['root_dir'] + '/' + apiversion), diff --git a/src/v5_5/NIMNAPUtils.py b/src/v5_5/NIMNAPUtils.py index 31bfa66e..e22d5f94 100644 --- a/src/v5_5/NIMNAPUtils.py +++ b/src/v5_5/NIMNAPUtils.py @@ -6,7 +6,7 @@ import json import base64 -import v5_4.GitOps +import v5_5.GitOps from NcgConfig import NcgConfig @@ -173,7 +173,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 = v5_4.GitOps.getObjectFromRepo(policyVersion['contents']) + status, policyBody = v5_5.GitOps.getObjectFromRepo(policyVersion['contents']) if status != 200: return JSONResponse( diff --git a/templates/v5.4/apigateway.tmpl b/templates/v5.4/apigateway.tmpl deleted file mode 100644 index 4a0171bd..00000000 --- a/templates/v5.4/apigateway.tmpl +++ /dev/null @@ -1,182 +0,0 @@ -{% 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 %} - -{% if declaration.info %} -# API Gateway: {% if declaration.info.title %}{{ declaration.info.title }}{% endif %} {% if declaration.info.version %}{{ declaration.info.version }}{% endif %} -{% endif %} - -# OpenAPI version: {{ declaration.version }} -# Base URI: {{ declaration.location.uri }} -# Strip base URI: {{ declaration.location.apigateway.api_gateway.strip_uri }} -# Destination server: {{ destination_server }} - -{% for v in enabledVisibility %} -include "{{ ncgconfig.nms.visibility_dir }}{{ declaration.location.uri }}-{{ v }}-server.conf"; -{% endfor %} - -{% if declaration.paths -%} -{% for path in declaration.paths|sort(attribute='path', reverse = True) %} -location {% if '{' not in path.path %}={% else %}~{% endif %} {% if declaration.location.uri != "/" %}{{ declaration.location.uri }}{% endif %}{{ 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.destination }}{% if declaration.location.apigateway.log.access.format %} {{ declaration.location.apigateway.log.access.format }}{% endif %}{% if declaration.location.apigateway.log.access.condition %} if={{ declaration.location.apigateway.log.access.condition }}{% endif %};{% endif %} - - {% if declaration.location.apigateway.log.error %}error_log {{ declaration.location.apigateway.log.error.destination }}{% if declaration.location.apigateway.log.error.level %} {{ declaration.location.apigateway.log.error.level }}{% endif %};{% 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 | replace(' ', '_') }}{% 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 --- #} - - {# --- Cache --- #} - {%- if declaration.location.apigateway.cache -%} - {%- for cacheEntry in declaration.location.apigateway.cache %} - {%- set enforceCache = namespace(toBeEnforced = False) -%} - {%- if cacheEntry.enforceOnPaths == False -%} - {%- set enforceCache.toBeEnforced = True -%} - {%- endif -%} - {%- for cachePath in cacheEntry.paths -%} - {%- if path.path == cachePath -%} - {%- if cacheEntry.enforceOnPaths == True -%} - {%- set enforceCache.toBeEnforced = True -%} - {%- else -%} - {%- set enforceCache.toBeEnforced = False -%} - {%- endif -%} - {%- endif -%} - {%- endfor -%} - - {%- if enforceCache.toBeEnforced == True -%} - {%- if cacheEntry.profile %}proxy_cache {{ cacheEntry.profile | replace(' ', '_') }}; - - {% if cacheEntry.key %}proxy_cache_key "{{ cacheEntry.key }}";{% endif %} - {% endif %} - - {% if cacheEntry.validity -%} - {% for validity in cacheEntry.validity -%} - proxy_cache_valid {{ validity.code }} {{ validity.ttl }}; - {% endfor %} - {% endif %} - {%- endif -%} - {%- endfor -%} - - {%- endif %} - - {# --- Cache end --- #} - - {% if declaration.location.apigateway.api_gateway.strip_uri -%} - rewrite ^{% if declaration.location.uri != "/" %}{{ declaration.location.uri }}{% endif %}/(.*)$ /$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$is_args$args; -} - -{% endfor %} - -{% if declaration.location.apigateway.developer_portal.enabled == True -%} - {% if declaration.location.apigateway.developer_portal.type.lower() == "redocly" %} -location = {% if declaration.location.uri != "/" %}{{ declaration.location.uri }}{% endif %}{{ declaration.location.apigateway.developer_portal.redocly.uri }} { - rewrite ^{% if declaration.location.uri != "/" %}{{ declaration.location.uri }}{% endif %}/(.*)$ /$1 break; - root {{ ncgconfig.nms.devportal_dir }}; -} - {% endif %} -{% endif %} -{% endif %} diff --git a/templates/v5.4/authn/client/jwks.tmpl b/templates/v5.4/authn/client/jwks.tmpl deleted file mode 100644 index aea3a355..00000000 --- a/templates/v5.4/authn/client/jwks.tmpl +++ /dev/null @@ -1,11 +0,0 @@ -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.4/authn/client/jwt.tmpl b/templates/v5.4/authn/client/jwt.tmpl deleted file mode 100644 index 14e97192..00000000 --- a/templates/v5.4/authn/client/jwt.tmpl +++ /dev/null @@ -1,6 +0,0 @@ -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.4/authn/client/mtls.tmpl b/templates/v5.4/authn/client/mtls.tmpl deleted file mode 100644 index 683facca..00000000 --- a/templates/v5.4/authn/client/mtls.tmpl +++ /dev/null @@ -1,29 +0,0 @@ -{%- 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.4/authn/client/oidc.tmpl b/templates/v5.4/authn/client/oidc.tmpl deleted file mode 100644 index 158e217f..00000000 --- a/templates/v5.4/authn/client/oidc.tmpl +++ /dev/null @@ -1,47 +0,0 @@ -# OpenID Connect provider for {{ authprofile.name }} - -oidc_provider {{ authprofile.name | replace(" ", "_") }} { - issuer {{ authprofile.oidc.issuer }}; - client_id {{ authprofile.oidc.client_id }}; - client_secret {{ authprofile.oidc.client_secret }}; - - {%- if authprofile.oidc.config_url -%} - config_url {{ authprofile.oidc.config_url }}; - {% endif %} - {%- if authprofile.oidc.cookie_name -%} - cookie_name {{ authprofile.oidc.cookie_name }}; - {% endif %} - {%- if authprofile.oidc.extra_auth_args -%} - extra_auth_args {{ authprofile.oidc.configextra_auth_args_url }}; - {% endif %} - {%- if authprofile.oidc.redirect_uri -%} - redirect_uri {{ authprofile.oidc.redirect_uri }}; - {% endif %} - {%- if authprofile.oidc.logout_uri -%} - logout_uri {{ authprofile.oidc.logout_uri }}; - {% endif %} - {%- if authprofile.oidc.post_logout_uri -%} - post_logout_uri {{ authprofile.oidc.post_logout_uri }}; - {% endif %} - {%- if authprofile.oidc.logout_token_hint -%} - logout_token_hint {% if authprofile.oidc.logout_token_hint == True %}on{% else %}off{% endif %}; - {% endif %} - {%- if authprofile.oidc.scope -%} - scope {{ authprofile.oidc.scope }}; - {% endif %} - {%- if authprofile.oidc.session_store -%} - session_store {{ authprofile.oidc.session_store }}; - {% endif %} - {%- if authprofile.oidc.session_timeout -%} - session_timeout {{ authprofile.oidc.session_timeout }}; - {% endif %} - {%- if authprofile.oidc.ssl_crl -%} - ssl_crl {{ ncgconfig.nms.certs_dir }}/{{ authprofile.oidc.ssl_crl }}.crt; - {% endif %} - {%- if authprofile.oidc.ssl_trusted_certificate -%} - ssl_trusted_certificate {{ ncgconfig.nms.certs_dir }}/{{ authprofile.oidc.ssl_trusted_certificate }}.crt; - {% endif %} - {%- if authprofile.oidc.userinfo -%} - userinfo {% if authprofile.oidc.userinfo == True %}on{% else %}off{% endif %}; - {% endif %} -} \ No newline at end of file diff --git a/templates/v5.4/authn/server/mtls.tmpl b/templates/v5.4/authn/server/mtls.tmpl deleted file mode 100644 index 5b0ae188..00000000 --- a/templates/v5.4/authn/server/mtls.tmpl +++ /dev/null @@ -1,2 +0,0 @@ -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.4/authn/server/token.tmpl b/templates/v5.4/authn/server/token.tmpl deleted file mode 100644 index 7acbd601..00000000 --- a/templates/v5.4/authn/server/token.tmpl +++ /dev/null @@ -1,7 +0,0 @@ -{% 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.4/authz/client/jwt-authz-map.tmpl b/templates/v5.4/authz/client/jwt-authz-map.tmpl deleted file mode 100644 index 047da21f..00000000 --- a/templates/v5.4/authz/client/jwt-authz-map.tmpl +++ /dev/null @@ -1,14 +0,0 @@ -{% 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.4/authz/client/jwt.tmpl b/templates/v5.4/authz/client/jwt.tmpl deleted file mode 100644 index f6b4d910..00000000 --- a/templates/v5.4/authz/client/jwt.tmpl +++ /dev/null @@ -1,3 +0,0 @@ -{% 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.4/devportal/backstage.tmpl b/templates/v5.4/devportal/backstage.tmpl deleted file mode 100644 index 9482f716..00000000 --- a/templates/v5.4/devportal/backstage.tmpl +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: API -metadata: - name: {{ declaration.name }} - annotations: - github.com/project-slug: backstage/backstage - backstage.io/techdocs-ref: dir:. - lighthouse.com/website-url: https://backstage.io -spec: - type: openapi - lifecycle: {{ declaration.lifecycle }} - owner: {{ declaration.owner }} - system: {{ declaration.system }} - definition: | -{% filter indent(width=4) %} - {{ openAPISchema }} -{% endfilter %} \ No newline at end of file diff --git a/templates/v5.4/http.tmpl b/templates/v5.4/http.tmpl deleted file mode 100644 index b8397ad9..00000000 --- a/templates/v5.4/http.tmpl +++ /dev/null @@ -1,140 +0,0 @@ -# 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 %} - -{# --- DNS resolver --- #} -{% if declaration.resolver -%} -include "{{ ncgconfig.nms.resolver_dir }}/{{ declaration.resolver | replace(" ", "_") }}.conf"; -{% endif -%} - -{# --- OpenID Connect providers --- #} -# OpenID Connect profiles -include "{{ ncgconfig.nms.auth_client_dir }}/oidc/*.conf"; - -{# --- ACME issuers shared zone --- #} -{% if declaration.acme_issuers %} -# ACME issuers shared memory zone -acme_shared_zone zone=ngx_acme_shared:1M; - -{%- for i in declaration.acme_issuers -%} -include "{{ ncgconfig.nms.acme_dir }}/{{ i.name | replace(" ", "_") }}.conf"; -{%- endfor -%} - -server { - # listener on port 80 is required to process ACME HTTP-01 challenges - listen 80; - - location / { - return 404; - } -} -{%- 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 %} -# Upstreams -{% for u in declaration.upstreams %} -{% if u.name %} -include "{{ ncgconfig.nms.upstream_http_dir }}/{{ u.name | replace(' ', '_') }}.conf"; -{% endif %} -{% endfor %} -{% endif %} - -{# --- Rate limit section --- #} -{% if declaration.rate_limit %} -# Rate limiting zones -{% for rl in declaration.rate_limit %} -limit_req_zone {{ rl.key }} zone={{ rl.name | replace(' ', '_') }}:{{ rl.size }} rate={{ rl.rate }}; -{% endfor %} -{% endif %} - -{# --- Cache section --- #} -{% if declaration.cache %} -# Cache zones -{% for c in declaration.cache %} -proxy_cache_path {{ c.basepath }}/{{ c.name | replace(' ', '_') }} levels=1:2 keys_zone={{ c.name | replace(' ', '_') }}:{{ c.ttl }} max_size={{ c.size }}; -{% endfor %} -{% endif -%} - -{# --- Visibility integration section --- #} -# Visibility integrations -include "{{ ncgconfig.nms.visibility_dir }}/*-http.conf"; - -{# --- 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 %} -include "{{ ncgconfig.nms.server_http_dir }}/{{ s.name | replace(' ', '_') }}.conf"; -{% endfor -%} \ No newline at end of file diff --git a/templates/v5.4/logformat.tmpl b/templates/v5.4/logformat.tmpl deleted file mode 100644 index db9863e5..00000000 --- a/templates/v5.4/logformat.tmpl +++ /dev/null @@ -1,12 +0,0 @@ -{ - "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.4/misc/acme.tmpl b/templates/v5.4/misc/acme.tmpl deleted file mode 100644 index 3b8d7642..00000000 --- a/templates/v5.4/misc/acme.tmpl +++ /dev/null @@ -1,21 +0,0 @@ -# ACME Issuer template - -acme_issuer {{ acmeprofile.name | replace(" ", "_") }} { - uri {{ acmeprofile.uri }}; -{% if acmeprofile.account_key %} - account_key {{ acmeprofile.account_key }}; -{% endif -%} -{% if acmeprofile.contact %} - contact {{ acmeprofile.contact }}; -{% endif %} -{% if acmeprofile.ssl_trusted_certificate %} - ssl_trusted_certificate {{ ncgconfig.nms.certs_dir }}/{{ acmeprofile.ssl_trusted_certificate }}.crt; -{% endif %} - ssl_verify {% if acmeprofile.ssl_verify == True %}on{% else %}off{% endif %}; -{% if acmeprofile.state_path %} - state_path {{ acmeprofile.state_path }}; -{% endif %} -{% if acmeprofile.accept_terms_of_service %} - accept_terms_of_service; -{% endif -%} -} diff --git a/templates/v5.4/misc/resolver.tmpl b/templates/v5.4/misc/resolver.tmpl deleted file mode 100644 index 963bc3c2..00000000 --- a/templates/v5.4/misc/resolver.tmpl +++ /dev/null @@ -1,4 +0,0 @@ -# DNS resolver template - -resolver {{ resolverprofile.address }}{% if resolverprofile.valid %}valid={{ resolverprofile.valid }}{% endif %} ipv4={% if resolverprofile.ipv4 == True %}on{% else %}off{% endif %} ipv6={% if resolverprofile.ipv6 == True %}on{% else %}off{% endif %}; -{% if resolverprofile.timeout %}resolver_timeout {{ resolverprofile.timeout }}{% endif %}; \ No newline at end of file diff --git a/templates/v5.4/misc/server-http.tmpl b/templates/v5.4/misc/server-http.tmpl deleted file mode 100644 index 0095f8cc..00000000 --- a/templates/v5.4/misc/server-http.tmpl +++ /dev/null @@ -1,359 +0,0 @@ -# HTTP server - {{ s.name }} - -server { - {#- --- 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.acme_issuer -%} - acme_certificate {{ s.listen.tls.acme_issuer | replace(" ", "_") }}; - {% endif -%} - - {%- 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] | replace(" ", "_") }}; - proxy_ssl_server_name on; - {% endif %} - - {% if s.resolver -%} - include "{{ ncgconfig.nms.resolver_dir }}/{{ s.resolver | replace(" ", "_") }}.conf"; - {% 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.destination }}{% if s.log.access.format %} {{ s.log.access.format }}{% endif %}{% if s.log.access.condition %} if={{ s.log.access.condition }}{% endif %};{% endif %} - - {% if s.log.error %}error_log {{ s.log.error.destination }}{% if s.log.error.level %} {{ s.log.error.level }}{% endif %};{% endif %} - - {# --- Client authentication at server {} level --- #} - {%- if s.authentication and s.authentication.client -%} - {%- for clientAuthProfile in s.authentication.client -%} - {%- set isThisOIDC = namespace(found = False) -%} - {%- for declClientAuthProfile in declaration.authentication.client -%} - {%- if declClientAuthProfile.type == "oidc" and declClientAuthProfile.name == clientAuthProfile.profile -%} - auth_oidc {{ clientAuthProfile.profile | replace(" ", "_") }}; - {%- set isThisOIDC.found = True -%} - {% endif -%} - {%- endfor -%} - {%- if isThisOIDC.found == False -%} - include "{{ ncgconfig.nms.auth_client_dir }}/{{ clientAuthProfile.profile | replace(" ", "_") }}.conf"; - {%- endif -%} - {% 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 %} - - {# --- Cache --- #} - {%- if s.cache -%} - {%- if s.cache.profile %}proxy_cache {{ s.cache.profile | replace(' ', '_') }}; - - {% if s.cache.key %}proxy_cache_key "{{ s.cache.key }}";{% endif %} - {% endif %} - - {% if s.cache.validity -%} - {% for validity in s.cache.validity -%} - proxy_cache_valid {{ validity.code }} {{ validity.ttl }}; - {% endfor %} - {% endif %} - - {% 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.destination }}{% if loc.log.access.format %} {{ loc.log.access.format }}{% endif %}{% if loc.log.access.condition %} if={{ loc.log.access.condition }}{% endif %};{% endif -%} - - {% if loc.log.error %}error_log {{ loc.log.error.destination }}{% if loc.log.error.level %} {{ loc.log.error.level }}{% endif %};{% 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 %} - - {# --- Cache --- #} - {%- if loc.cache -%} - {%- if loc.cache.profile %}proxy_cache {{ loc.cache.profile | replace(' ', '_') }}; - - {% if loc.cache.key %}proxy_cache_key "{{ loc.cache.key }}";{% endif %} - {% endif %} - - {% if loc.cache.validity -%} - {% for validity in loc.cache.validity -%} - proxy_cache_valid {{ validity.code }} {{ validity.ttl }}; - {% endfor %} - {% endif %} - - {% endif %} - - {# --- Client authentication at location level --- #} - {%- if loc.authentication and loc.authentication.client -%} - {%- for clientAuthProfile in loc.authentication.client -%} - {%- set isThisOIDC = namespace(found = False) -%} - {%- for declClientAuthProfile in declaration.authentication.client -%} - {%- if declClientAuthProfile.type == "oidc" and declClientAuthProfile.name == clientAuthProfile.profile -%} - auth_oidc {{ clientAuthProfile.profile | replace(" ", "_") }}; - {%- set isThisOIDC.found = True -%} - {% endif -%} - {%- endfor -%} - {%- if isThisOIDC.found == False -%} - include "{{ ncgconfig.nms.auth_client_dir }}/{{ clientAuthProfile.profile | replace(" ", "_") }}.conf"; - {%- endif -%} - {% 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 }}/{{ s.names[0] }}{{ 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 %} - -} \ No newline at end of file diff --git a/templates/v5.4/misc/server-stream.tmpl b/templates/v5.4/misc/server-stream.tmpl deleted file mode 100644 index 0d8a4e73..00000000 --- a/templates/v5.4/misc/server-stream.tmpl +++ /dev/null @@ -1,43 +0,0 @@ -# Stream server template - - {%- 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 | replace(" ", "_") }}; - {% endif -%} - {% endif -%} - - {% if s.resolver -%} - include "{{ ncgconfig.nms.resolver_dir }}/{{ s.resolver | replace(" ", "_") }}.conf"; - {% 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 -%} \ No newline at end of file diff --git a/templates/v5.4/misc/upstream-http.tmpl b/templates/v5.4/misc/upstream-http.tmpl deleted file mode 100644 index 5c82a664..00000000 --- a/templates/v5.4/misc/upstream-http.tmpl +++ /dev/null @@ -1,23 +0,0 @@ -# HTTP upstream template - -{% 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.resolver -%} - include "{{ ncgconfig.nms.resolver_dir }}/{{ u.resolver | replace(" ", "_") }}.conf"; - {% endif -%} - - {% if u.snippet and u.snippet.content %}{{ u.snippet.content | b64decode }}{% endif %} - -} -{% endif %} -{% endif %} \ No newline at end of file diff --git a/templates/v5.4/misc/upstream-stream.tmpl b/templates/v5.4/misc/upstream-stream.tmpl deleted file mode 100644 index 2e686aff..00000000 --- a/templates/v5.4/misc/upstream-stream.tmpl +++ /dev/null @@ -1,19 +0,0 @@ -# Stream upstream template - -{% 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 %} - - {% if u.resolver -%} - include "{{ ncgconfig.nms.resolver_dir }}/{{ u.resolver | replace(" ", "_") }}.conf"; - {% endif %} - -} -{% endif %} -{% endif %} \ No newline at end of file diff --git a/templates/v5.4/nginx-conf/license-key.tmpl b/templates/v5.4/nginx-conf/license-key.tmpl deleted file mode 100644 index f729d84c..00000000 --- a/templates/v5.4/nginx-conf/license-key.tmpl +++ /dev/null @@ -1 +0,0 @@ -{{ nginxconf.license.token }} \ No newline at end of file diff --git a/templates/v5.4/nginx-conf/mime.types b/templates/v5.4/nginx-conf/mime.types deleted file mode 100644 index d4e08dfe..00000000 --- a/templates/v5.4/nginx-conf/mime.types +++ /dev/null @@ -1,97 +0,0 @@ -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.4/nginx-conf/nginx.conf b/templates/v5.4/nginx-conf/nginx.conf deleted file mode 100644 index de18d5d9..00000000 --- a/templates/v5.4/nginx-conf/nginx.conf +++ /dev/null @@ -1,65 +0,0 @@ -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"'; - - # Additional log formats - {% if d.http.logformats -%} - # found - {% for lf in d.http.logformats -%} - log_format {{ lf.name }} escape={{ lf.escape }} '{{ lf.format }}'; - {% endfor -%} - {%- endif %} - - access_log /var/log/nginx/access.log main; - - sendfile on; - #tcp_nopush on; - keepalive_timeout 65; - #gzip on; - include /etc/nginx/{{ nginxconf.mainhttpfile }}; -} - -# 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/{{ nginxconf.mainstreamfile }}; -} - -{% if nginxconf.license %} -# NGINX R33+ license -mgmt { - # Default reporting sent to product.connect.nginx.com - usage_report endpoint={{ nginxconf.license.endpoint }}; - license_token /etc/nginx/license.jwt; - - # Set to 'off' to begin the 180-day reporting enforcement grace period. - # Reporting must begin or resume before the end of the grace period - # to ensure continued operation. - enforce_initial_report {% if nginxconf.license.grace_period == False %}on{% else %}off{% endif %}; - - # Set to 'off' to trust all SSL certificates (not recommended). - # Useful for reporting to NGINX Instance Manager without a local PKI. - ssl_verify {% if nginxconf.license.ssl_verify == True %}on{% else %}off{% endif %}; -} -{% endif %} \ No newline at end of file diff --git a/templates/v5.4/stream.tmpl b/templates/v5.4/stream.tmpl deleted file mode 100644 index 2374f026..00000000 --- a/templates/v5.4/stream.tmpl +++ /dev/null @@ -1,17 +0,0 @@ -# NGINX configuration file - Stream servers - generated by https://github.com/f5devcentral/NGINX-Declarative-API - -{# --- Upstreams section --- #} -{% if declaration.upstreams %} -# Upstreams -{% for u in declaration.upstreams %} -{% if u.name %} -include "{{ ncgconfig.nms.upstream_stream_dir }}/{{ u.name | replace(' ', '_') }}.conf"; -{% endif %} -{% endfor %} -{% endif %} - -{# --- Stream server section --- #} - -{% for s in declaration.servers %} -include "{{ ncgconfig.nms.server_stream_dir }}/{{ s.name | replace(' ', '_') }}.conf"; -{%- endfor %} diff --git a/templates/v5.4/visibility/moesif/http.tmpl b/templates/v5.4/visibility/moesif/http.tmpl deleted file mode 100644 index ccf38e2a..00000000 --- a/templates/v5.4/visibility/moesif/http.tmpl +++ /dev/null @@ -1,14 +0,0 @@ -# Moesif integration - https://www.moesif.com/docs/server-integration/nginx-openresty/ -# URI: {{ loc.uri }} -# application ID: {{ vis.moesif.application_id }} - -lua_shared_dict moesif_conf 5m; - -init_by_lua_block { - local config = ngx.shared.moesif_conf; - config:set("application_id", "{{ vis.moesif.application_id }}") -} - -lua_package_cpath ";;${prefix}?.so;${prefix}src/?.so;/usr/share/lua/5.1/lua/resty/moesif/?.so;/usr/share/lua/5.1/?.so;/usr/lib64/lua/5.1/?.so;/usr/lib/lua/5.1/?.so;/usr/local/openresty/luajit/share/lua/5.1/lua/resty?.so;/usr/local/share/lua/5.1/resty/moesif/?.so;{{ vis.moesif.plugin_path }}/?.so"; -lua_package_path ";;${prefix}?.lua;${prefix}src/?.lua;/usr/share/lua/5.1/lua/resty/moesif/?.lua;/usr/share/lua/5.1/?.lua;/usr/lib64/lua/5.1/?.lua;/usr/lib/lua/5.1/?.lua;/usr/local/openresty/luajit/share/lua/5.1/lua/resty?.lua;/usr/local/share/lua/5.1/resty/moesif/?.lua;{{ vis.moesif.plugin_path }}/?.lua"; - diff --git a/templates/v5.4/visibility/moesif/server.tmpl b/templates/v5.4/visibility/moesif/server.tmpl deleted file mode 100644 index 51c58dab..00000000 --- a/templates/v5.4/visibility/moesif/server.tmpl +++ /dev/null @@ -1,21 +0,0 @@ -# Moesif integration - https://www.moesif.com/docs/server-integration/nginx-openresty/ -# URI: {{ loc.uri }} -# application ID: {{ vis.moesif.application_id }} - -# Define the variables Moesif requires -set $moesif_user_id nil; -set $moesif_company_id nil; -set $moesif_req_body nil; -set $moesif_res_body nil; - -# Optionally, set moesif_user_id and moesif_company_id such from a request header or NGINX var to identify customer -header_filter_by_lua_block { - ngx.var.moesif_user_id = ngx.req.get_headers()["X-User-Id"] - ngx.var.moesif_company_id = ngx.req.get_headers()["X-Company-Id"] -} - -# Add Moesif plugin -access_by_lua_file {{ vis.moesif.plugin_path }}/read_req_body.lua; -body_filter_by_lua_file {{ vis.moesif.plugin_path }}/read_res_body.lua; -log_by_lua_file {{ vis.moesif.plugin_path }}/send_event.lua; - diff --git a/webui/IMPLEMENTATION.md b/webui/IMPLEMENTATION.md index 11670441..6bdf4ae4 100644 --- a/webui/IMPLEMENTATION.md +++ b/webui/IMPLEMENTATION.md @@ -308,7 +308,6 @@ location /v5.5/ { - [Web UI README](../webui/README.md) - Detailed Web UI documentation - [USAGE-v5.5.md](../USAGE-v5.5.md) - API v5.5 usage guide - [Docker Compose README](../contrib/docker-compose/README.md) - Deployment guide -- [OpenAPI Spec](../openapi.json) - Complete API specification ## 🤝 Contributing From bc7a68e00e96915f1ed81331309ea117af5dd6e1 Mon Sep 17 00:00:00 2001 From: Fabrizio Fiorucci Date: Tue, 21 Apr 2026 15:25:27 +0100 Subject: [PATCH 02/12] v5.6 initial commit --- USAGE-v5.6.md | 70 ++ src/V5_6_CreateConfig.py | 915 ++++++++++++++ src/V5_6_NginxConfigDeclaration.py | 1056 +++++++++++++++++ src/v5_6/APIGateway.py | 40 + src/v5_6/Asynchronous.py | 36 + src/v5_6/DeclarationPatcher.py | 238 ++++ src/v5_6/DevPortal.py | 46 + src/v5_6/GitOps.py | 83 ++ src/v5_6/MiscUtils.py | 67 ++ src/v5_6/NGINXOneNAPUtils.py | 256 ++++ src/v5_6/NGINXOneOutput.py | 379 ++++++ src/v5_6/NGINXOneUtils.py | 32 + src/v5_6/NIMNAPUtils.py | 276 +++++ src/v5_6/NIMOutput.py | 375 ++++++ src/v5_6/NIMUtils.py | 26 + src/v5_6/OpenAPIParser.py | 102 ++ templates/v5.6/apigateway-maps.tmpl | 72 ++ templates/v5.6/apigateway.tmpl | 210 ++++ templates/v5.6/authn/client/jwks.tmpl | 11 + templates/v5.6/authn/client/jwt.tmpl | 6 + templates/v5.6/authn/client/mtls.tmpl | 29 + templates/v5.6/authn/client/oidc.tmpl | 47 + templates/v5.6/authn/server/mtls.tmpl | 2 + templates/v5.6/authn/server/token.tmpl | 7 + .../v5.6/authz/client/jwt-authz-map.tmpl | 14 + templates/v5.6/authz/client/jwt.tmpl | 3 + templates/v5.6/devportal/backstage.tmpl | 17 + templates/v5.6/http.tmpl | 147 +++ templates/v5.6/logformat.tmpl | 12 + templates/v5.6/misc/acme.tmpl | 21 + templates/v5.6/misc/resolver.tmpl | 4 + templates/v5.6/misc/server-http.tmpl | 360 ++++++ templates/v5.6/misc/server-stream.tmpl | 43 + templates/v5.6/misc/upstream-http.tmpl | 23 + templates/v5.6/misc/upstream-stream.tmpl | 19 + templates/v5.6/nginx-conf/license-key.tmpl | 1 + templates/v5.6/nginx-conf/mime.types | 97 ++ templates/v5.6/nginx-conf/nginx.conf | 72 ++ templates/v5.6/stream.tmpl | 17 + templates/v5.6/visibility/moesif/http.tmpl | 14 + templates/v5.6/visibility/moesif/server.tmpl | 21 + 41 files changed, 5266 insertions(+) create mode 100644 USAGE-v5.6.md create mode 100644 src/V5_6_CreateConfig.py create mode 100644 src/V5_6_NginxConfigDeclaration.py create mode 100644 src/v5_6/APIGateway.py create mode 100644 src/v5_6/Asynchronous.py create mode 100644 src/v5_6/DeclarationPatcher.py create mode 100644 src/v5_6/DevPortal.py create mode 100644 src/v5_6/GitOps.py create mode 100644 src/v5_6/MiscUtils.py create mode 100644 src/v5_6/NGINXOneNAPUtils.py create mode 100644 src/v5_6/NGINXOneOutput.py create mode 100644 src/v5_6/NGINXOneUtils.py create mode 100644 src/v5_6/NIMNAPUtils.py create mode 100644 src/v5_6/NIMOutput.py create mode 100644 src/v5_6/NIMUtils.py create mode 100644 src/v5_6/OpenAPIParser.py create mode 100644 templates/v5.6/apigateway-maps.tmpl create mode 100644 templates/v5.6/apigateway.tmpl create mode 100644 templates/v5.6/authn/client/jwks.tmpl create mode 100644 templates/v5.6/authn/client/jwt.tmpl create mode 100644 templates/v5.6/authn/client/mtls.tmpl create mode 100644 templates/v5.6/authn/client/oidc.tmpl create mode 100644 templates/v5.6/authn/server/mtls.tmpl create mode 100644 templates/v5.6/authn/server/token.tmpl create mode 100644 templates/v5.6/authz/client/jwt-authz-map.tmpl create mode 100644 templates/v5.6/authz/client/jwt.tmpl create mode 100644 templates/v5.6/devportal/backstage.tmpl create mode 100644 templates/v5.6/http.tmpl create mode 100644 templates/v5.6/logformat.tmpl create mode 100644 templates/v5.6/misc/acme.tmpl create mode 100644 templates/v5.6/misc/resolver.tmpl create mode 100644 templates/v5.6/misc/server-http.tmpl create mode 100644 templates/v5.6/misc/server-stream.tmpl create mode 100644 templates/v5.6/misc/upstream-http.tmpl create mode 100644 templates/v5.6/misc/upstream-stream.tmpl create mode 100644 templates/v5.6/nginx-conf/license-key.tmpl create mode 100644 templates/v5.6/nginx-conf/mime.types create mode 100644 templates/v5.6/nginx-conf/nginx.conf create mode 100644 templates/v5.6/stream.tmpl create mode 100644 templates/v5.6/visibility/moesif/http.tmpl create mode 100644 templates/v5.6/visibility/moesif/server.tmpl diff --git a/USAGE-v5.6.md b/USAGE-v5.6.md new file mode 100644 index 00000000..22ad88fc --- /dev/null +++ b/USAGE-v5.6.md @@ -0,0 +1,70 @@ +# Usage for NGINX Declarative API v5.6 + +Version 5.6 supports: + +- [NGINX Instance Manager](https://docs.nginx.com/nginx-instance-manager/) 2.21+ +- [NGINX One Console](https://docs.nginx.com/nginx-one-console/) +- [NGINX Plus](https://docs.nginx.com/nginx/) R35+ +- [F5 WAF for NGINX](https://docs.nginx.com/waf/) with precompiled [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) for usage examples + +- `.output.license` defines the JWT license to use + - `.output.license.endpoint` the usage reporting endpoint (defaults to `product.connect.nginx.com`). NGINX Instance Manager address or FQDN can be used here + - `.output.license.token` the JWT license token. If this field is omitted, it is assumed that a `/etc/nginx/license.jwt` token already exists on the instance and it won't be replaced + - `.output.license.ssl_verify` set to `false` to trust all SSL certificates (not recommended). Useful for reporting to NGINX Instance Manager without a local PKI. + - `.output.license.grace_period` Set to 'true' to begin the 180-day reporting enforcement grace period. Reporting must begin or resume before the end of the grace period to ensure continued operation + - `.output.license.proxy` The optional explicit forward proxy `IP_address:port` or `FQDN:port` for usage reporting + - `.output.license.proxy_username` The optional explicit forward proxy authentication username for usage reporting + - `.output.license.proxy_password` The optional explicit forward proxy authentication password for usage reporting +- `.output.type` defines how NGINX configuration will be returned: + - *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.synchronous` **optional**, when set to `True` (default) the NGINX Declarative API waits for NGINX Instance Manager successful reply after publishing the NGINX configuration. Setting this to `False` enqueues the request, supporting multiple JSON declarations to be submitted at the same time/from multiple clients. Currently supported for `PATCH` operations only. + - `.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 + - *nginxone* - NGINX configuration is published to a NGINX One Console config sync group + - `.output.nginxone.url` the NGINX One Console URL + - `.output.nginxone.namespace` the NGINX One Console namespace + - `.output.nginxone.token` the authentication token + - `.output.nginxone.configsyncgroup` the NGINX One Console config sync group name + - `.output.nginxone.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 One Cloud Console + - `.output.nms.synchronous` **optional**, when set to `True` (default) the NGINX Declarative API waits for NGINX One Console successful reply after publishing the NGINX configuration. Setting this to `False` enqueues the request, supporting multiple JSON declarations to be submitted at the same time/from multiple clients. Currently supported for `PATCH` operations only. + - `.output.nginxone.modules` an optional array of NGINX module names (ie. 'ngx_http_app_protect_module', 'ngx_http_js_module','ngx_stream_js_module') + - `.output.nginxone.certificates` an optional array of TLS certificates/keys/chains to be published + - `.output.nginxone.certificates[].type` the item type ('certificate', 'key', 'chain') + - `.output.nginxone.certificates[].name` the certificate/key/chain name with no path/extension (ie. 'test-application') + - `.output.nginxone.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 +- `.declaration` describes the NGINX configuration to be created + - `.declaration.http[]` NGINX HTTP definitions + - `.declaration.layer4[]` NGINX TCP/UDP definitions + - `.declaration.resolvers[]` DNS resolvers definitions + +### API endpoints + +- `POST /v5.5/config/` - Publish a new declaration +- `PATCH /v5.5/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.5/config/{configUid}/submission/{submissionUid}` - Retrieve a submission (asynchronous `PATCH` request) status +- `GET /v5.5/config/{config_uid}` - Retrieve an existing declaration +- `DELETE /v5.5/config/{config_uid}` - Delete an existing declaration diff --git a/src/V5_6_CreateConfig.py b/src/V5_6_CreateConfig.py new file mode 100644 index 00000000..a437c689 --- /dev/null +++ b/src/V5_6_CreateConfig.py @@ -0,0 +1,915 @@ +""" +Configuration creation based on jinja2 templates +""" + +import base64 +import json +import pickle +from urllib.parse import urlparse + +import requests +import schedule +from fastapi.responses import Response, JSONResponse +from jinja2 import Environment, FileSystemLoader +from pydantic import ValidationError +from requests.packages.urllib3.exceptions import InsecureRequestWarning + +import v5_6.APIGateway +import v5_6.DevPortal +import v5_6.DeclarationPatcher +import v5_6.GitOps +import v5_6.MiscUtils +import v5_6.NIMOutput +import v5_6.NGINXOneOutput + +# F5 WAF for NGINX helper functions +import v5_6.NIMNAPUtils +import v5_6.NIMUtils + +# NGINX Declarative API modules +from NcgConfig import NcgConfig +from NcgRedis import NcgRedis + +# pydantic models +from V5_6_NginxConfigDeclaration import * + +# Tolerates self-signed TLS certificates +requests.packages.urllib3.disable_warnings(InsecureRequestWarning) + + +def configautosync(configUid): + print("Autosyncing configuid [" + configUid + "]") + + declaration = '' + declFromRedis = NcgRedis.redis.get(f'ncg.declaration.{configUid}') + + if declFromRedis is not None: + declaration = pickle.loads(declFromRedis) + apiversion = NcgRedis.redis.get(f'ncg.apiversion.{configUid}').decode() + + createconfig(declaration=declaration, apiversion=apiversion, runfromautosync=True, configUid=configUid) + + +# Create the given declarative configuration +# Return a JSON string: +# { "status_code": nnn, "headers": {}, "message": {} } +def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosync: bool = False, configUid: str = ""): + # Building NGINX configuration for the given declaration + + # NGINX configuration files for staged config + configFiles = {'files': []} + + # NGINX auxiliary files for staged config + auxFiles = {'files': []} + + # Extra manifests to be returned to the caller + extraOutputManifests = [] + + try: + # Pydantic JSON validation + ConfigDeclaration(**declaration.model_dump()) + except ValidationError as e: + print(f'Invalid declaration {e}') + + d = declaration.model_dump() + decltype = d['output']['type'] + + j2_env = Environment(loader=FileSystemLoader(NcgConfig.config['templates']['root_dir'] + '/' + apiversion), + trim_blocks=True, extensions=["jinja2_base64_filters.Base64Filters"]) + j2_env.filters['regex_replace'] = v5_6.MiscUtils.regex_replace + + # Check resolver profiles validity and creates resolver config files + if 'resolvers' in d['declaration']: + all_resolver_profiles = [] + + d_resolver_profiles = v5_6.MiscUtils.getDictKey(d, 'declaration.resolvers') + if d_resolver_profiles is not None: + # Render all resolver profiles + for i in range(len(d_resolver_profiles)): + resolver_profile = d_resolver_profiles[i] + + # Add the rendered resolver configuration snippet as a config file in the staged configuration + templateName = NcgConfig.config['templates']['resolver'] + renderedResolverProfile = j2_env.get_template(templateName).render( + resolverprofile=resolver_profile, ncgconfig=NcgConfig.config) + + b64renderedResolverProfile = base64.b64encode(bytes(renderedResolverProfile, 'utf-8')).decode( + 'utf-8') + configFileName = NcgConfig.config['nms']['resolver_dir'] + '/' + resolver_profile['name'].replace(' ', + '_') + ".conf" + resolverProfileConfigFile = {'contents': b64renderedResolverProfile, + 'name': configFileName} + + all_resolver_profiles.append(resolver_profile['name']) + auxFiles['files'].append(resolverProfileConfigFile) + + if 'http' in d['declaration']: + if 'snippet' in d['declaration']['http']: + status, snippet = v5_6.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}} + + d['declaration']['http']['snippet'] = snippet + + # Check HTTP upstreams validity + all_upstreams = [] + http = d['declaration']['http'] + + if 'upstreams' in http: + for i in range(len(http['upstreams'])): + upstream = http['upstreams'][i] + + if upstream['resolver'] and upstream['resolver'] not in all_resolver_profiles: + return {"status_code": 422, + "message": {"status_code": status, "message": + {"code": status, + "content": f"invalid resolver profile [{upstream['resolver']}] in HTTP upstream [{upstream['name']}], must be one of {all_resolver_profiles}"}}} + + if upstream['snippet']: + status, snippet = v5_6.GitOps.getObjectFromRepo(object = upstream['snippet'], authProfiles = d['declaration']['http']['authentication']) + + if status != 200: + return {"status_code": 422, "message": {"status_code": status, "message": snippet}} + + d['declaration']['http']['upstreams'][i]['snippet'] = snippet + + # Add the rendered upstream configuration snippet as a config file in the staged configuration + templateName = NcgConfig.config['templates']['upstream_http'] + renderedUpstreamProfile = j2_env.get_template(templateName).render( + u=upstream, ncgconfig=NcgConfig.config) + + b64renderedUpstreamProfile = base64.b64encode(bytes(renderedUpstreamProfile, 'utf-8')).decode( + 'utf-8') + configFileName = NcgConfig.config['nms']['upstream_http_dir'] + '/' + upstream['name'].replace(' ', '_') + ".conf" + upstreamProfileConfigFile = {'contents': b64renderedUpstreamProfile, + 'name': configFileName} + + auxFiles['files'].append(upstreamProfileConfigFile) + all_upstreams.append(http['upstreams'][i]['name']) + + http = d['declaration']['http'] + + # Check HTTP rate_limit profiles validity + all_ratelimits = [] + + d_rate_limit = v5_6.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']) + + # Check HTTP cache profiles validity + all_cache_profiles = [] + + d_cache_profiles = v5_6.MiscUtils.getDictKey(d, 'declaration.http.cache') + if d_cache_profiles is not None: + for i in range(len(d_cache_profiles)): + all_cache_profiles.append(d_cache_profiles[i]['name']) + + # Check authentication profiles validity and creates authentication config files + + # List of all auth client & server profile names + all_auth_client_profiles = [] + all_auth_server_profiles = [] + + d_auth_profiles = v5_6.MiscUtils.getDictKey(d, 'declaration.http.authentication') + if d_auth_profiles is not None: + if 'client' in d_auth_profiles: + # Render all client authentication profiles + + auth_client_profiles = d_auth_profiles['client'] + for i in range(len(auth_client_profiles)): + auth_profile = auth_client_profiles[i] + + match auth_profile['type']: + case 'jwt': + # Add the rendered authentication configuration snippet as a config file in the staged configuration - jwt template + templateName = NcgConfig.config['templates']['auth_client_root']+"/jwt.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) + + # Add the rendered authentication configuration snippet as a config file in the staged configuration - jwks template + templateName = NcgConfig.config['templates']['auth_client_root']+"/jwks.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'] + '/jwks_'+auth_profile['name'].replace(' ','_')+".conf" + authProfileConfigFile = {'contents': b64renderedClientAuthProfile, + 'name': configFileName } + + 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) + + case 'oidc': + # Add the rendered authentication configuration snippet as a config file in the staged configuration - OpenID Connect template + templateName = NcgConfig.config['templates']['auth_client_root'] + "/oidc.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'] + '/oidc/' + 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 + + auth_server_profiles = d_auth_profiles['server'] + for i in range(len(auth_server_profiles)): + auth_profile = auth_server_profiles[i] + + match auth_profile['type']: + case 'token': + # 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) + + 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) + + 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_6.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} + + auxFiles['files'].append(authProfileConfigFile) + + # NGINX Javascript profiles + all_njs_profiles = [] + d_njs_files = v5_6.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_6.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) + + # NGINX ACME issuer profiles + d_acme_issuers = v5_6.MiscUtils.getDictKey(d, 'declaration.http.acme_issuers') + all_acme_issuers = [] + if d_acme_issuers is not None: + # Render all ACME issuer profiles + for i in range(len(d_acme_issuers)): + acme_issuer = d_acme_issuers[i] + + # Add the rendered resolver configuration snippet as a config file in the staged configuration + templateName = NcgConfig.config['templates']['acme_issuer'] + renderedAcmeIssuerProfile = j2_env.get_template(templateName).render( + acmeprofile=acme_issuer, ncgconfig=NcgConfig.config) + + b64renderedAcmeProfile = base64.b64encode(bytes(renderedAcmeIssuerProfile, 'utf-8')).decode( + 'utf-8') + configFileName = NcgConfig.config['nms']['acme_dir'] + '/' + acme_issuer['name'].replace( + ' ','_') + ".conf" + acmeProfileConfigFile = {'contents': b64renderedAcmeProfile, + 'name': configFileName} + + all_acme_issuers.append(acme_issuer['name']) + auxFiles['files'].append(acmeProfileConfigFile) + + # HTTP level Javascript hooks + d_http_njs_hooks = v5_6.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}"}}} + + # HTTP level resolver validity check + d_http_resolver = v5_6.MiscUtils.getDictKey(d, 'declaration.http.resolver') + if d_http_resolver: + if d_http_resolver not in all_resolver_profiles: + return {"status_code": 422, + "message": {"status_code": status, "message": + {"code": status, + "content": f"invalid resolver profile [{d_http_resolver}] in HTTP context, must be one of {all_resolver_profiles}"}}} + + # Parse HTTP servers + d_servers = v5_6.MiscUtils.getDictKey(d, 'declaration.http.servers') + if d_servers is not None: + for server in d_servers: + serverSnippet = '' + + # Server level resolver name validity check + if server['resolver']: + if server['resolver'] not in all_resolver_profiles: + return {"status_code": 422, + "message": {"status_code": status, "message": + {"code": status, + "content": f"invalid resolver profile [{server['resolver']}] in HTTP server [{server['name']}], must be one of {all_resolver_profiles}"}}} + + # Server level cache profile name validity + if server['cache']: + if server['cache']['profile'] not in all_cache_profiles and server['cache']['profile'] != "": + return {"status_code": 422, + "message": {"status_code": status, "message": + {"code": status, + "content": f"invalid cache profile [{server['cache']['profile']}] in HTTP server [{server['name']}], must be one of {all_cache_profiles}"}}} + + # 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}"}}} + + # Server 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}"}}} + + # ACME issuers name validity check + if 'acme_issuer' in server['listen']['tls']: + acmeIssuer = server['listen']['tls']['acme_issuer'] + if acmeIssuer and acmeIssuer not in all_acme_issuers: + return {"status_code": 422, + "message": {"status_code": status, "message": + {"code": status, + "content": f"invalid ACME issuer [{acmeIssuer}] in server [{server['name']}] must be one of {all_acme_issuers}"}}} + + if server['snippet']: + status, serverSnippet = v5_6.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}} + + serverSnippet = serverSnippet['content'] + + # Create HTTP server configuration file + httpServerConf = j2_env.get_template(NcgConfig.config['templates']['server_http']).render(declaration=d['declaration']['http'], s=server, ncgconfig=NcgConfig.config) + httpServerConfb64 = base64.b64encode(bytes(httpServerConf, 'utf-8')).decode('utf-8') + newHttpServerAuxFile = {'contents': httpServerConfb64, 'name': NcgConfig.config['nms']['server_http_dir'] + + '/' + server['name'].replace(' ', '_') + ".conf"} + auxFiles['files'].append(newHttpServerAuxFile) + + 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 = v5_6.GitOps.getObjectFromRepo(object = loc['snippet'], authProfiles = d['declaration']['http']['authentication']) + + if status != 200: + return {"status_code": 422, "message": {"status_code": status, "message": snippet}} + + loc['snippet'] = snippet + + # Location upstream name validity check + if 'upstream' in loc and loc['upstream'] and urlparse(loc['upstream']).netloc not in all_upstreams: + return {"status_code": 422, + "message": {"status_code": status, "message": + {"code": status, "content": f"invalid HTTP upstream [{loc['upstream']}]"}}} + + # Location client authentication name validity check + if 'authentication' in loc and loc['authentication']: + locAuthClientProfiles = loc['authentication']['client'] + + for authClientProfile in locAuthClientProfiles: + 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']}] 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']: + locAuthServerProfiles = loc['authentication']['server'] + + for authServerProfile in locAuthServerProfiles: + if authServerProfile['profile'] not in all_auth_server_profiles: + return {"status_code": 422, + "message": {"status_code": status, "message": + {"code": status, "content": f"invalid server authentication profile [{authServerProfile['profile']}] in location [{loc['uri']}]"}}} + + # API Gateway visualization integrations + apiGwVisibilityIntegrations = {} + + if loc['apigateway'] and loc['apigateway']['visibility']: + visibility_integrations = loc['apigateway']['visibility'] + for i in range(len(visibility_integrations)): + vis = visibility_integrations[i] + + if vis['enabled'] == True: + apiGwVisibilityIntegrations[ vis['type'] ] = True + + if vis['type'].lower() == 'moesif': + # Moesif integration + + # Add the rendered Moesif visibility configuration snippet as a config file in the staged configuration - HTTP context + templateName = NcgConfig.config['templates'][ + 'visibility_root'] + "/moesif/http.tmpl" + renderedMoesifHTTP = j2_env.get_template(templateName).render( + vis=vis, loc=loc, ncgconfig=NcgConfig.config) + + b64renderedMoesifHTTP = base64.b64encode( + bytes(renderedMoesifHTTP, 'utf-8')).decode( + 'utf-8') + moesifHTTPConfigFile = {'contents': b64renderedMoesifHTTP, + 'name': NcgConfig.config['nms'][ + 'visibility_dir'] + + loc['uri'] + "-moesif-http.conf"} + + auxFiles['files'].append(moesifHTTPConfigFile) + + # Add the rendered Moesif visibility configuration snippet as a config file in the staged configuration - server context + templateName = NcgConfig.config['templates'][ + 'visibility_root'] + "/moesif/server.tmpl" + renderedMoesifServer = j2_env.get_template(templateName).render( + vis=vis, loc=loc, ncgconfig=NcgConfig.config) + + b64renderedMoesifServer = base64.b64encode( + bytes(renderedMoesifServer, 'utf-8')).decode( + 'utf-8') + moesifServerConfigFile = {'contents': b64renderedMoesifServer, + 'name': NcgConfig.config['nms'][ + 'visibility_dir'] + + loc['uri'] + "-moesif-server.conf"} + + auxFiles['files'].append(moesifServerConfigFile) + + # API Gateway provisioning + if loc['apigateway'] and loc['apigateway']['api_gateway'] and loc['apigateway']['api_gateway']['enabled'] and loc['apigateway']['api_gateway']['enabled'] == True: + + # API Gateway authentication profile names validity check + if loc['apigateway']['authentication'] and loc['apigateway']['authentication']['client']: + apigw_authn_profiles = loc['apigateway']['authentication']['client'] + for i in range(len(apigw_authn_profiles)): + if apigw_authn_profiles[i]['profile'] not in all_auth_client_profiles: + return {"status_code": 422, + "message": {"status_code": status, "message": + {"code": status, + "content": f"invalid API Gateway authentication profile [{apigw_authn_profiles[i]['profile']}] for OpenAPI schema [{loc['apigateway']['openapi_schema']['content']}] must be one of {all_auth_client_profiles}"}}} + + # API Gateway authorization profile names validity check + if loc['apigateway']['authorization']: + apigw_authz_profiles = loc['apigateway']['authorization'] + for i in range(len(apigw_authz_profiles)): + if apigw_authz_profiles[i]['profile'] not in all_authz_client_profiles: + return {"status_code": 422, + "message": {"status_code": status, "message": + {"code": status, + "content": f"invalid API Gateway authorization profile [{apigw_authz_profiles[i]['profile']}] for OpenAPI schema [{loc['apigateway']['openapi_schema']['content']}] must be one of {all_authz_client_profiles}"}}} + + # API Gateway rate limiting profile names validity check + if loc['apigateway']['rate_limit']: + apigw_rl_profiles = loc['apigateway']['rate_limit'] + for i in range(len(apigw_rl_profiles)): + if apigw_rl_profiles[i]['profile'] not in all_ratelimits: + return {"status_code": 422, + "message": {"status_code": status, "message": + {"code": status, + "content": f"invalid API Gateway rate limit profile [{apigw_authz_profiles[i]['profile']}] for OpenAPI schema [{loc['apigateway']['openapi_schema']['content']}] must be one of {all_ratelimits}"}}} + + openApiAuthProfile = loc['apigateway']['openapi_schema']['authentication'] + if openApiAuthProfile and openApiAuthProfile[0]['profile'] not in all_auth_server_profiles: + return {"status_code": 422, + "message": {"status_code": status, "message": + {"code": status, + "content": f"invalid server authentication profile [{openApiAuthProfile[0]['profile']}] for OpenAPI schema [{loc['apigateway']['openapi_schema']['content']}]"}}} + + status, apiGatewayConfigDeclaration, openAPISchemaJSON = v5_6.APIGateway.createAPIGateway(locationDeclaration = loc, authProfiles = loc['apigateway']['openapi_schema']['authentication']) + + if status!=200: + return {"status_code": 412, + "message": {"status_code": status, "message": + {"code": status, + "content": f"OpenAPI schema fetch failed for {loc['apigateway']['openapi_schema']['content']}"}}} + + # API Gateway configuration template rendering + if apiGatewayConfigDeclaration: + # API Gateway server / locations file + apiGatewaySnippet = j2_env.get_template(NcgConfig.config['templates']['apigwconf']).render( + declaration=apiGatewayConfigDeclaration, server=server['names'][0], enabledVisibility=apiGwVisibilityIntegrations, ncgconfig=NcgConfig.config) + apiGatewaySnippetb64 = base64.b64encode(bytes(apiGatewaySnippet, 'utf-8')).decode('utf-8') + + newAuxFile = {'contents': apiGatewaySnippetb64, 'name': NcgConfig.config['nms']['apigw_dir'] + + '/' + server['names'][0] + + loc['uri'] + ".conf" } + auxFiles['files'].append(newAuxFile) + + # API Gateway maps file for parameters enforcement + apiGatewayMapsSnippet = j2_env.get_template(NcgConfig.config['templates']['apigwmapsconf']).render( + declaration=apiGatewayConfigDeclaration, server=server['names'][0], ncgconfig=NcgConfig.config) + apiGatewayMapsSnippetb64 = base64.b64encode(bytes(apiGatewayMapsSnippet, 'utf-8')).decode('utf-8') + + newAuxFile = {'contents': apiGatewayMapsSnippetb64, 'name': NcgConfig.config['nms']['apigw_maps_dir'] + + '/' + server['names'][0] + + loc['uri'].replace('/', '_') + ".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: + + if loc['apigateway']['developer_portal']['type'].lower() == 'redocly': + ### Redocly developer portal - Add optional API Developer portal HTML files + status, devPortalHTML = v5_6.DevPortal.createDevPortal(locationDeclaration=loc, + authProfiles= + d['declaration']['http'][ + 'authentication']) + + if status != 200: + return {"status_code": 412, + "message": {"status_code": status, "message": + {"code": status, + "content": f"Developer Portal creation failed for {loc['uri']}"}}} + + newAuxFile = {'contents': devPortalHTML, 'name': NcgConfig.config['nms']['devportal_dir'] + + loc['apigateway']['developer_portal']['redocly']['uri']} + auxFiles['files'].append(newAuxFile) + + ### / Redocly developer portal - Add optional API Developer portal HTML files + elif loc['apigateway']['developer_portal']['type'].lower() == 'backstage': + ### Backstage developer portal - Create Kubernetes Backstage manifest + backstageManifest = j2_env.get_template(f"{NcgConfig.config['templates']['devportal_root']}/backstage.tmpl").render( + declaration=loc['apigateway']['developer_portal']['backstage'], openAPISchema = v5_6.MiscUtils.json_to_yaml(openAPISchemaJSON), ncgconfig=NcgConfig.config) + + extraOutputManifests.append(backstageManifest) + ### / Backstage developer portal - Create Kubernetes Backstage manifest + + # Check location-level rate limit profile name validity + if loc['rate_limit'] is not None: + if 'profile' in loc['rate_limit'] and loc['rate_limit']['profile'] and loc['rate_limit'][ + 'profile'] not in all_ratelimits: + return {"status_code": 422, + "message": { + "status_code": status, + "message": + {"code": status, + "content": + f"invalid rate_limit profile [{loc['rate_limit']['profile']}]"}}} + + # Check location-level cache profile name validity + if loc['cache'] is not None: + if 'profile' in loc['cache'] and loc['cache']['profile'] and loc['cache'][ + 'profile'] not in all_cache_profiles and loc['cache'][ + 'profile'] != "": + return {"status_code": 422, + "message": { + "status_code": status, + "message": + {"code": status, + "content": + f"invalid cache profile [{loc['cache']['profile']}]"}}} + + 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 = v5_6.MiscUtils.getDictKey(d, 'declaration.layer4.upstreams') + if d_upstreams is not None: + for i in range(len(d_upstreams)): + upstream = d_upstreams[i] + + if upstream['resolver'] and upstream['resolver'] not in all_resolver_profiles: + return {"status_code": 422, + "message": {"status_code": status, "message": + {"code": status, + "content": f"invalid resolver profile [{upstream['resolver']}] in stream upstream [{upstream['name']}], must be one of {all_resolver_profiles}"}}} + + if upstream['snippet']: + status, snippet = v5_6.GitOps.getObjectFromRepo(object = upstream['snippet'], authProfiles = d['declaration']['http']['authentication']) + + if status != 200: + return {"status_code": 422, "message": {"status_code": status, "message": snippet}} + + d['declaration']['layer4']['upstreams'][i]['snippet'] = snippet + + # Add the rendered upstream configuration snippet as a config file in the staged configuration + templateName = NcgConfig.config['templates']['upstream_stream'] + renderedUpstreamProfile = j2_env.get_template(templateName).render( + u=upstream, ncgconfig=NcgConfig.config) + + b64renderedUpstreamProfile = base64.b64encode(bytes(renderedUpstreamProfile, 'utf-8')).decode( + 'utf-8') + configFileName = NcgConfig.config['nms']['upstream_stream_dir'] + '/' + upstream['name'].replace(' ', '_') + ".conf" + upstreamProfileConfigFile = {'contents': b64renderedUpstreamProfile, + 'name': configFileName} + + auxFiles['files'].append(upstreamProfileConfigFile) + + all_upstreams.append(d_upstreams[i]['name']) + + d_servers = v5_6.MiscUtils.getDictKey(d, 'declaration.layer4.servers') + if d_servers is not None: + for server in d_servers: + + # Server level resolver name validity check + if server['resolver']: + if server['resolver'] not in all_resolver_profiles: + return {"status_code": 422, + "message": {"status_code": status, "message": + {"code": status, + "content": f"invalid resolver profile [{server['resolver'] }] in stream server [{server['name']}], must be one of {all_resolver_profiles}"}}} + + if server['snippet']: + status, snippet = v5_6.GitOps.getObjectFromRepo(object = server['snippet'], authProfiles = d['declaration']['http']['authentication']) + + if status != 200: + return {"status_code": 422, "message": {"status_code": status, "message": snippet}} + + server['snippet'] = snippet + + if 'upstream' in server and server['upstream'] and server['upstream'] not in all_upstreams: + return {"status_code": 422, + "message": { + "status_code": status, + "message": + {"code": status, "content": f"invalid Layer4 upstream {server['upstream']}"}}} + + # Create Stream server configuration file + streamServerConf = j2_env.get_template(NcgConfig.config['templates']['server_stream']).render(s=server, ncgconfig=NcgConfig.config) + streamServerConfb64 = base64.b64encode(bytes(streamServerConf, 'utf-8')).decode('utf-8') + newStreamServerAuxFile = {'contents': streamServerConfb64, 'name': NcgConfig.config['nms']['server_stream_dir'] + + '/' + server['name'].replace(' ', '_') + ".conf"} + auxFiles['files'].append(newStreamServerAuxFile) + + # HTTP configuration template rendering + httpConf = j2_env.get_template(NcgConfig.config['templates']['httpconf']).render( + declaration=d['declaration']['http'], ncgconfig=NcgConfig.config) if 'http' in d['declaration'] else '' + + # Stream configuration template rendering + streamConf = j2_env.get_template(NcgConfig.config['templates']['streamconf']).render( + declaration=d['declaration']['layer4'], ncgconfig=NcgConfig.config) if 'layer4' in d['declaration'] else '' + + b64HttpConf = str(base64.b64encode(httpConf.encode("utf-8")), "utf-8") + b64StreamConf = str(base64.b64encode(streamConf.encode("utf-8")), "utf-8") + + if decltype.lower() == 'nms': + # Output to NGINX Instance Manager + + # NGINX configuration files for staged config + configFiles['rootDir'] = NcgConfig.config['nms']['config_dir'] + + # NGINX auxiliary files for staged config + auxFiles['rootDir'] = NcgConfig.config['nms']['config_dir'] + + finalReply = v5_6.NIMOutput.NIMOutput(d = d, declaration = declaration, apiversion = apiversion, + b64HttpConf = b64HttpConf, b64StreamConf = b64StreamConf, + configFiles = configFiles, + auxFiles = auxFiles, + runfromautosync = runfromautosync, configUid = configUid ) + + if finalReply['status_code'] == 200: + if len(extraOutputManifests) > 0: + finalReply['message']['message']['content']['manifests'] = extraOutputManifests + + return finalReply + + elif decltype.lower() == 'nginxone': + # Output to NGINX One Console + + # NGINX configuration files for staged config + configFiles['name'] = NcgConfig.config['nms']['config_dir'] + + # NGINX auxiliary files for staged config + auxFiles['name'] = NcgConfig.config['nms']['config_dir'] + + finalReply = v5_6.NGINXOneOutput.NGINXOneOutput(d = d, declaration = declaration, apiversion = apiversion, + b64HttpConf = b64HttpConf, b64StreamConf = b64StreamConf, + configFiles = configFiles, + auxFiles = auxFiles, + runfromautosync = runfromautosync, configUid = configUid ) + + if finalReply['status_code'] == 200: + if len(extraOutputManifests) > 0: + finalReply['message']['message']['content']['manifests'] = extraOutputManifests + + return finalReply + else: + return {"status_code": 422, "message": {"status_code": 422, "message": f"output type {decltype} unknown"}} + + +def patch_config(declaration: ConfigDeclaration, configUid: str, apiversion: str): + # Patch a declaration + if configUid not in NcgRedis.declarationsList: + return JSONResponse( + status_code=404, + content={'code': 404, 'details': {'message': f'declaration {configUid} not found'}}, + headers={'Content-Type': 'application/json'} + ) + + # The declaration sections to be patched + declarationToPatch = declaration.model_dump() + + # The currently applied declaration + status_code, currentDeclaration = get_declaration(configUid=configUid) + + # Handle policy updates + d_policies = v5_6.MiscUtils.getDictKey(declarationToPatch, 'declaration.http.policies') + if d_policies is not None: + # F5 WAF for NGINX policy updates + for p in d_policies: + currentDeclaration = v5_6.DeclarationPatcher.patchNAPPolicies( + sourceDeclaration=currentDeclaration, patchedNAPPolicies=p) + + # Handle certificate updates + d_certificates = v5_6.MiscUtils.getDictKey(declarationToPatch, 'declaration.http.certificates') + if d_certificates is not None: + # TLS certificate/key updates + for p in d_certificates: + currentDeclaration = v5_6.DeclarationPatcher.patchCertificates( + sourceDeclaration=currentDeclaration, patchedCertificates=p) + + # Handle declaration updates + if 'declaration' in declarationToPatch: + # HTTP + d_upstreams = v5_6.MiscUtils.getDictKey(declarationToPatch, 'declaration.http.upstreams') + if d_upstreams: + # HTTP upstream patch + for u in d_upstreams: + currentDeclaration = v5_6.DeclarationPatcher.patchHttpUpstream( + sourceDeclaration=currentDeclaration, patchedHttpUpstream=u) + + d_servers = v5_6.MiscUtils.getDictKey(declarationToPatch, 'declaration.http.servers') + if d_servers: + # HTTP servers patch + for s in d_servers: + currentDeclaration = v5_6.DeclarationPatcher.patchHttpServer( + sourceDeclaration=currentDeclaration, patchedHttpServer=s) + + # Stream / Layer4 + d_upstreams = v5_6.MiscUtils.getDictKey(declarationToPatch, 'declaration.layer4.upstreams') + if d_upstreams: + # Stream upstream patch + for u in d_upstreams: + currentDeclaration = v5_6.DeclarationPatcher.patchStreamUpstream( + sourceDeclaration=currentDeclaration, patchedStreamUpstream=u) + + d_servers = v5_6.MiscUtils.getDictKey(declarationToPatch, 'declaration.layer4.servers') + if d_servers: + # Stream servers patch + for s in d_servers: + currentDeclaration = v5_6.DeclarationPatcher.patchStreamServer( + sourceDeclaration=currentDeclaration, patchedStreamServer=s) + + # Apply the updated declaration + configDeclaration = ConfigDeclaration.model_validate_json(json.dumps(currentDeclaration)) + + r = createconfig(declaration=configDeclaration, apiversion=apiversion, + runfromautosync=True, configUid=configUid) + + # Return the updated declaration + message = r['message'] + + if r['status_code'] != 200: + currentDeclaration = {} + # message = f'declaration {configUid} update failed'; + + responseContent = {'code': r['status_code'], 'details': {'message': message}, + 'declaration': currentDeclaration, 'configUid': configUid} + + return JSONResponse( + status_code=r['status_code'], + content=responseContent, + headers={'Content-Type': 'application/json'} + ) + + +# Gets the given declaration. Returns status_code and body +def get_declaration(configUid: str): + cfg = NcgRedis.redis.get('ncg.declaration.' + configUid) + + if cfg is None: + return 404, "" + + return 200, pickle.loads(cfg).dict() diff --git a/src/V5_6_NginxConfigDeclaration.py b/src/V5_6_NginxConfigDeclaration.py new file mode 100644 index 00000000..d3436f08 --- /dev/null +++ b/src/V5_6_NginxConfigDeclaration.py @@ -0,0 +1,1056 @@ +""" +JSON declaration structure - NGINX Declarative API v5.6 +""" + +from __future__ import annotations +from typing import List, Optional +from pydantic import BaseModel, model_validator + +import re + +# Regexp to check names +alphanumRegexp = r'^[a-zA-Z0-9\ \-\_]+$' + + +class TLSCertificate(BaseModel, extra="forbid"): + type: str + name: str + contents: Optional[ObjectFromSourceOfTruth] = {} + + @model_validator(mode='after') + def check_type(self) -> 'TLSCertificate': + _type = self.type + + valid = ['certificate', 'key'] + if _type not in valid: + raise ValueError(f"Invalid certificate type [{_type}] must be one of {str(valid)}") + + return self + + +class NGINXPolicyVersion(BaseModel, extra="forbid"): + tag: str = "" + displayName: Optional[str] = "" + description: Optional[str] = "" + contents: Optional[ObjectFromSourceOfTruth] = {} + + +class NGINXPolicy(BaseModel, extra="forbid"): + type: str = "" + name: str = "" # Name must be identical to the policy name used in the App Protect policy JSON file + active_tag: str = "" + versions: Optional[List[NGINXPolicyVersion]] = [] + + @model_validator(mode='after') + def check_type(self) -> 'NGINXPolicy': + _type = self.type + + valid = ['app_protect'] + if _type not in valid: + raise ValueError(f"Invalid policy type [{_type}] must be one of {str(valid)}") + + return self + + +class AppProtectLogProfile(BaseModel, extra="forbid"): + name: str + format: Optional[str] = "default" + format_string: Optional[str] = "" + type: Optional[str] = "blocked" + max_request_size: Optional[str] = "any" + max_message_size: Optional[str] = "5k" + + @model_validator(mode='after') + def check_type(self) -> 'AppProtectLogProfile': + _type, _format, _format_string = self.type, self.format, self.format_string + + valid = ['all', 'illegal', 'blocked'] + if _type not in valid: + raise ValueError(f"Invalid NGINX App Protect log type [{_type}] must be one of {str(valid)}") + + valid = ['default', 'grpc', 'arcsight', 'splunk', 'user-defined'] + if _format not in valid: + raise ValueError(f"Invalid NGINX App Protect log format [{_format}] must be one of {str(valid)}") + + if _format == 'user-defined' and _format_string == "": + raise ValueError(f"NGINX App Protect log format {_format} requires format_string") + + return self + + +class LogProfile(BaseModel, extra="forbid"): + type: str + app_protect: Optional[AppProtectLogProfile] = {} + + @model_validator(mode='after') + def check_type(self) -> 'LogProfile': + _type, app_protect = self.type, self.app_protect + + valid = ['app_protect'] + if _type not in valid: + raise ValueError(f"Invalid log profile type [{_type}] must be one of {str(valid)}") + + isError = False + if _type == 'app_protect': + if app_protect is None: + isError = True + + if isError: + raise ValueError(f"Invalid log profile data for type [{_type}]") + + return self + + +class OutputNMS(BaseModel, extra="forbid"): + url: str = "" + username: str = "" + password: str = "" + instancegroup: str = "" + synctime: Optional[int] = 0 + modules: Optional[List[str]] = [] + + +class OutputNGINXOne(BaseModel, extra="forbid"): + url: str = "" + namespace: str = "" + token: str = "" + configsyncgroup: str = "" + synctime: Optional[int] = 0 + modules: Optional[List[str]] = [] + + +class License(BaseModel, extra="forbid"): + endpoint: Optional[str] = "product.connect.nginx.com" + token: Optional[str] = "" + ssl_verify: bool = True + grace_period: bool = False + proxy: Optional[str] = "" + proxy_username: Optional[str] = "" + proxy_password: Optional[str] = "" + + +class Output(BaseModel, extra="forbid"): + type: str + synchronous: bool = True + license: Optional[License] = {} + nms: Optional[OutputNMS] = {} + nginxone: Optional[OutputNGINXOne] = {} + + @model_validator(mode='after') + def check_type(self) -> 'Output': + _type,nms, nginxone = self.type, self.nms, self.nginxone + + valid = ['nms', 'nginxone'] + if _type not in valid: + raise ValueError(f"Invalid output type [{_type}] must be one of {str(valid)}") + + isError = False + + if _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}]") + + return self + + +class OcspStapling(BaseModel, extra="forbid"): + enabled: Optional[bool] = False + verify: Optional[bool] = False + responder: Optional[str] = "" + + +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 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) -> 'AuthClientMtls': + _enabled = self.enabled + + valid = ['on', 'off', 'optional', 'optional_no_ca'] + if _enabled not in valid: + raise ValueError(f"Invalid mTLS type [{_enabled}] must be one of {str(valid)}") + + return self + + +class L4Tls(BaseModel, extra="forbid"): + certificate: str = "" + key: str = "" + ciphers: Optional[str] = "" + protocols: Optional[List[str]] = [] + authentication: Optional[LocationAuth] = {} + + +class Tls(BaseModel, extra="forbid"): + certificate: Optional[str] = "" + key: Optional[str] = "" + acme_issuer: Optional[str] = "" + ciphers: Optional[str] = "" + protocols: Optional[List[str]] = [] + authentication: Optional[LocationAuth] = {} + + @model_validator(mode='after') + def check_type(self) -> 'Tls': + certificate, key, acme_issuer = self.certificate, self.key, self.acme_issuer + + if acme_issuer and (certificate or key): + raise ValueError(f"Certificate and key not allowed when ACME is used") + + if not acme_issuer and (not certificate or not key): + raise ValueError(f"Certificate and key required") + + return self + +class Listen(BaseModel, extra="forbid"): + address: Optional[str] = "" + http2: Optional[bool] = False + tls: Optional[Tls] = {} + + +class ListenL4(BaseModel, extra="forbid"): + address: Optional[str] = "" + protocol: Optional[str] = "tcp" + tls: Optional[L4Tls] = {} + + @model_validator(mode='after') + def check_type(self) -> 'ListenL4': + protocol, tls = self.protocol, self.tls + + valid = ['tcp', 'udp'] + if protocol not in valid: + raise ValueError(f"Invalid protocol [{protocol}] must be one of {str(valid)}") + + if protocol != 'tcp' and tls and tls.certificate: + raise ValueError("TLS termination over UDP is not supported") + + return self + + +class Log(BaseModel, extra="forbid"): + access: Optional[LogAccess] = {} + error: Optional[LogError] = {} + + +class LogAccess(BaseModel, extra="forbid"): + destination: str + format: Optional[str] = "combined" + condition: Optional[str] = "" + + +class LogError(BaseModel, extra="forbid"): + destination: str + level: Optional[str] = "info" + + @model_validator(mode='after') + def check_type(self) -> 'LogError': + level = self.level + + valid = ['debug','info','notice','warn','error','crit','alert','emerg'] + if level not in valid: + raise ValueError(f"Invalid error log level [{level}] must be one of {str(valid)}") + + return self + +class RateLimit(BaseModel, extra="forbid"): + profile: Optional[str] = "" + httpcode: Optional[int] = 429 + burst: Optional[int] = 0 + delay: Optional[int] = 0 + + +class LocationAuthClient(BaseModel, extra="forbid"): + profile: Optional[str] = "" + + +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 + burst: Optional[int] = 0 + delay: Optional[int] = 0 + enforceOnPaths: Optional[bool] = True + paths: Optional[List[str]] = [] + +class APIGatewayAuthentication(BaseModel, extra="forbid"): + client: Optional[List[LocationAuthClient]] = [] + enforceOnPaths: Optional[bool] = True + paths: Optional[List[str]] = [] + + +class APIGatewayAuthorization(BaseModel, extra="forbid"): + profile: str + enforceOnPaths: Optional[bool] = True + paths: Optional[List[str]] = [] + + +class APIGatewayCache(BaseModel, extra="forbid"): + profile: str + key: Optional[str] = "$scheme$proxy_host$request_uri"; + validity: Optional[List[CacheObjectTTL]] = [] + enforceOnPaths: Optional[bool] = True + paths: Optional[List[str]] = [] + + @model_validator(mode='after') + def check_type(self) -> 'APIGatewayCache': + profile = self.profile + + if not re.search(alphanumRegexp,profile): + raise ValueError(f"Invalid cache item [{profile}] should match regexp {alphanumRegexp}") + + return self + + +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") + + valid = ['signed', 'encrypted', 'nested'] + if jwt_type not in valid: + raise ValueError(f"Invalid JWT type [{jwt_type}] must be one of {str(valid)}") + + return self + + +class AcmeIssuers(BaseModel, extra="forbid"): + name: str = "" + uri: str = "" + account_key: Optional[str] = "" + contact: Optional[str] = "" + ssl_trusted_certificate: Optional[str] = "" + ssl_verify: Optional[bool] = False + state_path: Optional[str] = "" + accept_terms_of_service: Optional[bool] = False + + +class AuthClientOIDC(BaseModel, extra="forbid"): + issuer: str = "" + client_id: str = "" + client_secret: str = "" + config_url: Optional[str] = "" + cookie_name: Optional[str] = "" + extra_auth_args: Optional[str] = "" + redirect_uri: Optional[str] = "/oidc_callback" + logout_uri: Optional[str] = "" + post_logout_uri: Optional[str] = "" + logout_token_hint: Optional[bool] = False + scope: Optional[str] = "openid" + session_store: Optional[str] = "" + session_timeout: Optional[str] = "8h" + ssl_crl: Optional[str] = "" + ssl_trusted_certificate: Optional[str] = "" + userinfo: Optional[bool] = False + + +class AuthServerToken(BaseModel, extra="forbid"): + token: str = "" + type: Optional[str] = "" + location: Optional[str] = "" + username: Optional[str] = "" + password: Optional[str] = "" + + @model_validator(mode='after') + def check_type(self) -> 'AuthServerToken': + 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 = "" + + +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] = "/" + interval: Optional[int] = 5 + fails: Optional[int] = 1 + passes: Optional[int] = 1 + + +class AppProtectLog(BaseModel, extra="forbid"): + enabled: Optional[bool] = False + profile_name: Optional[str] = "" + destination: Optional[str] = "" + + +class AppProtect(BaseModel, extra="forbid"): + enabled: Optional[bool] = False + policy: str = "" + log: AppProtectLog = {} + + +class Location(BaseModel, extra="forbid"): + uri: str + urimatch: Optional[str] = "prefix" + upstream: Optional[str] = "" + log: Optional[Log] = {} + apigateway: Optional[APIGateway] = {} + caching: Optional[str] = "" + rate_limit: Optional[RateLimit] = {} + health_check: Optional[HealthCheck] = {} + app_protect: Optional[AppProtect] = {} + snippet: Optional[ObjectFromSourceOfTruth] = {} + authentication: Optional[LocationAuth] = {} + authorization: Optional[AuthorizationProfileReference] = {} + headers: Optional[LocationHeaders] = {} + njs: Optional[List[NjsHookLocation]] = [] + cache: Optional[CacheItem] = {} + + @model_validator(mode='after') + def check_type(self) -> 'Location': + urimatch = self.urimatch + upstream = self.upstream + + valid = ['prefix', 'exact', 'regex', 'iregex', 'best'] + if urimatch not in valid: + raise ValueError(f"Invalid URI match type [{urimatch}] must be one of {str(valid)}") + + prefixes = ["http://", "https://"] + if upstream != "" and not upstream.lower().startswith(tuple(prefixes)): + raise ValueError(f"Upstream must start with one of {str(prefixes)}") + + return self + + +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]] = [] + resolver: Optional[str] = "" + listen: Optional[Listen] = {} + log: Optional[Log] = {} + locations: Optional[List[Location]] = [] + app_protect: Optional[AppProtect] = {} + snippet: Optional[ObjectFromSourceOfTruth] = {} + headers: Optional[LocationHeaders] = {} + njs: Optional[List[NjsHookHttpServer]] = [] + authentication: Optional[LocationAuth] = {} + authorization: Optional[AuthorizationProfileReference] = {} + cache: Optional[CacheItem] = {} + + @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"): + name: str + resolver: Optional[str] = "" + listen: Optional[ListenL4] = {} + 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 = "" + expires: Optional[str] = "" + domain: Optional[str] = "" + path: Optional[str] = "" + + +class Origin(BaseModel, extra="forbid"): + server: str + weight: Optional[int] = 1 + max_fails: Optional[int] = 1 + fail_timeout: Optional[str] = "10s" + max_conns: Optional[int] = 0 + slow_start: Optional[str] = "0" + backup: Optional[bool] = False + + +class L4Origin(BaseModel, extra="forbid"): + server: str + weight: Optional[int] = 1 + max_fails: Optional[int] = 1 + fail_timeout: Optional[str] = "10s" + max_conns: Optional[int] = 0 + slow_start: Optional[str] = "0" + backup: Optional[bool] = False + + +class Upstream(BaseModel, extra="forbid"): + name: str + resolver: Optional[str] = "" + origin: Optional[List[Origin]] = [] + 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 + resolver: Optional[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] + ttl: Optional[str] = 60 + + +class CachingItem(BaseModel, extra="forbid"): + name: str + key: str + 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 + key: str + 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 + listen: Optional[str] = "" + allow_acl: Optional[str] = "" + + +class MapEntry(BaseModel, extra="forbid"): + key: str + keymatch: str + value: str + + @model_validator(mode='after') + def check_type(self) -> 'MapEntry': + keymatch = self.keymatch + + valid = ['exact', 'regex', 'iregex'] + if keymatch not in valid: + raise ValueError(f"Invalid key match type [{keymatch}] must be one of {str(valid)}") + + return self + + +class Map(BaseModel, extra="forbid"): + match: str + variable: str + entries: Optional[List[MapEntry]] = [] + + +class Layer4(BaseModel, extra="forbid"): + servers: Optional[List[L4Server]] = [] + upstreams: Optional[List[L4Upstream]] = [] + certificates: Optional[List[TLSCertificate]] = [] + logformats: Optional[List[L4LogFormat]] = [] + + +class Resolver(BaseModel, extra="forbid"): + name: str + address: str + valid: Optional[str] = "" + ipv4: bool = True + ipv6: bool = True + timeout: str = "30s" + + @model_validator(mode='after') + def check_type(self) -> 'Resolver': + name = self.name + + if not re.search(alphanumRegexp,name): + raise ValueError(f"Invalid resolver name [{name}] should match regexp {alphanumRegexp}") + + return self + +class L4LogFormat(BaseModel, extra="forbid"): + name: str + escape: str = "default" + format: str + + @model_validator(mode='after') + def check_type(self) -> 'L4LogFormat': + escape = self.escape + + valid = ['default', 'json', 'none'] + if escape not in valid: + raise ValueError(f"Invalid escape mode [{escape}] must be one of {str(valid)}") + + return self + + +class HttpLogFormat(BaseModel, extra="forbid"): + name: str + escape: str = "default" + format: str + + @model_validator(mode='after') + def check_type(self) -> 'HttpLogFormat': + escape = self.escape + + valid = ['default', 'json', 'none'] + if escape not in valid: + raise ValueError(f"Invalid escape mode [{escape}] must be one of {str(valid)}") + + return self + + +class CacheProfile(BaseModel, extra="forbid"): + name: str + basepath: Optional[str] = "/tmp" + size: Optional[str] = "10m" + ttl: Optional[str] = "10m" + max_size: Optional[str] = "" + min_free: Optional[str] = "" + + @model_validator(mode='after') + def check_type(self) -> 'CacheProfile': + name = self.name + + if not re.search(alphanumRegexp,name): + raise ValueError(f"Invalid cache name [{name}] should match regexp {alphanumRegexp}") + + return self + + +class CacheObjectTTL(BaseModel, extra="forbid"): + code: str = "any" + ttl: str = "10m" + + @model_validator(mode='after') + def check_type(self) -> 'CacheObjectTTL': + code = self.code + + if (code.isdigit() and (int(code) < 100 or int(code) >= 600)) or (not code.isdigit() and code!="any"): + raise ValueError(f"Invalid cache HTTP code [{code}] should be an integer between 100 and 599 or 'any'") + + return self + + +class CacheItem(BaseModel, extra="forbid"): + profile: Optional[str] = "" + key: Optional[str] = "$scheme$proxy_host$request_uri"; + validity: Optional[List[CacheObjectTTL]] = [] + + @model_validator(mode='after') + def check_type(self) -> 'CacheItem': + profile = self.profile + + if not re.search(alphanumRegexp,profile) and profile != "": + raise ValueError(f"Invalid cache item [{profile}] should match regexp {alphanumRegexp}") + + return self + + +class Authentication_Client(BaseModel, extra="forbid"): + name: str + type: str + + jwt: Optional[AuthClientJWT] = {} + mtls: Optional[AuthClientMtls] = {} + oidc: Optional[AuthClientOIDC] = {} + + @model_validator(mode='after') + def check_type(self) -> 'Authentication_Client': + _type, name = self.type, self.name + + valid = ['jwt', 'mtls', 'oidc'] + 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 + + +class Authentication_Server(BaseModel, extra="forbid"): + name: str + 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', '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 + + +class Authentication(BaseModel, extra="forbid"): + client: Optional[List[Authentication_Client]] = [] + 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]] = [] + caching: Optional[List[CachingItem]] = [] + rate_limit: Optional[List[RateLimitItem]] = [] + nginx_plus_api: Optional[NginxPlusApi] = {} + maps: Optional[List[Map]] = [] + snippet: Optional[ObjectFromSourceOfTruth] = {} + authentication: Optional[Authentication] = {} + authorization: Optional[List[Authorization]] = [] + njs: Optional[List[NjsHookHttpServer]] = [] + njs_profiles: Optional[List[NjsFile]] = [] + cache: Optional[List[CacheProfile]] = [] + logformats: Optional[List[HttpLogFormat]] = [] + resolver: Optional[str] = "" + acme_issuers: Optional[List[AcmeIssuers]] = [] + certificates: Optional[List[TLSCertificate]] = [] + policies: Optional[List[NGINXPolicy]] = [] + log_profiles: Optional[List[LogProfile]] = [] + + +class Declaration(BaseModel, extra="forbid"): + layer4: Optional[Layer4] = {} + http: Optional[Http] = {} + resolvers: Optional[List[Resolver]] = [] + + +class API_Gateway(BaseModel, extra="forbid"): + enabled: Optional[bool] = False + strip_uri: Optional[bool] = False + server_url: Optional[str] = "" + + +class DevPortal_Redocly(BaseModel, extra="forbid"): + uri: Optional[str] = "/devportal.html" + + +class DevPortal_Backstage(BaseModel, extra="forbid"): + name: str = "" + lifecycle: Optional[str] = "production" + owner: str = "" + system: Optional[str] = "" + + @model_validator(mode='after') + def check_type(self) -> 'DevPortal_Backstage': + _lifecycle = self.lifecycle + + valid = ['experimental', 'production', 'deprecated'] + if _lifecycle not in valid: + raise ValueError(f"Invalid developer portal type [{_lifecycle}] must be one of {str(valid)}") + + return self + + +class DeveloperPortal(BaseModel, extra="forbid"): + enabled: Optional[bool] = False + type: str = "" + redocly: Optional[DevPortal_Redocly] = {} + backstage: Optional[DevPortal_Backstage] = {} + + @model_validator(mode='after') + def check_type(self) -> 'DeveloperPortal': + _enabled, _type, _redocly, _backstage = self.enabled, self.type, self.redocly, self.backstage + + valid = ['redocly', 'backstage'] + + if _enabled == True and _type not in valid: + raise ValueError(f"Invalid developer portal type [{_type}] must be one of {str(valid)}") + + isError = False + + if _type == 'redocly' and not _redocly: + isError = True + + if _type == 'backstage' and not _backstage: + isError = True + + if isError: + raise ValueError(f"Missing developer portal data for type [{_type}]") + + return self + + +class Visibility_Moesif(BaseModel, extra="forbid"): + application_id: str = "" + plugin_path: Optional[str] = "/usr/local/share/lua/5.1/resty/moesif" + + +class Visibility(BaseModel, extra="forbid"): + enabled: Optional[bool] = False + type: str = "" + moesif: Optional[Visibility_Moesif] = {} + + @model_validator(mode='after') + def check_type(self) -> 'Visibility': + _enabled, _type, _moesif = self.enabled, self.type, self.moesif + + valid = ['moesif'] + + if _enabled == True and _type not in valid: + raise ValueError(f"Invalid visibility type [{_type}] must be one of {str(valid)}") + + isError = False + + if _type == 'moesif' and not _moesif: + isError = True + + if isError: + raise ValueError(f"Missing visibility data for type [{_type}]") + + return self + +class APIGateway(BaseModel, extra="forbid"): + openapi_schema: Optional[ObjectFromSourceOfTruth] = {} + api_gateway: Optional[API_Gateway] = {} + developer_portal: Optional[DeveloperPortal] = {} + visibility: Optional[List[Visibility]] = [] + rate_limit: Optional[List[RateLimitApiGw]] = [] + authentication: Optional[APIGatewayAuthentication] = {} + authorization: Optional[List[APIGatewayAuthorization]] = [] + cache: Optional[List[APIGatewayCache]] = [] + log: Optional[Log] = {} + + +class ConfigDeclaration(BaseModel, extra="forbid"): + output: Output + declaration: Optional[Declaration] = {} diff --git a/src/v5_6/APIGateway.py b/src/v5_6/APIGateway.py new file mode 100644 index 00000000..502826fd --- /dev/null +++ b/src/v5_6/APIGateway.py @@ -0,0 +1,40 @@ +""" +API Gateway support functions +""" + +import json + +import v5_6.GitOps +import v5_6.MiscUtils +from v5_6.OpenAPIParser import OpenAPIParser + +# pydantic models +from V5_6_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_6.GitOps.getObjectFromRepo(object=locationDeclaration['apigateway']['openapi_schema'], + authProfiles = authProfiles['server'] if 'server' in authProfiles else {}, base64Encode=False) + + if status != 200: + return status,"","" + + if v5_6.MiscUtils.yaml_or_json(apiSchemaString['content']) == 'yaml': + # YAML to JSON conversion + apiSchemaString['content'] = v5_6.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, apiSchemaString['content'] \ No newline at end of file diff --git a/src/v5_6/Asynchronous.py b/src/v5_6/Asynchronous.py new file mode 100644 index 00000000..12225696 --- /dev/null +++ b/src/v5_6/Asynchronous.py @@ -0,0 +1,36 @@ +"""" +Asynchronous declarations support +""" +import json +import pickle + +import v5_6.MiscUtils +from NcgRedis import NcgRedis + +# pydantic models +from V5_6_NginxConfigDeclaration import ConfigDeclaration + +# +# Check if the incoming request is asynchronous +# +def checkIfAsynch(declaration: ConfigDeclaration, method: str, apiVersion: str, configUid: str): + djson = declaration.model_dump() + + if djson['output']['synchronous']: + # Synchronous declaration, normal processing + return None, None + + # Asynchronous declaration, submit to FIFO queue + submissionUid = str(v5_6.MiscUtils.getuniqueid()) + submissionPayload = {'declaration': declaration, 'method': method, 'configUid': configUid, "apiVersion": apiVersion, "submissionUid": submissionUid} + NcgRedis.asyncQueue.put(submissionPayload) + + response = {} + response['code'] = 202 + response['message'] = f'Declaration submitted' + response['configUid'] = configUid + response['submissionUid'] = submissionUid + + NcgRedis.redis.set(f'ncg.async.submission.{submissionUid}', json.dumps(response)) + + return 202, response \ No newline at end of file diff --git a/src/v5_6/DeclarationPatcher.py b/src/v5_6/DeclarationPatcher.py new file mode 100644 index 00000000..d5b6b593 --- /dev/null +++ b/src/v5_6/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 'declaration' not in sourceDeclaration: + return sourceDeclaration + + if 'http' not in sourceDeclaration['declaration']: + return sourceDeclaration + + if 'policies' not in sourceDeclaration['declaration']['http']: + return sourceDeclaration + + # NGINX App Protect WAF policies patch + for p in sourceDeclaration['declaration']['http']['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['declaration']['http']['policies'] = allTargetPolicies + + return sourceDeclaration + + +# Returns the patched declaration based on patchedCertificates +def patchCertificates(sourceDeclaration: dict, patchedCertificates: dict): + allTargetCertificates = [] + + haveWePatched = False + + if 'declaration' not in sourceDeclaration: + return sourceDeclaration + + if 'http' not in sourceDeclaration['declaration']: + return sourceDeclaration + + if 'certificates' not in sourceDeclaration['declaration']['http']: + return sourceDeclaration + + # TLS certificates patch + for c in sourceDeclaration['declaration']['http']['certificates']: + if 'type' in c and c['type'] in ['certificate', 'key'] \ + 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, '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 being patched is a new one, let's add it + allTargetCertificates.append(patchedCertificates) + + sourceDeclaration['declaration']['http']['certificates'] = allTargetCertificates + + return sourceDeclaration diff --git a/src/v5_6/DevPortal.py b/src/v5_6/DevPortal.py new file mode 100644 index 00000000..178c7f65 --- /dev/null +++ b/src/v5_6/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_6.GitOps +import v5_6.MiscUtils + +# pydantic models +from V5_6_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_6.GitOps.getObjectFromRepo( + object = locationDeclaration['apigateway']['openapi_schema'], authProfiles = authProfiles['server'] if 'server' in authProfiles else {}, base64Encode = False) + + if v5_6.MiscUtils.yaml_or_json(apiSchemaString['content']) == 'yaml': + # YAML to JSON conversion + status, devportalJSON = buildDevPortal(openapischema = v5_6.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/v5_6/GitOps.py b/src/v5_6/GitOps.py new file mode 100644 index 00000000..0bb1f693 --- /dev/null +++ b/src/v5_6/GitOps.py @@ -0,0 +1,83 @@ +""" +GitOps support functions +""" + +import base64 +import requests + +from requests import ReadTimeout, HTTPError, Timeout, ConnectionError, ConnectTimeout + +import v5_6.MiscUtils + +# pydantic models +from V5_6_NginxConfigDeclaration import * + + +# Fetches a URL content +def __fetchfromsourceoftruth__(url, headers = {} ): + # Object is fetched from external repository + + try: + reply = requests.get(url = url, headers = headers, verify=False) + except (ConnectTimeout, HTTPError, ReadTimeout, Timeout, ConnectionError): + return 408, "URL " + url + " unreachable" + + return reply.status_code, reply.text + + +# If content starts with http(s):// fetches the object and return it b64-encoded by default. +# base64Encode to be set to False to disable b64 encoding +# Returns the status original content otherwise. +# Return is a tuple: status_code, content +def getObjectFromRepo(object: ObjectFromSourceOfTruth, authProfiles: Authentication={}, base64Encode: bool=True): + status_code = 200 + response = object + + if object: + if object['content'].lower().startswith(("http://","https://")): + # Object is fetched from external repository + headers = {} + + # Set server authentication if needed + 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': + + authToken = authP['token']['token'] + authTokenType = authP['token']['type'] + + 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) + + if status_code == 200: + if base64Encode == True: + fetchedContent = base64.b64encode(bytes(fetchedContent, 'utf-8')).decode('utf-8') + else: + fetchedContent = bytes(fetchedContent, 'utf-8').decode("utf-8") + else: + fetchedContent = f"Error fetching {object['content']}" + + response['content'] = fetchedContent + + else: + # Object is specified directly into the JSON payload, perform base64 decoding if needed + if not base64Encode: + if v5_6.MiscUtils.isBase64(object['content']): + response['content'] = base64.b64decode(object['content']).decode(); + else: + response['content'] = object['content'] + + return status_code, response \ No newline at end of file diff --git a/src/v5_6/MiscUtils.py b/src/v5_6/MiscUtils.py new file mode 100644 index 00000000..294b3a8f --- /dev/null +++ b/src/v5_6/MiscUtils.py @@ -0,0 +1,67 @@ +""" +Support functions +""" + +import re +import json +import yaml +import uuid +import socket +import base64 + + +# Searches for a nested key in a dictionary and returns its value, or None if nothing was found. +# key_lookup must be a string where each key is deparated by a given "separator" character, which by default is a dot +def getDictKey(_dict: dict, key_lookup: str, separator='.'): + keys = key_lookup.split(separator) + subdict = _dict + + for k in keys: + subdict = subdict[k] if k in subdict else None + if subdict is None: + return None + + return subdict + +# Jinja2 regexp filter +def regex_replace(s, find, replace): + return re.sub(find, replace, s) + +# JSON/YAML detection +def yaml_or_json(document: str): + try: + json.load(document) + return 'json' + except Exception: + return 'yaml' + +# YAML to JSON conversion +def yaml_to_json(document: str): + return json.dumps(yaml.load(document, Loader=yaml.BaseLoader)) + + +# JSON TO YAML conversion +def json_to_yaml(document: str): + return yaml.dump(json.loads(document)) + + +# Returns a unique ID +def getuniqueid(): + return uuid.uuid4() + + +# Test DNS resolution +# Returns {True,IP address} if successful and {False,error description} for NXDOMAIN/if DNS resolution failed +def resolveFQDN(fqdn:str): + try: + return True,socket.gethostbyname(fqdn) + except Exception as e: + return False,e + + +# Check for base64 encoding, return True if s is base64-encoded, False otherwise +def isBase64(s): + try: + return base64.b64encode(base64.b64decode(s)) == bytes(s,"utf-8") + except Exception: + return False \ No newline at end of file diff --git a/src/v5_6/NGINXOneNAPUtils.py b/src/v5_6/NGINXOneNAPUtils.py new file mode 100644 index 00000000..45d9e254 --- /dev/null +++ b/src/v5_6/NGINXOneNAPUtils.py @@ -0,0 +1,256 @@ +""" +NGINX App Protect support functions +""" + +import requests +import json +import base64 + +import v5_6.GitOps + +from NcgConfig import NcgConfig + +from fastapi.responses import Response, JSONResponse + +available_log_profiles = ['log_all', 'log_blocked', 'log_illegal', 'secops_dashboard'] + + +# Define (create/update) a NGINX App Protect policy on NMS. +# If policyUid is not empty a the policy update is performed +# Returns a tuple {status_code,text}. status_code is 201 if successful +def __definePolicyOnNGINXOne__(nginxOneUrl: str, nginxOneToken: str, nginxOneNamespace: str, policyJson: str): + policyName = json.loads(policyJson)['policy']['name'] + + # Payload for NGINX One Console + # policyBody holds the base64-encoded policy JSON definition + # Control plane-compiled policy bundles are supported. Create the NGINX App Protect policy on NGINX One Console + # POST {nginxOneUrl}/api/nginx/one/namespaces/{nginxOneNamespace}/app-protect/policies + # { + # "policy": "" + # } + policyCreationPayload = {} + policyCreationPayload['policy'] = base64.b64encode(bytes(policyJson, 'utf-8')).decode('utf-8') + + # Retrieve the full policy list from NGINX One Console + allExistingPolicies = __getAllPolicies__(nginxOneUrl = nginxOneUrl, nginxOneToken = nginxOneToken, nginxOneNamespace=nginxOneNamespace) + polId = __getPolicyId__(json.loads(allExistingPolicies.text), policyName) + + if polId != "": + # This is a new version for an existing policy + r = requests.put(url=f"{nginxOneUrl}/api/nginx/one/namespaces/{nginxOneNamespace}/app-protect/policies/{polId}", + data=json.dumps(policyCreationPayload), + headers={'Content-Type': 'application/json', + "Authorization": f"Bearer APIToken {nginxOneToken}"}, + verify=False) + else: + # New policy creation + r = requests.post(url=f"{nginxOneUrl}/api/nginx/one/namespaces/{nginxOneNamespace}/app-protect/policies", + data=json.dumps(policyCreationPayload), + headers={'Content-Type': 'application/json', "Authorization": f"Bearer APIToken {nginxOneToken}"}, + verify=False) + + return r + + +# Retrieve security policies information +def __getAllPolicies__(nginxOneUrl: str, nginxOneToken: str, nginxOneNamespace: str): + return requests.get(url=f"{nginxOneUrl}/api/nginx/one/namespaces/{nginxOneNamespace}/app-protect/policies?paginated=false", + headers={"Authorization": f"Bearer APIToken {nginxOneToken}"}, verify=False) + + +# Return the policy ID for the given policyName. allPoliciesJSON is the JSON output from __getAllPolicies__ +def __getPolicyId__(allPoliciesJSON: dict, policyName: str): + if 'items' in allPoliciesJSON: + for p in allPoliciesJSON['items']: + if policyName == p['name']: + return p['object_id'] + + return "" + + +# Delete security policies from control plane +def __deletePolicy__(nginxOneUrl: str, nginxOneToken: str, nginxOneNamespace: str, policyUids: list): + jsonPayload = [] + + for polId in policyUids: + item = {} + item['object_id'] = polId + item['action'] = "delete" + jsonPayload.append(item) + + return requests.patch(url=f'{nginxOneUrl}/api/nginx/one/namespaces/{nginxOneNamespace}/app-protect/policies', + headers={"Content-Type": "application/json", "Authorization": f"Bearer APIToken {nginxOneToken}"}, verify=False, + data=json.dumps(jsonPayload)) + + +# Check NAP policies names validity for the given declaration +# Return a tuple: status, description. If status = 200 checks were successful +def checkDeclarationPolicies(declaration: dict): + # NGINX App Protect policies check - duplicated policy names + + # all policy names as defined in the declaration + # { 'policyName': 'activeTag', ... } + allPolicyNames = {} + + if 'policies' not in declaration['output']['nginxone']: + return 200, "" + + for policy in declaration['output']['nginxone']['policies']: + # print(f"Found NAP Policy [{policy['name']}] active tag [{policy['active_tag']}]") + + if policy['name'] and policy['name'] in allPolicyNames: + return 422, f"Duplicated NGINX App Protect WAF policy [{policy['name']}]" + + allPolicyNames[policy['name']] = policy['active_tag'] + + # Check policy releases for non-univoque tags + allPolicyVersionTags = {} + for policyVersion in policy['versions']: + if policyVersion['tag'] and policyVersion['tag'] in allPolicyVersionTags: + return 422, f"Duplicated NGINX App Protect WAF policy tag [{policyVersion['tag']}] " \ + f"for policy [{policy['name']}]" + + allPolicyVersionTags[policyVersion['tag']] = "found" + + if policy['active_tag'] and policy['active_tag'] not in allPolicyVersionTags: + return 422, f"Invalid active tag [{policy['active_tag']}] for policy [{policy['name']}]" + + # Check policy names referenced by the declaration inside HTTP servers[]: they must be valid + if 'http' in declaration['declaration'] and 'servers' in declaration['declaration']['http']: + for httpServer in declaration['declaration']['http']['servers']: + if 'app_protect' in httpServer: + if 'policy' in httpServer['app_protect'] and httpServer['app_protect']['policy'] \ + and httpServer['app_protect']['policy'] not in allPolicyNames: + return 422, f"Unknown NGINX App Protect WAF policy [{httpServer['app_protect']['policy']}] " \ + f"referenced by HTTP server [{httpServer['name']}]" + + if 'log' in httpServer['app_protect'] \ + and 'profile_name' in httpServer['app_protect']['log'] \ + and httpServer['app_protect']['log']['profile_name'] \ + and httpServer['app_protect']['log']['profile_name'] \ + not in available_log_profiles: + return 422, f"Invalid NGINX App Protect WAF log profile " \ + f"[{httpServer['app_protect']['log']['profile_name']}] referenced by HTTP server " \ + f"[{httpServer['name']}]" + + # Check policy names referenced in HTTP servers[].locations[] + for location in httpServer['locations']: + if 'app_protect' in location: + if 'policy' in location['app_protect'] and location['app_protect']['policy'] \ + and location['app_protect']['policy'] not in allPolicyNames: + return 422, f"Unknown NGINX App Protect WAF policy [{location['app_protect']['policy']}] " \ + f"referenced by HTTP server [{httpServer['name']}] location [{location['uri']}]" + + if 'log' in httpServer['app_protect'] and httpServer['app_protect']['log'] \ + and httpServer['app_protect']['log']['profile_name'] \ + and httpServer['app_protect']['log']['profile_name'] \ + not in available_log_profiles: + return 422, f"Invalid NGINX App Protect WAF log profile " \ + f"[{httpServer['app_protect']['log']['profile_name']}] referenced by HTTP server " \ + f"[{httpServer['name']}] location [{location['uri']}]" + + return 200, "" + + +# For the given declaration creates/updates NGINX App Protect WAF policies on NGINX Instance Manager +# making sure that they are in sync with what is defined in the JSON declaration +# Returns a JSON with status code and content +def provisionPolicies(nginxOneUrl: str, nginxOneToken: str, nginxOneNamespace: str, declaration: dict): + # NGINX App Protect policies - each policy supports multiple tagged versions + + # Policy names and all tag/uid pairs + # {'prod-policy': [{'tag': 'v1', 'uid': 'ebcf9c7e-0930-450d-8108-7cad30e59661'}, + # {'tag': 'v2', 'uid': 'd18c2eb7-814e-4e4d-90fc-54014eef199e'}], + # 'staging-policy': [{'tag': 'block', 'uid': '9794faa7-5b6c-4ce5-9e68-946f04766bb4'}, + # {'tag': 'xss-ok', 'uid': '7b4b850a-ff9e-42a0-85d0-850171474224'}]} + all_policy_names_and_versions = {} + + # Policy names and active tag uids + # { 'prod-policy': 'ebcf9c7e-0930-450d-8108-7cad30e59661', + # 'staging-policy': '7b4b850a-ff9e-42a0-85d0-850171474224' } + all_policy_active_names_and_uids = {} + + for p in declaration['output']['nginxone']['policies']: + policy_name = p['name'] + if policy_name: + policy_active_tag = p['active_tag'] + + # Iterates over all NGINX App Protect policies + if p['type'] == 'app_protect': + # Iterates over all policy versions + + # Remove pre-existing policy versions + allPoliciesJSON = __getAllPolicies__(nginxOneUrl=nginxOneUrl, nginxOneToken=nginxOneToken, nginxOneNamespace=nginxOneNamespace) + polId = __getPolicyId__(allPoliciesJSON = json.loads(allPoliciesJSON.text), policyName=policy_name) + if polId != "": + __deletePolicy__(nginxOneUrl=nginxOneUrl, nginxOneToken=nginxOneToken, nginxOneNamespace=nginxOneNamespace, policyUids=[polId]) + + # Create all policy versions + for policyVersion in p['versions']: + status, policyBody = v5_6.GitOps.getObjectFromRepo(policyVersion['contents'],base64Encode=False) + + if status != 200: + return JSONResponse( + status_code=422, + content={"code": status, + "details": policyBody['content']} + ) + + # Create the NGINX App Protect policy on NGINX One Console + r = __definePolicyOnNGINXOne__( + nginxOneUrl=nginxOneUrl, nginxOneToken=nginxOneToken, nginxOneNamespace=nginxOneNamespace, + policyJson=policyBody['content'] + ) + + # Check for errors creating NGINX App Protect policy + if r.status_code != 201: + return JSONResponse( + status_code=r.status_code, + content={"code": r.status_code, "details": json.loads(r.text)} + ) + else: + # Policy was created, retrieve metadata.uid for each policy version + if policy_name not in all_policy_names_and_versions: + all_policy_names_and_versions[policy_name] = [] + + # Stores the policy version + uid = json.loads(r.text)['latest']['object_id'] + tag = policyVersion['tag'] + + if policy_active_tag == tag: + all_policy_active_names_and_uids[policy_name] = uid + + all_policy_names_and_versions[policy_name].append({'tag': tag, 'uid': uid}) + + return JSONResponse(status_code=200, content={"all_policy_names_and_versions": all_policy_names_and_versions, + "all_policy_active_names_and_uids": all_policy_active_names_and_uids}) + + +# Publish a NGINX App Protect WAF policy making it active +# activePolicyUids is a dict { "policy_name": "active_uid", [...] } +# Return True if at least one policy was enabled, False otherwise +def makePolicyActive(nginxOneUrl: str, nginxOneToken: str, nginxOneNamespace: str, activePolicyUids: dict, instanceGroupUid: str): + doWeHavePolicies = False + + for policyName in activePolicyUids: + body = { + "publications": [ + { + "policyContent": { + "name": f'{policyName}', + "uid": f'{activePolicyUids[policyName]}' + }, + "instanceGroups": [ + f'{instanceGroupUid}' + ] + } + ] + } + + doWeHavePolicies = True + r = requests.post(url=f'{nginxOneUrl}/api/platform/v1/security/publish', + data=json.dumps(body), + headers={'Content-Type': 'application/json', "Authorization": f"Bearer APIToken {nginxOneToken}"}, + verify=False) + + return doWeHavePolicies \ No newline at end of file diff --git a/src/v5_6/NGINXOneOutput.py b/src/v5_6/NGINXOneOutput.py new file mode 100644 index 00000000..82a854bd --- /dev/null +++ b/src/v5_6/NGINXOneOutput.py @@ -0,0 +1,379 @@ +""" +Output to NGINX One console +""" + +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_6_CreateConfig + +import v5_6.APIGateway +import v5_6.DevPortal +import v5_6.DeclarationPatcher +import v5_6.GitOps +import v5_6.MiscUtils +import v5_6.NGINXOneUtils + +# pydantic models +from V5_6_NginxConfigDeclaration import * + +# NGINX App Protect helper functions +# NGINX App Protect helper functions +import v5_6.NGINXOneNAPUtils + +# NGINX Declarative API modules +from NcgConfig import NcgConfig +from NcgRedis import NcgRedis + +def NGINXOneOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpConf: str, + b64StreamConf: str,configFiles = {}, auxFiles = {}, + runfromautosync: bool = False, + configUid: str = ""): + # NGINX One Console Staged Configuration publish + + nOneToken = v5_6.MiscUtils.getDictKey(d, 'output.nginxone.token') + nOneConfigSyncGroup = v5_6.MiscUtils.getDictKey(d, 'output.nginxone.configsyncgroup') + nOneNamespace = v5_6.MiscUtils.getDictKey(d, 'output.nginxone.namespace') + + nOneSynctime = v5_6.MiscUtils.getDictKey(d, 'output.nginxone.synctime') + + nOneUrlFromJson = v5_6.MiscUtils.getDictKey(d, 'output.nginxone.url') + urlCheck = urlparse(nOneUrlFromJson) + + 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 One URL {nOneUrlFromJson}"}}, + "headers": {'Content-Type': 'application/json'}} + + # DNS resolution check + dnsOutcome, dnsReply = v5_6.MiscUtils.resolveFQDN(urlCheck.netloc) + if not dnsOutcome: + return {"status_code": 400, + "message": {"status_code": 400, "message": {"code": 400, + "content": f"DNS resolution failed for {urlCheck.netloc}: {dnsReply}"}}, + "headers": {'Content-Type': 'application/json'}} + + nOneUrl = f"{urlCheck.scheme}://{urlCheck.netloc}" + + if nOneSynctime < 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_6.MiscUtils.getDictKey(d, 'output.nginxone.policies') + if d_policies is not None: + for policy in d_policies: + if 'versions' in policy: + for policyVersion in policy['versions']: + status, content = v5_6.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_6.MiscUtils.getDictKey(d, 'output.nginxone.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 + + # TLS certificates and key names validity checks for servers + d_servers = v5_6.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_6.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']) + "] must be one of [" + ",".join(all_tls['certificate']) + "]"} + }} + + cert_key = v5_6.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']) + "] must be one of [" + ",".join(all_tls['key']) + "]"} + }} + + trusted_cert_name = v5_6.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']) + + "] must be one of [" + ",".join(all_tls['certificate']) + "]"} + }} + + # TLS certificates and key names validity checks or ACME issuer profiles + d_acmeissuers = v5_6.MiscUtils.getDictKey(d, 'declaration.http.acme_issuers') + if d_acmeissuers is not None: + for issuer in d_acmeissuers: + cert_name = issuer['ssl_trusted_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 ACME issuer [" + str( + issuer['name']) +"] must be one of [" + ",".join(all_tls['certificate']) + "]"} + }} + + # Add optional certificates specified under output.nginxone.certificates + extensions_map = {'certificate': '.crt', 'key': '.key'} + + d_certificates = v5_6.MiscUtils.getDictKey(d, 'output.nginxone.certificates') + if d_certificates is not None: + for c in d_certificates: + status, certContent = v5_6.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.nginxone.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={'mainhttpfile': NcgConfig.config['nms']['staged_config_http_filename'], + 'mainstreamfile': NcgConfig.config['nms']['staged_config_stream_filename'], + 'modules': v5_6.MiscUtils.getDictKey(d, 'output.nginxone.modules'), + 'license': v5_6.MiscUtils.getDictKey(d, 'output.license')}, + d={'http': v5_6.MiscUtils.getDictKey(d, 'declaration.http')}) + + # Base64-encoded NGINX main configuration (/etc/nginx/nginx.conf) + b64NginxMain = str(base64.urlsafe_b64encode(nginxMainConf.encode("utf-8")), "utf-8") + + # NGINX License file + licenseJwtFile = j2_env.get_template(NcgConfig.config['templates']['license']).render( + nginxconf={'license': v5_6.MiscUtils.getDictKey(d, 'output.license')}) + + # Base64-encoded license file (/etc/nginx/license.jwt) + b64licenseJwtFile = str(base64.urlsafe_b64encode(licenseJwtFile.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'} + filesLicenseFile = {'contents': b64licenseJwtFile, 'name': NcgConfig.config['nms']['config_dir'] + '/license.jwt'} + 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) + + # If no R33+ license token was specified in the JSON declaration, it is assumed a token already exists + # on the NGINX instances and it won't be overwritten + if v5_6.MiscUtils.getDictKey(d, 'output.license.token') != "": + configFiles['files'].append(filesLicenseFile) + + # Staged config + baseStagedConfig = {'aux': [ { 'files': configFiles } ] } + stagedConfig = {'conf_path': NcgConfig.config['nms']['config_dir'] + '/nginx.conf', + 'configs': [ configFiles, auxFiles ]} + + 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 NGINX One needed + print( + f'Declaration [{configUid}] changed, publishing' if configUid else f'New declaration created, publishing') + + # Get the config sync group id nOneUrl: str, nOneTokenUsername: str, nameSpace: str, clusterName: str + returnCode, igUid = v5_6.NGINXOneUtils.getConfigSyncGroupId(nOneUrl = nOneUrl, nOneToken = nOneToken, + nameSpace = nOneNamespace, configSyncGroupName = nOneConfigSyncGroup) + + # Invalid config sync group + if returnCode != 200: + return {"status_code": 404, + "message": {"status_code": 404, "message": {"code": returnCode, + "content": igUid}}, + "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_6.NGINXOneNAPUtils.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 + ppReply = v5_6.NGINXOneNAPUtils.provisionPolicies( + nginxOneUrl = nOneUrl, nginxOneToken = nOneToken, nginxOneNamespace = nOneNamespace, declaration=d) + + if ppReply.status_code >= 400: + return {"status_code": ppReply.status_code, + "message": {"status_code": ppReply.status_code, "message": {"code": ppReply.status_code, "content": ppReply.content} }} + + napPolicies = json.loads(ppReply.body) + provisionedNapPolicies = napPolicies['all_policy_names_and_versions'] + activePolicyUids = napPolicies['all_policy_active_names_and_uids'] + + ### / NGINX App Protect policies support + + ### Publish staged config to config sync group + returnHttpCode = 422 + + r = requests.put(url=f'{nOneUrl}/api/nginx/one/namespaces/{nOneNamespace}/config-sync-groups/{igUid}/config', + data=json.dumps(stagedConfig), + headers={'Content-Type': 'application/json', "Authorization": f"Bearer APIToken {nOneToken}"}, + verify=False) + + if r.status_code not in [200, 202]: + # Configuration publish failed + return {"status_code": r.status_code, + "message": {"status_code": r.status_code, "message": r.text}, + "headers": {'Content-Type': 'application/json'}} + + if r.status_code == 202: + # Configuration has been submitted to NGINX One Console, fetch the deployment status - reply was HTTP/202 + publishResponse = json.loads(r.text) + publication_id = publishResponse['object_id'] + + # Wait for either NGINX One Cloud Console 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=f'{nOneUrl}/api/nginx/one/namespaces/{nOneNamespace}/config-sync-groups/{igUid}/publications/{publication_id}', + headers={"Authorization": f"Bearer APIToken {nOneToken}"}, + verify=False) + + checkJson = json.loads(deploymentCheck.text) + + if not checkJson['status'] == 'pending': + isPending = False + + if checkJson['status'] == "failed": + # Staged config publish to NGINX One failed + jsonResponse = checkJson['status_reasons'][0] + returnHttpCode = 422 + elif checkJson['status'] == "succeeded": + jsonResponse = { "message": "Config successfully applied", "status": checkJson['status'] } + returnHttpCode = 200 + + else: + # Staged config publish to NGINX One succeeded - reply was HTTP/200 + jsonResponse = json.loads(r.text) + returnHttpCode = 200 + + # if nmsSynctime > 0 and runfromautosync == False: + if runfromautosync == False: + # No configuration is found, generate one + configUid = str(v5_6.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_6.NGINXOneNAPUtils.makePolicyActive(nginxOneUrl=nOneUrl, + nginxOneToken=nOneToken, + nginxOneNamespace=nOneNamespace, + 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_6.NGINXOneNAPUtils.cleanPolicyLeftovers(nginxOneUrl=nOneUrl,nginxOneToken=nOneToken, + # nginxOneNamespace=nOneNamespace, + # currentPolicies=provisionedNapPolicies) + + # If deploying a new configuration in GitOps mode start autosync + if nOneSynctime == 0: + NcgRedis.declarationsList[configUid] = "static" + elif not runfromautosync: + # GitOps autosync + print(f'Starting autosync for configUid {configUid} every {nOneSynctime} seconds') + + job = schedule.every(nOneSynctime).seconds.do(lambda: v5_6_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': returnHttpCode, '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": returnHttpCode, + "message": {"status_code": returnHttpCode, + "message": responseContent}, + "headers": {'Content-Type': 'application/json'} + } \ No newline at end of file diff --git a/src/v5_6/NGINXOneUtils.py b/src/v5_6/NGINXOneUtils.py new file mode 100644 index 00000000..48c4a902 --- /dev/null +++ b/src/v5_6/NGINXOneUtils.py @@ -0,0 +1,32 @@ +""" +NGINX One support functions +""" + +import requests +import json + + +# Fetch a cluster ID from NGINX One +# Return None if not found +def getConfigSyncGroupId(nOneUrl: str, nOneToken: str, nameSpace: str, configSyncGroupName: str): + # Retrieve config sync group uid + cSyncGroup = requests.get(url=f'{nOneUrl}/api/nginx/one/namespaces/{nameSpace}/config-sync-groups?paginated=false', + verify=False, headers = {"Authorization": f"Bearer APIToken {nOneToken}"}) + + if cSyncGroup.status_code != 200: + if cSyncGroup.status_code == 401: + return cSyncGroup.status_code, "NGINX One authentication failed" + else: + return cSyncGroup.status_code, f"Error fetching config sync group uid: {cSyncGroup.text}" + + # Get the instance group id + igUid = None + igJson = json.loads(cSyncGroup.text) + for i in igJson['items']: + if i['name'] == configSyncGroupName: + igUid = i['object_id'] + + if igUid is None: + return 404, f"config sync group [{configSyncGroupName}] not found" + + return 200, igUid diff --git a/src/v5_6/NIMNAPUtils.py b/src/v5_6/NIMNAPUtils.py new file mode 100644 index 00000000..bb211e2d --- /dev/null +++ b/src/v5_6/NIMNAPUtils.py @@ -0,0 +1,276 @@ +""" +F5 WAF for NGINX support functions +""" + +import requests +import json +import base64 + +import v5_6.GitOps + +from NcgConfig import NcgConfig + +from fastapi.responses import Response, JSONResponse + +available_log_profiles = ['log_all', 'log_blocked', 'log_illegal', 'secops_dashboard'] + + +# Define (create/update) a F5 WAF for NGINX policy on NMS. +# If policyUid is not empty the policy update is performed +# Returns a tuple {status_code,text}. status_code is 201 if successful +def __definePolicyOnNMS__(nmsUrl: str, nmsUsername: str, nmsPassword: str, policyName: str, policyDisplayName: str, + policyDescription: str, policyJson: str, policyUid: str = ""): + # policyJson holds the base64-encoded policy JSON definition + # Control plane-compiled policy bundles are supported. Create the F5 WAF for NGINX policy on NGINX Instance Manager + # POST https://IP_ADDRESS/api/platform/v1/security/policies + # { + # "metadata": { + # "name": "prod-policy", + # "displayName": "Production Policy - blocking", + # "description": "Production-ready policy - blocking" + # }, + # "content": "" + # } + + policyCreationPayload = {'metadata': {}} + policyCreationPayload['metadata']['name'] = policyName + policyCreationPayload['metadata']['displayName'] = policyDisplayName + policyCreationPayload['metadata']['description'] = policyDescription + policyCreationPayload['content'] = policyJson + + if policyUid != "": + # Existing policy update + r = requests.put(url=f"{nmsUrl}/api/platform/v1/security/policies/{policyUid}", + data=json.dumps(policyCreationPayload), + headers={'Content-Type': 'application/json'}, + auth=(nmsUsername, nmsPassword), + verify=False) + else: + # New policy creation - first try to create it as a new revision for an existing policy + # The response code is 201 if successful and 404 if there is no policy with the given name + r = requests.post(url=f"{nmsUrl}/api/platform/v1/security/policies?isNewRevision=true", + data=json.dumps(policyCreationPayload), + headers={'Content-Type': 'application/json'}, + auth=(nmsUsername, nmsPassword), + verify=False) + + # Check if this is a new policy with no existing versions. If this is true create its initial version + if r.status_code == 404: + r = requests.post(url=f"{nmsUrl}/api/platform/v1/security/policies", + data=json.dumps(policyCreationPayload), + headers={'Content-Type': 'application/json'}, + auth=(nmsUsername, nmsPassword), + verify=False) + + return r + + +# Retrieve security policies information +def __getAllPolicies__(nmsUrl: str, nmsUsername: str, nmsPassword: str): + return requests.get(url=f'{nmsUrl}/api/platform/v1/security/policies', + auth=(nmsUsername, nmsPassword), verify=False) + + +# Delete security policy from control plane +def __deletePolicy__(nmsUrl: str, nmsUsername: str, nmsPassword: str, policyUid: str): + return requests.delete(url=f'{nmsUrl}/api/platform/v1/security/policies/{policyUid}', + auth=(nmsUsername, nmsPassword), verify=False) + + +# Check NAP policies names validity for the given declaration +# Return a tuple: status, description. If status = 200 checks were successful +def checkDeclarationPolicies(declaration: dict): + # F5 WAF for NGINX policies check - duplicated policy names + + # all policy names as defined in the declaration + # { 'policyName': 'activeTag', ... } + allPolicyNames = {} + + if 'http' not in declaration['declaration']: + return 200, "" + + if 'policies' not in declaration['declaration']['http']: + return 200, "" + + for policy in declaration['declaration']['http']['policies']: + # print(f"Found NAP Policy [{policy['name']}] active tag [{policy['active_tag']}]") + + if policy['name'] and policy['name'] in allPolicyNames: + return 422, f"Duplicated F5 WAF for NGINX WAF policy [{policy['name']}]" + + allPolicyNames[policy['name']] = policy['active_tag'] + + # Check policy releases for non-univoque tags + allPolicyVersionTags = {} + for policyVersion in policy['versions']: + if policyVersion['tag'] and policyVersion['tag'] in allPolicyVersionTags: + return 422, f"Duplicated F5 WAF for NGINX WAF policy tag [{policyVersion['tag']}] " \ + f"for policy [{policy['name']}]" + + allPolicyVersionTags[policyVersion['tag']] = "found" + + if policy['active_tag'] and policy['active_tag'] not in allPolicyVersionTags: + return 422, f"Invalid active tag [{policy['active_tag']}] for policy [{policy['name']}]" + + # Check policy names referenced by the declaration inside HTTP servers[]: they must be valid + if 'http' in declaration['declaration'] and 'servers' in declaration['declaration']['http']: + for httpServer in declaration['declaration']['http']['servers']: + if 'app_protect' in httpServer: + if 'policy' in httpServer['app_protect'] and httpServer['app_protect']['policy'] \ + and httpServer['app_protect']['policy'] not in allPolicyNames: + return 422, f"Unknown F5 WAF for NGINX WAF policy [{httpServer['app_protect']['policy']}] " \ + f"referenced by HTTP server [{httpServer['name']}]" + + if 'log' in httpServer['app_protect'] \ + and 'profile_name' in httpServer['app_protect']['log'] \ + and httpServer['app_protect']['log']['profile_name'] \ + and httpServer['app_protect']['log']['profile_name'] \ + not in available_log_profiles: + return 422, f"Invalid F5 WAF for NGINX WAF log profile " \ + f"[{httpServer['app_protect']['log']['profile_name']}] referenced by HTTP server " \ + f"[{httpServer['name']}]" + + # Check policy names referenced in HTTP servers[].locations[] + for location in httpServer['locations']: + if 'app_protect' in location: + if 'policy' in location['app_protect'] and location['app_protect']['policy'] \ + and location['app_protect']['policy'] not in allPolicyNames: + return 422, f"Unknown F5 WAF for NGINX WAF policy [{location['app_protect']['policy']}] " \ + f"referenced by HTTP server [{httpServer['name']}] location [{location['uri']}]" + + if 'log' in httpServer['app_protect'] and httpServer['app_protect']['log'] \ + and httpServer['app_protect']['log']['profile_name'] \ + and httpServer['app_protect']['log']['profile_name'] \ + not in available_log_profiles: + return 422, f"Invalid F5 WAF for NGINX WAF log profile " \ + f"[{httpServer['app_protect']['log']['profile_name']}] referenced by HTTP server " \ + f"[{httpServer['name']}] location [{location['uri']}]" + + return 200, "" + + +# For the given declaration creates/updates F5 WAF for NGINX WAF policies on NGINX Instance Manager +# making sure that they are in sync with what is defined in the JSON declaration +# Returns a JSON with status code and content +def provisionPolicies(nmsUrl: str, nmsUsername: str, nmsPassword: str, declaration: dict): + # F5 WAF for NGINX policies - each policy supports multiple tagged versions + + # Policy names and all tag/uid pairs + # {'prod-policy': [{'tag': 'v1', 'uid': 'ebcf9c7e-0930-450d-8108-7cad30e59661'}, + # {'tag': 'v2', 'uid': 'd18c2eb7-814e-4e4d-90fc-54014eef199e'}], + # 'staging-policy': [{'tag': 'block', 'uid': '9794faa7-5b6c-4ce5-9e68-946f04766bb4'}, + # {'tag': 'xss-ok', 'uid': '7b4b850a-ff9e-42a0-85d0-850171474224'}]} + all_policy_names_and_versions = {} + + # Policy names and active tag uids + # { 'prod-policy': 'ebcf9c7e-0930-450d-8108-7cad30e59661', + # 'staging-policy': '7b4b850a-ff9e-42a0-85d0-850171474224' } + all_policy_active_names_and_uids = {} + + if 'http' in declaration['declaration'] and 'policies' in declaration['declaration']['http']: + for p in declaration['declaration']['http']['policies']: + policy_name = p['name'] + if policy_name: + policy_active_tag = p['active_tag'] + + # Iterates over all F5 WAF for NGINX policies + if p['type'] == 'app_protect': + # Iterates over all policy versions + for policyVersion in p['versions']: + status, policyBody = v5_6.GitOps.getObjectFromRepo(policyVersion['contents']) + + if status != 200: + return JSONResponse( + status_code=422, + content={"code": status, + "details": policyBody['content']} + ) + + # Create the F5 WAF for NGINX policy on NMS + r = __definePolicyOnNMS__( + nmsUrl=nmsUrl, nmsUsername=nmsUsername, nmsPassword=nmsPassword, + policyName=policy_name, + policyDisplayName=policyVersion['displayName'], + policyDescription=policyVersion['description'], + policyJson=policyBody['content'] + ) + + # Check for errors creating F5 WAF for NGINX policy + if r.status_code != 201: + return JSONResponse( + status_code=r.status_code, + content={"code": r.status_code, "details": json.loads(r.text)} + ) + else: + # Policy was created, retrieve metadata.uid for each policy version + if policy_name not in all_policy_names_and_versions: + all_policy_names_and_versions[policy_name] = [] + + # Stores the policy version + uid = json.loads(r.text)['metadata']['uid'] + tag = policyVersion['tag'] + + if policy_active_tag == tag: + all_policy_active_names_and_uids[policy_name] = uid + + all_policy_names_and_versions[policy_name].append({'tag': tag, 'uid': uid}) + + return JSONResponse(status_code=200, content={"all_policy_names_and_versions": all_policy_names_and_versions, + "all_policy_active_names_and_uids": all_policy_active_names_and_uids}) + + +# Publish a F5 WAF for NGINX WAF policy making it active +# activePolicyUids is a dict { "policy_name": "active_uid", [...] } +# Return True if at least one policy was enabled, False otherwise +def makePolicyActive(nmsUrl: str, nmsUsername: str, nmsPassword: str, activePolicyUids: dict, instanceGroupUid: str): + doWeHavePolicies = False + + for policyName in activePolicyUids: + body = { + "publications": [ + { + "policyContent": { + "name": f'{policyName}', + "uid": f'{activePolicyUids[policyName]}' + }, + "instanceGroups": [ + f'{instanceGroupUid}' + ] + } + ] + } + + doWeHavePolicies = True + r = requests.post(url=f'{nmsUrl}/api/platform/v1/security/publish', auth=(nmsUsername, nmsPassword), + data=json.dumps(body), headers={'Content-Type': 'application/json'}, verify=False) + + return doWeHavePolicies + + +# For the given declaration creates/updates F5 WAF for NGINX WAF policies on NGINX Instance Manager +# making sure that they are in sync with what is defined in the JSON declaration +# Returns a tuple: status, response payload +def cleanPolicyLeftovers(nmsUrl: str, nmsUsername: str, nmsPassword: str, currentPolicies: dict): + # Fetch all policies currently defined on the control plane + allNMSPolicies = __getAllPolicies__(nmsUrl=nmsUrl, nmsUsername=nmsUsername, nmsPassword=nmsPassword) + allNMSPoliciesJson = json.loads(allNMSPolicies.text) + + # Build a list of all uids for policies currently available on the control plane whose names match + # currentPolicies (policies that have just been pushed to data plane) + allUidsOnNMS = [] + for p in allNMSPoliciesJson['items']: + if p['metadata']['name'] in currentPolicies: + allUidsOnNMS.append(p['metadata']['uid']) + + allCurrentPoliciesUIDs = [] + for policyName in currentPolicies: + if policyName: + for tag in currentPolicies[policyName]: + allCurrentPoliciesUIDs.append(tag['uid']) + + uidsToRemove = list(set(allUidsOnNMS) - set(allCurrentPoliciesUIDs)) + + for uid in uidsToRemove: + __deletePolicy__(nmsUrl=nmsUrl, nmsUsername=nmsUsername, nmsPassword=nmsPassword, policyUid=uid) + + return \ No newline at end of file diff --git a/src/v5_6/NIMOutput.py b/src/v5_6/NIMOutput.py new file mode 100644 index 00000000..024a834f --- /dev/null +++ b/src/v5_6/NIMOutput.py @@ -0,0 +1,375 @@ +""" +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_6_CreateConfig + +import v5_6.APIGateway +import v5_6.DevPortal +import v5_6.DeclarationPatcher +import v5_6.GitOps +import v5_6.MiscUtils +import v5_6.NIMOutput +import v5_6.NIMUtils + +# pydantic models +from V5_6_NginxConfigDeclaration import * + +# F5 WAF for NGINX helper functions +import v5_6.NIMNAPUtils + +# NGINX Declarative API modules +from NcgConfig import NcgConfig +from NcgRedis import NcgRedis + +def NIMOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpConf: str, + b64StreamConf: str,configFiles = {}, auxFiles = {}, + runfromautosync: bool = False, + configUid: str = ""): + # NGINX Instance Manager Staged Configuration publish + + nmsUsername = v5_6.MiscUtils.getDictKey(d, 'output.nms.username') + nmsPassword = v5_6.MiscUtils.getDictKey(d, 'output.nms.password') + nmsInstanceGroup = v5_6.MiscUtils.getDictKey(d, 'output.nms.instancegroup') + nmsSynctime = v5_6.MiscUtils.getDictKey(d, 'output.nms.synctime') + + nmsUrlFromJson = v5_6.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'}} + + # DNS resolution check + dnsOutcome, dnsReply = v5_6.MiscUtils.resolveFQDN(urlCheck.netloc) + if not dnsOutcome: + return {"status_code": 400, + "message": {"status_code": 400, "message": {"code": 400, + "content": f"DNS resolution failed for {urlCheck.netloc}: {dnsReply}"}}, + "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 F5 WAF for NGINX WAF policies from source of truth if needed + d_policies = v5_6.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_6.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_6.MiscUtils.getDictKey(d, 'declaration.http.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 + + # TLS certificates and key names validity checks for servers + d_servers = v5_6.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_6.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']) + "] must be one of [" + ",".join(all_tls['certificate']) + "]"} + }} + + cert_key = v5_6.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']) + "] must be one of [" + ",".join(all_tls['key']) + "]"} + }} + + trusted_cert_name = v5_6.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']) + + "] must be one of [" + ",".join(all_tls['certificate']) + "]"} + }} + + # TLS certificates and key names validity checks or ACME issuer profiles + d_acmeissuers = v5_6.MiscUtils.getDictKey(d, 'declaration.http.acme_issuers') + if d_acmeissuers is not None: + for issuer in d_acmeissuers: + cert_name = issuer['ssl_trusted_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 ACME issuer [" + str( + issuer['name']) +"] must be one of [" + ",".join(all_tls['certificate']) + "]"} + }} + + # Add optional certificates specified under declaration.http.certificates + extensions_map = {'certificate': '.crt', 'key': '.key'} + + d_certificates = v5_6.MiscUtils.getDictKey(d, 'declaration.http.certificates') + if d_certificates is not None: + for c in d_certificates: + status, certContent = v5_6.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 declaration.http.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={'mainhttpfile': NcgConfig.config['nms']['staged_config_http_filename'], + 'mainstreamfile': NcgConfig.config['nms']['staged_config_stream_filename'], + 'modules': v5_6.MiscUtils.getDictKey(d, 'output.nms.modules'), + 'license': v5_6.MiscUtils.getDictKey(d, 'output.license')}, + d={'http': v5_6.MiscUtils.getDictKey(d, 'declaration.http')}) + + # Base64-encoded NGINX main configuration (/etc/nginx/nginx.conf) + b64NginxMain = str(base64.urlsafe_b64encode(nginxMainConf.encode("utf-8")), "utf-8") + + # NGINX License file + licenseJwtFile = j2_env.get_template(NcgConfig.config['templates']['license']).render( + nginxconf={'license': v5_6.MiscUtils.getDictKey(d, 'output.license')}) + + # Base64-encoded license file (/etc/nginx/license.jwt) + b64licenseJwtFile = str(base64.urlsafe_b64encode(licenseJwtFile.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'} + filesLicenseFile = {'contents': b64licenseJwtFile, 'name': NcgConfig.config['nms']['config_dir'] + '/license.jwt'} + 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) + + # If no R33+ license token was specified in the JSON declaration, it is assumed a token already exists + # on the NGINX instances and it won't be overwritten + if v5_6.MiscUtils.getDictKey(d, 'output.license.token') != "": + configFiles['files'].append(filesLicenseFile) + + # 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_6.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'}} + + ### F5 WAF for NGINX policies support - commits policies to control plane + + # Check F5 WAF for NGINX WAF policies configuration sanity + status, description = v5_6.NIMNAPUtils.checkDeclarationPolicies(d) + + if status != 200: + return {"status_code": 422, + "message": {"status_code": status, "message": {"code": status, "content": description}}, + "headers": {'Content-Type': 'application/json'}} + + # Provision F5 WAF for NGINX WAF policies to NGINX Instance Manager + ppReply = v5_6.NIMNAPUtils.provisionPolicies( + nmsUrl=nmsUrl, nmsUsername=nmsUsername, nmsPassword=nmsPassword, declaration=d) + + if ppReply.status_code >= 400: + return {"status_code": ppReply.status_code, + "message": {"status_code": ppReply.status_code, "message": {"code": ppReply.status_code, "content": ppReply.content} }} + + napPolicies = json.loads(ppReply.body) + provisionedNapPolicies = napPolicies['all_policy_names_and_versions'] + activePolicyUids = napPolicies['all_policy_active_names_and_uids'] + + ### / F5 WAF for NGINX 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 + jsonResponse = {} + 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 deploymentCheck.status_code == 404: + jsonResponse = {"message": f"deployment not found at {publishResponse['links']['rel']}"} + isPending = False + + if 'details' in checkJson and not checkJson['details']['pending']: + isPending = False + + if 'details' not in checkJson or len(checkJson['details']['failure']) > 0: + # Staged config publish to NIM failed + jsonResponse = checkJson['details']['failure'][0] if 'details' in checkJson else jsonResponse + 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_6.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 F5 WAF for NGINX policies active + doWeHavePolicies = v5_6.NIMNAPUtils.makePolicyActive(nmsUrl=nmsUrl, nmsUsername=nmsUsername, + nmsPassword=nmsPassword, + activePolicyUids=activePolicyUids, + instanceGroupUid=igUid) + + if doWeHavePolicies: + # Clean up F5 WAF for NGINX WAF policies not used anymore + # and not defined in the declaration just pushed + time.sleep(NcgConfig.config['nms']['staged_config_publish_waittime']) + v5_6.NIMNAPUtils.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_6_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_6/NIMUtils.py b/src/v5_6/NIMUtils.py new file mode 100644 index 00000000..de1b9a96 --- /dev/null +++ b/src/v5_6/NIMUtils.py @@ -0,0 +1,26 @@ +""" +NGINX Instance Manager support functions +""" + +import requests +import json + + +# Fetch an instance group UID from NGINX Instance Manager +# Return None if not found +def getNIMInstanceGroupUid(nmsUrl: str, nmsUsername: str, nmsPassword: str, instanceGroupName: str): + # Retrieve instance group uid + ig = requests.get(url=f'{nmsUrl}/api/platform/v1/instance-groups', auth=(nmsUsername, nmsPassword), + verify=False) + + if ig.status_code != 200: + return None + + # Get the instance group id + igUid = None + igJson = json.loads(ig.text) + for i in igJson['items']: + if i['name'] == instanceGroupName: + igUid = i['uid'] + + return igUid diff --git a/src/v5_6/OpenAPIParser.py b/src/v5_6/OpenAPIParser.py new file mode 100644 index 00000000..5e415563 --- /dev/null +++ b/src/v5_6/OpenAPIParser.py @@ -0,0 +1,102 @@ +""" +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): + if 'info' in self.openAPISchema: + return self.openAPISchema['info'] + + return None + + 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: + self.m = {} + self.m['method'] = method + self.m['details'] = {} + self.m['parameters'] = [] + + self.m['details']['description'] = methodInfo['description'] if 'description' in methodInfo else '' + self.m['details']['summary'] = methodInfo['summary'] if 'summary' in methodInfo else '' + self.m['details']['operationId'] = methodInfo['operationId'] if 'operationId' in methodInfo else '' + + # loop over query string parameters + if 'parameters' in methodInfo and methodInfo['parameters']: + parametersInfo = methodInfo['parameters'] + for qsParam in parametersInfo: + if 'name' in qsParam: + thisParam = {} + thisParam['name'] = qsParam['name'] + thisParam['in'] = qsParam['in'] if 'in' in qsParam else '' + thisParam['description'] = qsParam['description'] if 'description' in qsParam else '' + thisParam['required'] = qsParam[ + 'required'] if 'required' in qsParam else False + # thisParam['type'] = qsParam['type'] if 'type' in qsParam else '' + thisParamSchema = {} + + if 'schema' in qsParam: + thisParamSchema['type'] = qsParam['schema']['type'] if 'type' in qsParam['schema'] else '' + thisParamSchema['default'] = qsParam['schema']['default'] if 'default' in qsParam['schema'] else '' + + thisParamSchemaEnum = [] + if 'enum' in qsParam['schema']: + for e in qsParam['schema']['enum']: + thisParamSchemaEnum.append(e) + + thisParamSchema['enum'] = thisParamSchemaEnum + + thisParam['schema'] = thisParamSchema + + self.m['parameters'].append(thisParam) + + self.p['methods'].append(self.m) + + self.allPaths.append(self.p) + + return self.allPaths diff --git a/templates/v5.6/apigateway-maps.tmpl b/templates/v5.6/apigateway-maps.tmpl new file mode 100644 index 00000000..23790689 --- /dev/null +++ b/templates/v5.6/apigateway-maps.tmpl @@ -0,0 +1,72 @@ +# API Gateway maps file - server {{ server }} +# OpenAPI version: {{ declaration.version }} +# Base URI: {{ declaration.location.uri }} +# Strip base URI: {{ declaration.location.apigateway.api_gateway.strip_uri }} + +{%- for path in declaration.paths -%} +{%- for method in path.methods %} +{%- set queryStringParms = namespace(allParams = '') %} +{%- for parm in method.parameters -%} +{%- if parm.required | lower == "true" and parm.in | lower == "query" %} +{%- set queryStringParms.allParams = queryStringParms.allParams + ' ' + parm.name %} +{%- endif %} +{%- endfor -%} + + +{% if queryStringParms.allParams != '' %} + + +# Required query string parameters for {{ declaration.location.uri }}{{ path.path }} - method {{ method.method|upper }} +map "" $required_params_{{ method.method }}_{{ server | replace('.','_') }}{{ declaration.location.uri | replace('/','_') }}{{ path.path | replace('/','_') | replace('.','_') | replace('{','_') | replace('}','_') }} { + default "{{ queryStringParms.allParams | trim }}"; +} +{%- endif -%} + +{% set allParams = namespace(missing = '') -%} +{% set allParamsValues = namespace(missing = '') -%} +{% for parm in method.parameters -%} +{% if parm.required | lower == "true" and parm.in|lower == "query" %} + +{% set allParams.missing = allParams.missing + "$missing_" + method.method + "_" + server | replace('.','_') + declaration.location.uri | replace('/','_') + path.path | replace('/','_') | replace('.','_') | replace('{','_') | replace('}','_') + "_" + parm.name %} + +# Check query string parameter value and set variable to 0 if the value is among allowed ones in the OpenAPI schema enum, 1 if value is wrong +{% if parm.schema.enum %} +map $request_method$host$uri-$arg_{{ parm.name }} $wrongvalue_{{ method.method }}_{{ server | replace('.','_') }}{{ declaration.location.uri | replace('/','_') }}{{ path.path | replace('/','_') | replace('.','_') | replace('{','_') | replace('}','_') }}_{{ parm.name }} +{ +{% for enum in parm.schema.enum %} + "{{ method.method|upper }}{{ server }}{{ declaration.location.uri }}{{ path.path }}-{{ enum }}" 0; +{% set allParamsValues.missing = allParamsValues.missing + "$wrongvalue_" + method.method + "_" + server | replace('.','_') + declaration.location.uri | replace('/','_') + path.path | replace('/','_') | replace('.','_') | replace('{','_') | replace('}','_') + "_" + parm.name + "-" + enum %} +{% endfor %} + default 1; +} +{% endif %} + +# Check query string parameters and set variable to 0 if found, 1 if missing +map $request_method$host$uri$arg_{{ parm.name }} $missing_{{ method.method }}_{{ server | replace('.','_') }}{{ declaration.location.uri | replace('/','_') }}{{ path.path | replace('/','_') | replace('.','_') | replace('{','_') | replace('}','_') }}_{{ parm.name }} +{ + "{{ method.method|upper }}{{ server }}{{ declaration.location.uri }}{{ path.path }}" 1; + default 0; +} +{% endif -%} +{%- endfor -%} + + +{% if allParams.missing != '' %} + +# Check if all required parameters have been received +map "{{ allParams.missing | trim }}" $any_missing_{{ method.method }}_{{ server | replace('.','_') }}{{ declaration.location.uri | replace('/','_') }}{{ path.path | replace('/','_') | replace('.','_') | replace('{','_') | replace('}','_') }} { + ~1 1; # if any digit is 1 one or more required query string parameter is missing + default 0; # all required query string parameters present +} +{% endif %} + + +# Check if all required parameter values have been received +map "{{ allParamsValues.missing | trim }}" $any_values_invalid_{{ method.method }}_{{ server | replace('.','_') }}{{ declaration.location.uri | replace('/','_') }}{{ path.path | replace('/','_') | replace('.','_') | replace('{','_') | replace('}','_') }} { +{% if allParamsValues.missing != '' %} + ~1 1; # if any digit is 1 one or more required query string parameter value is invalid +{% endif %} + default 0; # all required query string parameters have valid values +} +{%- endfor %} +{% endfor %} \ No newline at end of file diff --git a/templates/v5.6/apigateway.tmpl b/templates/v5.6/apigateway.tmpl new file mode 100644 index 00000000..48f016e8 --- /dev/null +++ b/templates/v5.6/apigateway.tmpl @@ -0,0 +1,210 @@ +{% 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 %} + +{% if declaration.info %} +# API Gateway: {% if declaration.info.title %}{{ declaration.info.title }}{% endif %} {% if declaration.info.version %}{{ declaration.info.version }}{% endif %} +{% endif %} + +# OpenAPI version: {{ declaration.version | replace('\n',' ') }} +# Base URI: {{ declaration.location.uri | replace('\n',' ') }} +# Strip base URI: {{ declaration.location.apigateway.api_gateway.strip_uri | replace('\n',' ') }} +# Destination server: {{ destination_server | replace('\n',' ') }} + +default_type application/json; + +{% for v in enabledVisibility %} +include "{{ ncgconfig.nms.visibility_dir }}{{ declaration.location.uri }}-{{ v }}-server.conf"; +{% endfor %} + +{% if declaration.paths -%} +{% for path in declaration.paths|sort(attribute='path', reverse = True) %} +location {% if '{' not in path.path %}={% else %}~{% endif %} {% if declaration.location.uri != "/" %}{{ declaration.location.uri }}{% endif %}{{ path.path | regex_replace('{(.*?)}','([^/]+)') }} { + status_zone {% if declaration.location.uri != "/" %}{{ declaration.location.uri }}{% endif %}{{ path.path | regex_replace('{(.*?)}','([^/]+)') }}; + + {% for method in path.methods -%} + # {{ method.method|upper }} - operationId: {{ method.details.operationId }} + {% if method.details.description %}# Description: {{ method.details.description | replace('\n',' ') }}{% endif %} + + {% if method.details.summary %}# Summary: {{ method.details.summary }}{% endif %} + + + {# --- Query String parameters enforcement --- -#} + {%- set allParams = namespace(missing = '') -%} + {% for parm in method.parameters -%} + {% if parm.required | lower == "true" and parm.in | lower == "query" %} + {% set allParams.missing = allParams.missing + "$missing_" + method.method + "_" + server | replace('.','_') + declaration.location.uri | replace('/','_') + path.path | replace('/','_') | replace('.','_') | replace('{','_') | replace('}','_') + "_" + parm.name %} + {% endif %} + {% endfor %} + + {% if allParams.missing != '' -%} + if ( $any_missing_{{ method.method }}_{{ server | replace('.','_') }}{{ declaration.location.uri | replace('/','_') }}{{ path.path | replace('/','_') | replace('.','_') | replace('{','_') | replace('}','_') }} ) { + return 422 '{"code":422,"message":"Missing required query parameter [$required_params_{{ method.method }}_{{ server | replace('.','_') }}{{ declaration.location.uri | replace('/','_') }}{{ path.path | replace('/','_') | replace('.','_') | replace('{','_') | replace('}','_') }}]"}'; + } + if ( $any_values_invalid_{{ method.method }}_{{ server | replace('.','_') }}{{ declaration.location.uri | replace('/','_') }}{{ path.path | replace('/','_') | replace('.','_') | replace('{','_') | replace('}','_') }} ) { + return 422 '{"code":422,"message":"Invalid parameter value"}'; + } + {%- endif %} + + {% endfor -%} + {% set method_names = path.methods|map(attribute='method')|list %} + + {% if declaration.location.apigateway.log.access %}access_log {{ declaration.location.apigateway.log.access.destination }}{% if declaration.location.apigateway.log.access.format %} {{ declaration.location.apigateway.log.access.format }}{% endif %}{% if declaration.location.apigateway.log.access.condition %} if={{ declaration.location.apigateway.log.access.condition }}{% endif %};{% endif %} + + {% if declaration.location.apigateway.log.error %}error_log {{ declaration.location.apigateway.log.error.destination }}{% if declaration.location.apigateway.log.error.level %} {{ declaration.location.apigateway.log.error.level }}{% endif %};{% endif %} + + + {# --- HTTP methods enforcement --- -#} + 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 | replace(' ', '_') }}{% 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 --- #} + + {# --- Cache --- #} + {%- if declaration.location.apigateway.cache -%} + {%- for cacheEntry in declaration.location.apigateway.cache %} + {%- set enforceCache = namespace(toBeEnforced = False) -%} + {%- if cacheEntry.enforceOnPaths == False -%} + {%- set enforceCache.toBeEnforced = True -%} + {%- endif -%} + {%- for cachePath in cacheEntry.paths -%} + {%- if path.path == cachePath -%} + {%- if cacheEntry.enforceOnPaths == True -%} + {%- set enforceCache.toBeEnforced = True -%} + {%- else -%} + {%- set enforceCache.toBeEnforced = False -%} + {%- endif -%} + {%- endif -%} + {%- endfor -%} + + {%- if enforceCache.toBeEnforced == True -%} + {%- if cacheEntry.profile %}proxy_cache {{ cacheEntry.profile | replace(' ', '_') }}; + + {% if cacheEntry.key %}proxy_cache_key "{{ cacheEntry.key }}";{% endif %} + {% endif %} + + {% if cacheEntry.validity -%} + {% for validity in cacheEntry.validity -%} + proxy_cache_valid {{ validity.code }} {{ validity.ttl }}; + {% endfor %} + {% endif %} + {%- endif -%} + {%- endfor -%} + + {%- endif %} + + {# --- Cache end --- #} + + {%- if declaration.location.apigateway.api_gateway.strip_uri -%} + rewrite ^{% if declaration.location.uri != "/" %}{{ declaration.location.uri }}{% endif %}/(.*)$ /$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$is_args$args; +} + +{% endfor %} + +{% if declaration.location.apigateway.developer_portal.enabled == True -%} + {% if declaration.location.apigateway.developer_portal.type.lower() == "redocly" %} +location = {% if declaration.location.uri != "/" %}{{ declaration.location.uri }}{% endif %}{{ declaration.location.apigateway.developer_portal.redocly.uri }} { + rewrite ^{% if declaration.location.uri != "/" %}{{ declaration.location.uri }}{% endif %}/(.*)$ /$1 break; + root {{ ncgconfig.nms.devportal_dir }}; +} + {% endif %} +{% endif %} +{% endif %} diff --git a/templates/v5.6/authn/client/jwks.tmpl b/templates/v5.6/authn/client/jwks.tmpl new file mode 100644 index 00000000..aea3a355 --- /dev/null +++ b/templates/v5.6/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.6/authn/client/jwt.tmpl b/templates/v5.6/authn/client/jwt.tmpl new file mode 100644 index 00000000..14e97192 --- /dev/null +++ b/templates/v5.6/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.6/authn/client/mtls.tmpl b/templates/v5.6/authn/client/mtls.tmpl new file mode 100644 index 00000000..683facca --- /dev/null +++ b/templates/v5.6/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.6/authn/client/oidc.tmpl b/templates/v5.6/authn/client/oidc.tmpl new file mode 100644 index 00000000..158e217f --- /dev/null +++ b/templates/v5.6/authn/client/oidc.tmpl @@ -0,0 +1,47 @@ +# OpenID Connect provider for {{ authprofile.name }} + +oidc_provider {{ authprofile.name | replace(" ", "_") }} { + issuer {{ authprofile.oidc.issuer }}; + client_id {{ authprofile.oidc.client_id }}; + client_secret {{ authprofile.oidc.client_secret }}; + + {%- if authprofile.oidc.config_url -%} + config_url {{ authprofile.oidc.config_url }}; + {% endif %} + {%- if authprofile.oidc.cookie_name -%} + cookie_name {{ authprofile.oidc.cookie_name }}; + {% endif %} + {%- if authprofile.oidc.extra_auth_args -%} + extra_auth_args {{ authprofile.oidc.configextra_auth_args_url }}; + {% endif %} + {%- if authprofile.oidc.redirect_uri -%} + redirect_uri {{ authprofile.oidc.redirect_uri }}; + {% endif %} + {%- if authprofile.oidc.logout_uri -%} + logout_uri {{ authprofile.oidc.logout_uri }}; + {% endif %} + {%- if authprofile.oidc.post_logout_uri -%} + post_logout_uri {{ authprofile.oidc.post_logout_uri }}; + {% endif %} + {%- if authprofile.oidc.logout_token_hint -%} + logout_token_hint {% if authprofile.oidc.logout_token_hint == True %}on{% else %}off{% endif %}; + {% endif %} + {%- if authprofile.oidc.scope -%} + scope {{ authprofile.oidc.scope }}; + {% endif %} + {%- if authprofile.oidc.session_store -%} + session_store {{ authprofile.oidc.session_store }}; + {% endif %} + {%- if authprofile.oidc.session_timeout -%} + session_timeout {{ authprofile.oidc.session_timeout }}; + {% endif %} + {%- if authprofile.oidc.ssl_crl -%} + ssl_crl {{ ncgconfig.nms.certs_dir }}/{{ authprofile.oidc.ssl_crl }}.crt; + {% endif %} + {%- if authprofile.oidc.ssl_trusted_certificate -%} + ssl_trusted_certificate {{ ncgconfig.nms.certs_dir }}/{{ authprofile.oidc.ssl_trusted_certificate }}.crt; + {% endif %} + {%- if authprofile.oidc.userinfo -%} + userinfo {% if authprofile.oidc.userinfo == True %}on{% else %}off{% endif %}; + {% endif %} +} \ No newline at end of file diff --git a/templates/v5.6/authn/server/mtls.tmpl b/templates/v5.6/authn/server/mtls.tmpl new file mode 100644 index 00000000..5b0ae188 --- /dev/null +++ b/templates/v5.6/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.6/authn/server/token.tmpl b/templates/v5.6/authn/server/token.tmpl new file mode 100644 index 00000000..7acbd601 --- /dev/null +++ b/templates/v5.6/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.6/authz/client/jwt-authz-map.tmpl b/templates/v5.6/authz/client/jwt-authz-map.tmpl new file mode 100644 index 00000000..047da21f --- /dev/null +++ b/templates/v5.6/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.6/authz/client/jwt.tmpl b/templates/v5.6/authz/client/jwt.tmpl new file mode 100644 index 00000000..f6b4d910 --- /dev/null +++ b/templates/v5.6/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.6/devportal/backstage.tmpl b/templates/v5.6/devportal/backstage.tmpl new file mode 100644 index 00000000..9482f716 --- /dev/null +++ b/templates/v5.6/devportal/backstage.tmpl @@ -0,0 +1,17 @@ +apiVersion: backstage.io/v1alpha1 +kind: API +metadata: + name: {{ declaration.name }} + annotations: + github.com/project-slug: backstage/backstage + backstage.io/techdocs-ref: dir:. + lighthouse.com/website-url: https://backstage.io +spec: + type: openapi + lifecycle: {{ declaration.lifecycle }} + owner: {{ declaration.owner }} + system: {{ declaration.system }} + definition: | +{% filter indent(width=4) %} + {{ openAPISchema }} +{% endfilter %} \ No newline at end of file diff --git a/templates/v5.6/http.tmpl b/templates/v5.6/http.tmpl new file mode 100644 index 00000000..2b0046b1 --- /dev/null +++ b/templates/v5.6/http.tmpl @@ -0,0 +1,147 @@ +# 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 %} + +{# --- DNS resolver --- #} +{% if declaration.resolver -%} +include "{{ ncgconfig.nms.resolver_dir }}/{{ declaration.resolver | replace(" ", "_") }}.conf"; +{% endif -%} + +{# --- OpenID Connect providers --- #} +# OpenID Connect profiles +include "{{ ncgconfig.nms.auth_client_dir }}/oidc/*.conf"; + +{# --- ACME issuers shared zone --- #} +{% if declaration.acme_issuers %} +# ACME issuers shared memory zone +acme_shared_zone zone=ngx_acme_shared:1M; + +{%- for i in declaration.acme_issuers -%} +include "{{ ncgconfig.nms.acme_dir }}/{{ i.name | replace(" ", "_") }}.conf"; +{%- endfor -%} + +server { + # listener on port 80 is required to process ACME HTTP-01 challenges + listen 80; + + location / { + return 404; + } +} +{%- 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 -%} +# Authorization profiles +variables_hash_bucket_size 512; +map_hash_bucket_size 256; +{% for authzprofile in declaration.authorization -%} +include "{{ ncgconfig.nms.authz_client_dir }}/{{ authzprofile.name | replace(" ", "_") }}.maps.conf"; +{% endfor -%} +{%- endif -%} + +{# --- Maps section for API Gateway parameters enforcement --- #} + +# API Gateway parameter enforcement maps +include "{{ ncgconfig.nms.apigw_maps_dir }}/*.conf"; + +{# --- Snippets section --- #} +{% if declaration.snippet and declaration.snippet.content %}{{ declaration.snippet.content | b64decode }}{% endif %} + + +{# --- Upstreams section --- #} +{% if declaration.upstreams %} +# Upstreams +{% for u in declaration.upstreams %} +{% if u.name %} +include "{{ ncgconfig.nms.upstream_http_dir }}/{{ u.name | replace(' ', '_') }}.conf"; +{% endif %} +{% endfor %} +{% endif %} + +{# --- Rate limit section --- #} +{% if declaration.rate_limit %} +# Rate limiting zones +{% for rl in declaration.rate_limit %} +limit_req_zone {{ rl.key }} zone={{ rl.name | replace(' ', '_') }}:{{ rl.size }} rate={{ rl.rate }}; +{% endfor %} +{% endif %} + +{# --- Cache section --- #} +{% if declaration.cache %} +# Cache zones +{% for c in declaration.cache %} +proxy_cache_path {{ c.basepath }}/{{ c.name | replace(' ', '_') }} levels=1:2 keys_zone={{ c.name | replace(' ', '_') }}:{{ c.ttl }} max_size={{ c.size }}; +{% endfor %} +{% endif -%} + +{# --- Visibility integration section --- #} +# Visibility integrations +include "{{ ncgconfig.nms.visibility_dir }}/*-http.conf"; + +{# --- 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 %} +include "{{ ncgconfig.nms.server_http_dir }}/{{ s.name | replace(' ', '_') }}.conf"; +{% endfor -%} \ No newline at end of file diff --git a/templates/v5.6/logformat.tmpl b/templates/v5.6/logformat.tmpl new file mode 100644 index 00000000..db9863e5 --- /dev/null +++ b/templates/v5.6/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.6/misc/acme.tmpl b/templates/v5.6/misc/acme.tmpl new file mode 100644 index 00000000..3b8d7642 --- /dev/null +++ b/templates/v5.6/misc/acme.tmpl @@ -0,0 +1,21 @@ +# ACME Issuer template + +acme_issuer {{ acmeprofile.name | replace(" ", "_") }} { + uri {{ acmeprofile.uri }}; +{% if acmeprofile.account_key %} + account_key {{ acmeprofile.account_key }}; +{% endif -%} +{% if acmeprofile.contact %} + contact {{ acmeprofile.contact }}; +{% endif %} +{% if acmeprofile.ssl_trusted_certificate %} + ssl_trusted_certificate {{ ncgconfig.nms.certs_dir }}/{{ acmeprofile.ssl_trusted_certificate }}.crt; +{% endif %} + ssl_verify {% if acmeprofile.ssl_verify == True %}on{% else %}off{% endif %}; +{% if acmeprofile.state_path %} + state_path {{ acmeprofile.state_path }}; +{% endif %} +{% if acmeprofile.accept_terms_of_service %} + accept_terms_of_service; +{% endif -%} +} diff --git a/templates/v5.6/misc/resolver.tmpl b/templates/v5.6/misc/resolver.tmpl new file mode 100644 index 00000000..963bc3c2 --- /dev/null +++ b/templates/v5.6/misc/resolver.tmpl @@ -0,0 +1,4 @@ +# DNS resolver template + +resolver {{ resolverprofile.address }}{% if resolverprofile.valid %}valid={{ resolverprofile.valid }}{% endif %} ipv4={% if resolverprofile.ipv4 == True %}on{% else %}off{% endif %} ipv6={% if resolverprofile.ipv6 == True %}on{% else %}off{% endif %}; +{% if resolverprofile.timeout %}resolver_timeout {{ resolverprofile.timeout }}{% endif %}; \ No newline at end of file diff --git a/templates/v5.6/misc/server-http.tmpl b/templates/v5.6/misc/server-http.tmpl new file mode 100644 index 00000000..c5fdccd8 --- /dev/null +++ b/templates/v5.6/misc/server-http.tmpl @@ -0,0 +1,360 @@ +# HTTP server - {{ s.name }} + +server { + {#- --- 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.acme_issuer -%} + acme_certificate {{ s.listen.tls.acme_issuer | replace(" ", "_") }}; + {% endif -%} + + {%- 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] | replace(" ", "_") }}; + proxy_ssl_server_name on; + {% endif %} + + {% if s.resolver -%} + include "{{ ncgconfig.nms.resolver_dir }}/{{ s.resolver | replace(" ", "_") }}.conf"; + {% 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.destination }}{% if s.log.access.format %} {{ s.log.access.format }}{% endif %}{% if s.log.access.condition %} if={{ s.log.access.condition }}{% endif %};{% endif %} + + {% if s.log.error %}error_log {{ s.log.error.destination }}{% if s.log.error.level %} {{ s.log.error.level }}{% endif %};{% endif %} + + {# --- Client authentication at server {} level --- #} + {%- if s.authentication and s.authentication.client -%} + {%- for clientAuthProfile in s.authentication.client -%} + {%- set isThisOIDC = namespace(found = False) -%} + {%- for declClientAuthProfile in declaration.authentication.client -%} + {%- if declClientAuthProfile.type == "oidc" and declClientAuthProfile.name == clientAuthProfile.profile -%} + auth_oidc {{ clientAuthProfile.profile | replace(" ", "_") }}; + {%- set isThisOIDC.found = True -%} + {% endif -%} + {%- endfor -%} + {%- if isThisOIDC.found == False -%} + include "{{ ncgconfig.nms.auth_client_dir }}/{{ clientAuthProfile.profile | replace(" ", "_") }}.conf"; + {%- endif -%} + {% 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 %} + + {# --- Cache --- #} + {%- if s.cache -%} + {%- if s.cache.profile %}proxy_cache {{ s.cache.profile | replace(' ', '_') }}; + + {% if s.cache.key %}proxy_cache_key "{{ s.cache.key }}";{% endif %} + {% endif %} + + {% if s.cache.validity -%} + {% for validity in s.cache.validity -%} + proxy_cache_valid {{ validity.code }} {{ validity.ttl }}; + {% endfor %} + {% endif %} + + {% 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 }} { + status_zone {{ loc.uri | replace(" ", "_") }}; + {% 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.destination }}{% if loc.log.access.format %} {{ loc.log.access.format }}{% endif %}{% if loc.log.access.condition %} if={{ loc.log.access.condition }}{% endif %};{% endif %} + + {% if loc.log.error %}error_log {{ loc.log.error.destination }}{% if loc.log.error.level %} {{ loc.log.error.level }}{% endif %};{% 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 %} + + {# --- Cache --- #} + {%- if loc.cache -%} + {%- if loc.cache.profile %}proxy_cache {{ loc.cache.profile | replace(' ', '_') }}; + + {% if loc.cache.key %}proxy_cache_key "{{ loc.cache.key }}";{% endif %} + {% endif %} + + {% if loc.cache.validity -%} + {% for validity in loc.cache.validity -%} + proxy_cache_valid {{ validity.code }} {{ validity.ttl }}; + {% endfor %} + {% endif %} + + {% endif %} + + {# --- Client authentication at location level --- #} + {%- if loc.authentication and loc.authentication.client -%} + {%- for clientAuthProfile in loc.authentication.client -%} + {%- set isThisOIDC = namespace(found = False) -%} + {%- for declClientAuthProfile in declaration.authentication.client -%} + {%- if declClientAuthProfile.type == "oidc" and declClientAuthProfile.name == clientAuthProfile.profile -%} + auth_oidc {{ clientAuthProfile.profile | replace(" ", "_") }}; + {%- set isThisOIDC.found = True -%} + {% endif -%} + {%- endfor -%} + {%- if isThisOIDC.found == False -%} + include "{{ ncgconfig.nms.auth_client_dir }}/{{ clientAuthProfile.profile | replace(" ", "_") }}.conf"; + {%- endif -%} + {% 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 }}/{{ s.names[0] }}{{ 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 %} + +} \ No newline at end of file diff --git a/templates/v5.6/misc/server-stream.tmpl b/templates/v5.6/misc/server-stream.tmpl new file mode 100644 index 00000000..0d8a4e73 --- /dev/null +++ b/templates/v5.6/misc/server-stream.tmpl @@ -0,0 +1,43 @@ +# Stream server template + + {%- 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 | replace(" ", "_") }}; + {% endif -%} + {% endif -%} + + {% if s.resolver -%} + include "{{ ncgconfig.nms.resolver_dir }}/{{ s.resolver | replace(" ", "_") }}.conf"; + {% 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 -%} \ No newline at end of file diff --git a/templates/v5.6/misc/upstream-http.tmpl b/templates/v5.6/misc/upstream-http.tmpl new file mode 100644 index 00000000..5c82a664 --- /dev/null +++ b/templates/v5.6/misc/upstream-http.tmpl @@ -0,0 +1,23 @@ +# HTTP upstream template + +{% 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.resolver -%} + include "{{ ncgconfig.nms.resolver_dir }}/{{ u.resolver | replace(" ", "_") }}.conf"; + {% endif -%} + + {% if u.snippet and u.snippet.content %}{{ u.snippet.content | b64decode }}{% endif %} + +} +{% endif %} +{% endif %} \ No newline at end of file diff --git a/templates/v5.6/misc/upstream-stream.tmpl b/templates/v5.6/misc/upstream-stream.tmpl new file mode 100644 index 00000000..2e686aff --- /dev/null +++ b/templates/v5.6/misc/upstream-stream.tmpl @@ -0,0 +1,19 @@ +# Stream upstream template + +{% 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 %} + + {% if u.resolver -%} + include "{{ ncgconfig.nms.resolver_dir }}/{{ u.resolver | replace(" ", "_") }}.conf"; + {% endif %} + +} +{% endif %} +{% endif %} \ No newline at end of file diff --git a/templates/v5.6/nginx-conf/license-key.tmpl b/templates/v5.6/nginx-conf/license-key.tmpl new file mode 100644 index 00000000..f729d84c --- /dev/null +++ b/templates/v5.6/nginx-conf/license-key.tmpl @@ -0,0 +1 @@ +{{ nginxconf.license.token }} \ No newline at end of file diff --git a/templates/v5.6/nginx-conf/mime.types b/templates/v5.6/nginx-conf/mime.types new file mode 100644 index 00000000..d4e08dfe --- /dev/null +++ b/templates/v5.6/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.6/nginx-conf/nginx.conf b/templates/v5.6/nginx-conf/nginx.conf new file mode 100644 index 00000000..7e46c902 --- /dev/null +++ b/templates/v5.6/nginx-conf/nginx.conf @@ -0,0 +1,72 @@ +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"'; + + # Additional log formats + {% if d.http.logformats -%} + # found + {% for lf in d.http.logformats -%} + log_format {{ lf.name }} escape={{ lf.escape }} '{{ lf.format }}'; + {% endfor -%} + {%- endif %} + + access_log /var/log/nginx/access.log main; + + sendfile on; + #tcp_nopush on; + keepalive_timeout 65; + #gzip on; + include /etc/nginx/{{ nginxconf.mainhttpfile }}; +} + +# 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/{{ nginxconf.mainstreamfile }}; +} + +{% if nginxconf.license %} +# NGINX R33+ license +mgmt { + # Default reporting sent to product.connect.nginx.com + usage_report endpoint={{ nginxconf.license.endpoint }}; + license_token /etc/nginx/license.jwt; + + # Set to 'off' to begin the 180-day reporting enforcement grace period. + # Reporting must begin or resume before the end of the grace period + # to ensure continued operation. + enforce_initial_report {% if nginxconf.license.grace_period == False %}on{% else %}off{% endif %}; + + # Set to 'off' to trust all SSL certificates (not recommended). + # Useful for reporting to NGINX Instance Manager without a local PKI. + ssl_verify {% if nginxconf.license.ssl_verify == True %}on{% else %}off{% endif %}; + + {% if nginxconf.license.proxy %}proxy {{ nginxconf.license.proxy }};{% endif %} + + {% if nginxconf.license.proxy_username %}proxy_username {{ nginxconf.license.proxy_username }};{% endif %} + + {% if nginxconf.license.proxy_password %}proxy_password {{ nginxconf.license.proxy_password }};{% endif %} + +} +{% endif %} \ No newline at end of file diff --git a/templates/v5.6/stream.tmpl b/templates/v5.6/stream.tmpl new file mode 100644 index 00000000..2374f026 --- /dev/null +++ b/templates/v5.6/stream.tmpl @@ -0,0 +1,17 @@ +# NGINX configuration file - Stream servers - generated by https://github.com/f5devcentral/NGINX-Declarative-API + +{# --- Upstreams section --- #} +{% if declaration.upstreams %} +# Upstreams +{% for u in declaration.upstreams %} +{% if u.name %} +include "{{ ncgconfig.nms.upstream_stream_dir }}/{{ u.name | replace(' ', '_') }}.conf"; +{% endif %} +{% endfor %} +{% endif %} + +{# --- Stream server section --- #} + +{% for s in declaration.servers %} +include "{{ ncgconfig.nms.server_stream_dir }}/{{ s.name | replace(' ', '_') }}.conf"; +{%- endfor %} diff --git a/templates/v5.6/visibility/moesif/http.tmpl b/templates/v5.6/visibility/moesif/http.tmpl new file mode 100644 index 00000000..ccf38e2a --- /dev/null +++ b/templates/v5.6/visibility/moesif/http.tmpl @@ -0,0 +1,14 @@ +# Moesif integration - https://www.moesif.com/docs/server-integration/nginx-openresty/ +# URI: {{ loc.uri }} +# application ID: {{ vis.moesif.application_id }} + +lua_shared_dict moesif_conf 5m; + +init_by_lua_block { + local config = ngx.shared.moesif_conf; + config:set("application_id", "{{ vis.moesif.application_id }}") +} + +lua_package_cpath ";;${prefix}?.so;${prefix}src/?.so;/usr/share/lua/5.1/lua/resty/moesif/?.so;/usr/share/lua/5.1/?.so;/usr/lib64/lua/5.1/?.so;/usr/lib/lua/5.1/?.so;/usr/local/openresty/luajit/share/lua/5.1/lua/resty?.so;/usr/local/share/lua/5.1/resty/moesif/?.so;{{ vis.moesif.plugin_path }}/?.so"; +lua_package_path ";;${prefix}?.lua;${prefix}src/?.lua;/usr/share/lua/5.1/lua/resty/moesif/?.lua;/usr/share/lua/5.1/?.lua;/usr/lib64/lua/5.1/?.lua;/usr/lib/lua/5.1/?.lua;/usr/local/openresty/luajit/share/lua/5.1/lua/resty?.lua;/usr/local/share/lua/5.1/resty/moesif/?.lua;{{ vis.moesif.plugin_path }}/?.lua"; + diff --git a/templates/v5.6/visibility/moesif/server.tmpl b/templates/v5.6/visibility/moesif/server.tmpl new file mode 100644 index 00000000..51c58dab --- /dev/null +++ b/templates/v5.6/visibility/moesif/server.tmpl @@ -0,0 +1,21 @@ +# Moesif integration - https://www.moesif.com/docs/server-integration/nginx-openresty/ +# URI: {{ loc.uri }} +# application ID: {{ vis.moesif.application_id }} + +# Define the variables Moesif requires +set $moesif_user_id nil; +set $moesif_company_id nil; +set $moesif_req_body nil; +set $moesif_res_body nil; + +# Optionally, set moesif_user_id and moesif_company_id such from a request header or NGINX var to identify customer +header_filter_by_lua_block { + ngx.var.moesif_user_id = ngx.req.get_headers()["X-User-Id"] + ngx.var.moesif_company_id = ngx.req.get_headers()["X-Company-Id"] +} + +# Add Moesif plugin +access_by_lua_file {{ vis.moesif.plugin_path }}/read_req_body.lua; +body_filter_by_lua_file {{ vis.moesif.plugin_path }}/read_res_body.lua; +log_by_lua_file {{ vis.moesif.plugin_path }}/send_event.lua; + From 8ce845b206ca77a6737f2dd9abce6a043b29dc3a Mon Sep 17 00:00:00 2001 From: Fabrizio Fiorucci Date: Tue, 21 Apr 2026 17:52:47 +0100 Subject: [PATCH 03/12] v5.6 updates --- src/V5_6_CreateConfig.py | 2 +- src/v5_5/NIMNAPUtils.py | 2 +- src/v5_6/NIMNAPUtils.py | 12 ++++++++---- src/v5_6/NIMOutput.py | 18 +++++++++--------- src/v5_6/NIMUtils.py | 2 +- templates/v5.6/misc/server-http.tmpl | 2 +- 6 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/V5_6_CreateConfig.py b/src/V5_6_CreateConfig.py index a437c689..7948f01d 100644 --- a/src/V5_6_CreateConfig.py +++ b/src/V5_6_CreateConfig.py @@ -69,7 +69,7 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn # Pydantic JSON validation ConfigDeclaration(**declaration.model_dump()) except ValidationError as e: - print(f'Invalid declaration {e}') + print(f"Invalid declaration {e}") d = declaration.model_dump() decltype = d['output']['type'] diff --git a/src/v5_5/NIMNAPUtils.py b/src/v5_5/NIMNAPUtils.py index e22d5f94..ba9290bc 100644 --- a/src/v5_5/NIMNAPUtils.py +++ b/src/v5_5/NIMNAPUtils.py @@ -15,7 +15,7 @@ available_log_profiles = ['log_all', 'log_blocked', 'log_illegal', 'secops_dashboard'] -# Define (create/update) a F5 WAF for NGINX policy on NMS. +# Define (create/update) a F5 WAF for NGINX policy on NGINX Instance Manager. # If policyUid is not empty the policy update is performed # Returns a tuple {status_code,text}. status_code is 201 if successful def __definePolicyOnNMS__(nmsUrl: str, nmsUsername: str, nmsPassword: str, policyName: str, policyDisplayName: str, diff --git a/src/v5_6/NIMNAPUtils.py b/src/v5_6/NIMNAPUtils.py index bb211e2d..57acc74f 100644 --- a/src/v5_6/NIMNAPUtils.py +++ b/src/v5_6/NIMNAPUtils.py @@ -119,7 +119,7 @@ def checkDeclarationPolicies(declaration: dict): if 'policy' in httpServer['app_protect'] and httpServer['app_protect']['policy'] \ and httpServer['app_protect']['policy'] not in allPolicyNames: return 422, f"Unknown F5 WAF for NGINX WAF policy [{httpServer['app_protect']['policy']}] " \ - f"referenced by HTTP server [{httpServer['name']}]" + f"referenced by HTTP server [{httpServer['name']}] it should be one of [{', '.join(allPolicyNames.keys())}]" if 'log' in httpServer['app_protect'] \ and 'profile_name' in httpServer['app_protect']['log'] \ @@ -128,7 +128,7 @@ def checkDeclarationPolicies(declaration: dict): not in available_log_profiles: return 422, f"Invalid F5 WAF for NGINX WAF log profile " \ f"[{httpServer['app_protect']['log']['profile_name']}] referenced by HTTP server " \ - f"[{httpServer['name']}]" + f"[{httpServer['name']}] it should be one of [{', '.join(available_log_profiles.keys())}]" # Check policy names referenced in HTTP servers[].locations[] for location in httpServer['locations']: @@ -136,7 +136,8 @@ def checkDeclarationPolicies(declaration: dict): if 'policy' in location['app_protect'] and location['app_protect']['policy'] \ and location['app_protect']['policy'] not in allPolicyNames: return 422, f"Unknown F5 WAF for NGINX WAF policy [{location['app_protect']['policy']}] " \ - f"referenced by HTTP server [{httpServer['name']}] location [{location['uri']}]" + (f"referenced by HTTP server [{httpServer['name']}] location [{location['uri']}] " + f"it should be one of [{', '.join(allPolicyNames.keys())}]") if 'log' in httpServer['app_protect'] and httpServer['app_protect']['log'] \ and httpServer['app_protect']['log']['profile_name'] \ @@ -144,7 +145,8 @@ def checkDeclarationPolicies(declaration: dict): not in available_log_profiles: return 422, f"Invalid F5 WAF for NGINX WAF log profile " \ f"[{httpServer['app_protect']['log']['profile_name']}] referenced by HTTP server " \ - f"[{httpServer['name']}] location [{location['uri']}]" + (f"[{httpServer['name']}] location [{location['uri']}] " + f"it should be one of [{', '.join(available_log_profiles.keys())}]") return 200, "" @@ -244,6 +246,8 @@ def makePolicyActive(nmsUrl: str, nmsUsername: str, nmsPassword: str, activePoli r = requests.post(url=f'{nmsUrl}/api/platform/v1/security/publish', auth=(nmsUsername, nmsPassword), data=json.dumps(body), headers={'Content-Type': 'application/json'}, verify=False) + print(f"WAF policy publish {policyName} {body} -> {r.status_code} {r.text}") + return doWeHavePolicies diff --git a/src/v5_6/NIMOutput.py b/src/v5_6/NIMOutput.py index 024a834f..3c52ab53 100644 --- a/src/v5_6/NIMOutput.py +++ b/src/v5_6/NIMOutput.py @@ -247,7 +247,7 @@ def NIMOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpConf: s ### F5 WAF for NGINX policies support - commits policies to control plane - # Check F5 WAF for NGINX WAF policies configuration sanity + # Check WAF policies configuration sanity status, description = v5_6.NIMNAPUtils.checkDeclarationPolicies(d) if status != 200: @@ -255,7 +255,7 @@ def NIMOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpConf: s "message": {"status_code": status, "message": {"code": status, "content": description}}, "headers": {'Content-Type': 'application/json'}} - # Provision F5 WAF for NGINX WAF policies to NGINX Instance Manager + # Provision WAF policies to NGINX Instance Manager ppReply = v5_6.NIMNAPUtils.provisionPolicies( nmsUrl=nmsUrl, nmsUsername=nmsUsername, nmsPassword=nmsPassword, declaration=d) @@ -267,7 +267,7 @@ def NIMOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpConf: s provisionedNapPolicies = napPolicies['all_policy_names_and_versions'] activePolicyUids = napPolicies['all_policy_active_names_and_uids'] - ### / F5 WAF for NGINX policies support + ### / F5 WAF for NGINX policies support ### Publish staged config to instance group r = requests.post(url=nmsUrl + f"/api/platform/v1/instance-groups/{igUid}/config", @@ -285,7 +285,7 @@ def NIMOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpConf: s # Fetch the deployment status publishResponse = json.loads(r.text) - # Wait for either NIM success or failure after pushing a staged config + # Wait for either NGINX Instance Manager success or failure after pushing a staged config isPending = True jsonResponse = {} while isPending: @@ -331,17 +331,17 @@ def NIMOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpConf: s # Makes F5 WAF for NGINX policies active doWeHavePolicies = v5_6.NIMNAPUtils.makePolicyActive(nmsUrl=nmsUrl, nmsUsername=nmsUsername, - nmsPassword=nmsPassword, - activePolicyUids=activePolicyUids, - instanceGroupUid=igUid) + nmsPassword=nmsPassword, + activePolicyUids=activePolicyUids, + instanceGroupUid=igUid) if doWeHavePolicies: # Clean up F5 WAF for NGINX WAF policies not used anymore # and not defined in the declaration just pushed time.sleep(NcgConfig.config['nms']['staged_config_publish_waittime']) v5_6.NIMNAPUtils.cleanPolicyLeftovers(nmsUrl=nmsUrl, nmsUsername=nmsUsername, - nmsPassword=nmsPassword, - currentPolicies=provisionedNapPolicies) + nmsPassword=nmsPassword, + currentPolicies=provisionedNapPolicies) # If deploying a new configuration in GitOps mode start autosync if nmsSynctime == 0: diff --git a/src/v5_6/NIMUtils.py b/src/v5_6/NIMUtils.py index de1b9a96..aade4dfe 100644 --- a/src/v5_6/NIMUtils.py +++ b/src/v5_6/NIMUtils.py @@ -10,7 +10,7 @@ # Return None if not found def getNIMInstanceGroupUid(nmsUrl: str, nmsUsername: str, nmsPassword: str, instanceGroupName: str): # Retrieve instance group uid - ig = requests.get(url=f'{nmsUrl}/api/platform/v1/instance-groups', auth=(nmsUsername, nmsPassword), + ig = requests.get(url=f'{nmsUrl}/api/platform/v1/instance-groups?limit=100', auth=(nmsUsername, nmsPassword), verify=False) if ig.status_code != 200: diff --git a/templates/v5.6/misc/server-http.tmpl b/templates/v5.6/misc/server-http.tmpl index c5fdccd8..00028a3d 100644 --- a/templates/v5.6/misc/server-http.tmpl +++ b/templates/v5.6/misc/server-http.tmpl @@ -83,7 +83,7 @@ server { {%- 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 -%} + {% 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 %} From a3c309b39bb95c13aafc7d79839cecb0a30f85aa Mon Sep 17 00:00:00 2001 From: Fabrizio Fiorucci Date: Tue, 5 May 2026 11:40:44 +0100 Subject: [PATCH 04/12] v5.6 initial commit --- src/V5_6_CreateConfig.py | 36 ++++++++++++++++++------------------ src/v5_6/NIMNAPUtils.py | 2 -- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/V5_6_CreateConfig.py b/src/V5_6_CreateConfig.py index 7948f01d..3f08250d 100644 --- a/src/V5_6_CreateConfig.py +++ b/src/V5_6_CreateConfig.py @@ -101,7 +101,7 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn 'name': configFileName} all_resolver_profiles.append(resolver_profile['name']) - auxFiles['files'].append(resolverProfileConfigFile) + configFiles['files'].append(resolverProfileConfigFile) if 'http' in d['declaration']: if 'snippet' in d['declaration']['http']: @@ -145,7 +145,7 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn upstreamProfileConfigFile = {'contents': b64renderedUpstreamProfile, 'name': configFileName} - auxFiles['files'].append(upstreamProfileConfigFile) + configFiles['files'].append(upstreamProfileConfigFile) all_upstreams.append(http['upstreams'][i]['name']) http = d['declaration']['http'] @@ -194,7 +194,7 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn 'name': configFileName } all_auth_client_profiles.append(auth_profile['name']) - auxFiles['files'].append(authProfileConfigFile) + configFiles['files'].append(authProfileConfigFile) # Add the rendered authentication configuration snippet as a config file in the staged configuration - jwks template templateName = NcgConfig.config['templates']['auth_client_root']+"/jwks.tmpl" @@ -206,7 +206,7 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn authProfileConfigFile = {'contents': b64renderedClientAuthProfile, 'name': configFileName } - auxFiles['files'].append(authProfileConfigFile) + configFiles['files'].append(authProfileConfigFile) case 'mtls': # Add the rendered authentication configuration snippet as a config file in the staged configuration - mTLS template @@ -222,7 +222,7 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn 'name': configFileName} all_auth_client_profiles.append(auth_profile['name']) - auxFiles['files'].append(authProfileConfigFile) + configFiles['files'].append(authProfileConfigFile) case 'oidc': # Add the rendered authentication configuration snippet as a config file in the staged configuration - OpenID Connect template @@ -238,7 +238,7 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn 'name': configFileName} all_auth_client_profiles.append(auth_profile['name']) - auxFiles['files'].append(authProfileConfigFile) + configFiles['files'].append(authProfileConfigFile) if 'server' in d_auth_profiles: # Render all server authentication profiles @@ -260,7 +260,7 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn 'name': configFileName } all_auth_server_profiles.append(auth_profile['name']) - auxFiles['files'].append(authProfileConfigFile) + configFiles['files'].append(authProfileConfigFile) case 'mtls': # Add the rendered authentication configuration snippet as a config file in the staged configuration - mTLS template @@ -276,7 +276,7 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn 'name': configFileName} all_auth_server_profiles.append(auth_profile['name']) - auxFiles['files'].append(authProfileConfigFile) + configFiles['files'].append(authProfileConfigFile) # Check authorization profiles validity and creates authorization config files @@ -304,7 +304,7 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn 'name': configFileName } all_authz_client_profiles.append(authz_profile['name']) - auxFiles['files'].append(authProfileConfigFile) + configFiles['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" @@ -318,7 +318,7 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn authProfileConfigFile = {'contents': b64renderedClientAuthProfile, 'name': configFileName} - auxFiles['files'].append(authProfileConfigFile) + configFiles['files'].append(authProfileConfigFile) # NGINX Javascript profiles all_njs_profiles = [] @@ -361,7 +361,7 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn 'name': configFileName} all_acme_issuers.append(acme_issuer['name']) - auxFiles['files'].append(acmeProfileConfigFile) + configFiles['files'].append(acmeProfileConfigFile) # HTTP level Javascript hooks d_http_njs_hooks = v5_6.MiscUtils.getDictKey(d, 'declaration.http.njs') @@ -465,7 +465,7 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn httpServerConfb64 = base64.b64encode(bytes(httpServerConf, 'utf-8')).decode('utf-8') newHttpServerAuxFile = {'contents': httpServerConfb64, 'name': NcgConfig.config['nms']['server_http_dir'] + '/' + server['name'].replace(' ', '_') + ".conf"} - auxFiles['files'].append(newHttpServerAuxFile) + configFiles['files'].append(newHttpServerAuxFile) for loc in server['locations']: @@ -547,7 +547,7 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn 'visibility_dir'] + loc['uri'] + "-moesif-http.conf"} - auxFiles['files'].append(moesifHTTPConfigFile) + configFiles['files'].append(moesifHTTPConfigFile) # Add the rendered Moesif visibility configuration snippet as a config file in the staged configuration - server context templateName = NcgConfig.config['templates'][ @@ -563,7 +563,7 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn 'visibility_dir'] + loc['uri'] + "-moesif-server.conf"} - auxFiles['files'].append(moesifServerConfigFile) + configFiles['files'].append(moesifServerConfigFile) # API Gateway provisioning if loc['apigateway'] and loc['apigateway']['api_gateway'] and loc['apigateway']['api_gateway']['enabled'] and loc['apigateway']['api_gateway']['enabled'] == True: @@ -623,7 +623,7 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn newAuxFile = {'contents': apiGatewaySnippetb64, 'name': NcgConfig.config['nms']['apigw_dir'] + '/' + server['names'][0] + loc['uri'] + ".conf" } - auxFiles['files'].append(newAuxFile) + configFiles['files'].append(newAuxFile) # API Gateway maps file for parameters enforcement apiGatewayMapsSnippet = j2_env.get_template(NcgConfig.config['templates']['apigwmapsconf']).render( @@ -633,7 +633,7 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn newAuxFile = {'contents': apiGatewayMapsSnippetb64, 'name': NcgConfig.config['nms']['apigw_maps_dir'] + '/' + server['names'][0] + loc['uri'].replace('/', '_') + ".conf" } - auxFiles['files'].append(newAuxFile) + configFiles['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: @@ -725,7 +725,7 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn upstreamProfileConfigFile = {'contents': b64renderedUpstreamProfile, 'name': configFileName} - auxFiles['files'].append(upstreamProfileConfigFile) + configFiles['files'].append(upstreamProfileConfigFile) all_upstreams.append(d_upstreams[i]['name']) @@ -761,7 +761,7 @@ def createconfig(declaration: ConfigDeclaration, apiversion: str, runfromautosyn streamServerConfb64 = base64.b64encode(bytes(streamServerConf, 'utf-8')).decode('utf-8') newStreamServerAuxFile = {'contents': streamServerConfb64, 'name': NcgConfig.config['nms']['server_stream_dir'] + '/' + server['name'].replace(' ', '_') + ".conf"} - auxFiles['files'].append(newStreamServerAuxFile) + configFiles['files'].append(newStreamServerAuxFile) # HTTP configuration template rendering httpConf = j2_env.get_template(NcgConfig.config['templates']['httpconf']).render( diff --git a/src/v5_6/NIMNAPUtils.py b/src/v5_6/NIMNAPUtils.py index 57acc74f..4971ee00 100644 --- a/src/v5_6/NIMNAPUtils.py +++ b/src/v5_6/NIMNAPUtils.py @@ -246,8 +246,6 @@ def makePolicyActive(nmsUrl: str, nmsUsername: str, nmsPassword: str, activePoli r = requests.post(url=f'{nmsUrl}/api/platform/v1/security/publish', auth=(nmsUsername, nmsPassword), data=json.dumps(body), headers={'Content-Type': 'application/json'}, verify=False) - print(f"WAF policy publish {policyName} {body} -> {r.status_code} {r.text}") - return doWeHavePolicies From cf1188b63d0ac5e3647f3c2665842e570c218b9e Mon Sep 17 00:00:00 2001 From: Fabrizio Fiorucci Date: Tue, 5 May 2026 17:25:00 +0100 Subject: [PATCH 05/12] Postman collection updated, USAGE-v5.6 updated, bugfixes --- USAGE-v5.6.md | 36 ++-- ...NX Declarative API.postman_collection.json | 167 ++++++++++-------- src/v5_6/DeclarationPatcher.py | 4 +- src/v5_6/NGINXOneNAPUtils.py | 99 ++++++----- src/v5_6/NGINXOneOutput.py | 12 +- src/v5_6/NIMOutput.py | 4 +- 6 files changed, 174 insertions(+), 148 deletions(-) diff --git a/USAGE-v5.6.md b/USAGE-v5.6.md index 22ad88fc..6aee0d26 100644 --- a/USAGE-v5.6.md +++ b/USAGE-v5.6.md @@ -26,19 +26,6 @@ The JSON schema is self explanatory. See also the [sample Postman collection](/c - `.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.synchronous` **optional**, when set to `True` (default) the NGINX Declarative API waits for NGINX Instance Manager successful reply after publishing the NGINX configuration. Setting this to `False` enqueues the request, supporting multiple JSON declarations to be submitted at the same time/from multiple clients. Currently supported for `PATCH` operations only. - `.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 - *nginxone* - NGINX configuration is published to a NGINX One Console config sync group - `.output.nginxone.url` the NGINX One Console URL - `.output.nginxone.namespace` the NGINX One Console namespace @@ -47,14 +34,23 @@ The JSON schema is self explanatory. See also the [sample Postman collection](/c - `.output.nginxone.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 One Cloud Console - `.output.nms.synchronous` **optional**, when set to `True` (default) the NGINX Declarative API waits for NGINX One Console successful reply after publishing the NGINX configuration. Setting this to `False` enqueues the request, supporting multiple JSON declarations to be submitted at the same time/from multiple clients. Currently supported for `PATCH` operations only. - `.output.nginxone.modules` an optional array of NGINX module names (ie. 'ngx_http_app_protect_module', 'ngx_http_js_module','ngx_stream_js_module') - - `.output.nginxone.certificates` an optional array of TLS certificates/keys/chains to be published - - `.output.nginxone.certificates[].type` the item type ('certificate', 'key', 'chain') - - `.output.nginxone.certificates[].name` the certificate/key/chain name with no path/extension (ie. 'test-application') - - `.output.nginxone.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 - `.declaration` describes the NGINX configuration to be created - - `.declaration.http[]` NGINX HTTP definitions - - `.declaration.layer4[]` NGINX TCP/UDP definitions - - `.declaration.resolvers[]` DNS resolvers definitions + - `.declaration.http` NGINX HTTP definitions + - `.declaration.http.certificates` an optional array of TLS certificates/keys/chains to be published + - `.declaration.http.certificates[].type` the item type ('certificate', 'key', 'chain') + - `.declaration.http.certificates[].name` the certificate/key/chain name with no path/extension (ie. 'test-application') + - `.declaration.http.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 + - `.declaration.http.policies[]` an optional array of NGINX App Protect security policies + - `.declaration.http.policies[].type` the policy type ('app_protect') + - `.declaration.http.policies[].name` the policy name (ie. 'prod-policy') + - `.declaration.http.policies[].active_tag` the policy tag to enable among all available versions (ie. 'v1') + - `.declaration.http.policies[].versions[]` array with all available policy versions + - `.declaration.http.policies[].versions[].tag` the policy version's tag name + - `.declaration.http.policies[].versions[].displayName` the policy version's display name + - `.declaration.http.policies[].versions[].description` the policy version's description + - `.declaration.http.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.layer4` NGINX TCP/UDP definitions + - `.declaration.resolvers` DNS resolvers definitions ### API endpoints diff --git a/contrib/postman/NGINX Declarative API.postman_collection.json b/contrib/postman/NGINX Declarative API.postman_collection.json index f5099b82..78e1cc87 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": "6fc2a74f-7e06-45e7-806b-1f9953d905c2", + "_postman_id": "6bcfa8d2-a3c5-4659-9255-c951d40420c5", "name": "NGINX Declarative API", "description": "Declarative REST API and GitOps automation layer for NGINX Instance Manager and NGINX One Console\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-6fc2a74f-7e06-45e7-806b-1f9953d905c2?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-6bcfa8d2-a3c5-4659-9255-c951d40420c5?action=share&source=collection_link&creator=1667416" }, "item": [ { - "name": "v5.4", + "name": "v5.5", "item": [ { "name": "NGINX Instance Manager", @@ -2053,7 +2053,7 @@ "response": [] }, { - "name": "TLS Offload and NGINX App Protect", + "name": "TLS Offload and F5 WAF for NGINX", "event": [ { "listen": "test", @@ -5449,7 +5449,7 @@ "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)" }, { - "name": "v5.5", + "name": "v5.6", "item": [ { "name": "NGINX Instance Manager", @@ -5471,7 +5471,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -5480,7 +5481,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_acme_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"cacert\",\n \"contents\": {\n \"content\": \"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZjekNDQTF1Z0F3SUJBZ0lVVnNRZkFaTW4vazNRTU9nc0RuVEdUaU9PbGJ3d0RRWUpLb1pJaHZjTkFRRUwKQlFBd1NURUxNQWtHQTFVRUJoTUNTVlF4RFRBTEJnTlZCQWdNQkVGemRHa3hFVEFQQmdOVkJBb01DRlJsYzNRZwpUR0ZpTVJnd0ZnWURWUVFEREE5MmJTMWliR0Z1YXk1bVppNXNZVzR3SGhjTk1qTXdOakE0TURrMU5EQTRXaGNOCk1qUXdOakEzTURrMU5EQTRXakJKTVFzd0NRWURWUVFHRXdKSlZERU5NQXNHQTFVRUNBd0VRWE4wYVRFUk1BOEcKQTFVRUNnd0lWR1Z6ZENCTVlXSXhHREFXQmdOVkJBTU1EM1p0TFdKc1lXNXJMbVptTG14aGJqQ0NBaUl3RFFZSgpLb1pJaHZjTkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFLMlQwWXpkcjB0dWQzaVJRNGNzaGNhRVJTRzVjTDE2CkhRblhoYWw4emlUL1VRQUNIUGdzZDYwcWlEaldvQTJXb0lGWFFpUHkzOG1vZGtWRlR4Qmt5U2VldndOOFJiLzEKOFhaMS8yS1RnVmRDcHkvNm11WE15bXZYODJad05CVkV3QnoxUk5kbklUSk44cVh3a0d4bHozbDBib1loRkFyUQpNdmkxcW1RaHpDa2Zpb041MVkrYlBXOXpTQlFQdXNrcXJYYzRqTTJ0VENNQ2pTcFlvd1hXM1ppRmc5WEJ1Z09aCjFmdWd1Zmw4K1FJYzNZSEFoL1Z1NloraXFEOGxQeGRKODlBeDZaazVtOGdkVG9JdUhBbUNWaHFpUXBGRjkzSTgKbkYrSnRuYnBaNTRJUTZBbWYrYiswakMxdmY4Kzg0WUppaEVzWExyaGMxZTRTZ2dwdzEvcWpDb21QblhGVjEzUwpsUG5kVlhVR0taa1ZKdXdZTjJyZElmd3YrdCs5MGhwUVBmNmFBTjRCamRxOXdkdkQzSXVnS2JYZG5CQ0FUTEY4ClYyRTFTSE9VZGdRY3duK1d1WDVVOGdPa3B2b2VFN0g1REJ6Rks1WTZ2SHZlaTRlNkp3RTRDK3FJL1BmbTgreTEKNEpsOFBSOW5JQmdGQ3hrZWpwa2tRQ0I5U0dvMVZidzZhWmdZd0VQNHh6YXFYYXV3L3F4c0oxNUkrRTBndEs1OApuWUtkM0hqelk5Slh6V0NVNTdXbmc2SzNvTTIzNXpyRzJnNm1FaHQ4SStDckVMUFNuZURjZU8zVlJkc2dlblBCCis4U1JxVU8vWG9LWHNEU3I5amoxdWluVzYwTG5MZ0Zmc3JQeGlQVlZlMFh1TFZESlhCSlNoRDZDeGRyMnBSOGQKS25SRDZrTFpZZEtMQWdNQkFBR2pVekJSTUIwR0ExVWREZ1FXQkJRUzZnS2pMK3VFc0dXeXVjbTZyb0xVaXpqVwpWREFmQmdOVkhTTUVHREFXZ0JRUzZnS2pMK3VFc0dXeXVjbTZyb0xVaXpqV1ZEQVBCZ05WSFJNQkFmOEVCVEFECkFRSC9NQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUNBUUJad3B4Z2Z4N2thZFhvRHNyT1hUVXJ6dEFPMkFQRVJNaTAKaTkyNk9DTGFPbVVYZW1uKytXSUU1K2tUSE0wcS8vbUZCTURzSmdZSFVLUlNvRGNsNmh4TnVFNUNzS2trRVFTSgpMTHZrWlB0S2J5NGlxMitLZ1JtdVZxbXJNVTBYQzZMZDl3WmttL2huUjNtT3V6bko4MGZmV1JDQ0xGWDEwY2EzCnc5TGM1d1JLTFBZZXQvcEs5SitOYWN3TFJRYTczVFovMUpQNW9BU3czVjNoYkxlLy9UeWpnOURqUlZGY3FYWnEKWWs2Mm5qSkhZVzh3WmlhZzc0QXU4dHE5OG5KandBV1ROMFV5L2w1Q2VpWnV5bzZlU0RHVDNJNm1BdGU1VXBvWAppNXBkYlZ6VDdOZC9IOEwwZHZNdVZ2N0FmakZlcU91cUZNNkkzTnlvbStLWENxNmJQdGxBWEkzeVFZc0t4ZlRkCkw3SnRaTmx6MGJ6eHJhcHI4RmpYcjhML1ZkeHQza00xMnJwb2kzL3hsckR6Q2Q2b2YrQ1MxelBocUdpOUhvcUoKZEU5VGhYMklTdkd2akVSYzVVNFRsNjJBNHNyeGJQbUt0eWx3dGNGVEJacUJiRGY3ZjBBc2cveWhndXdTcktsQQpBNkRWVXVCRFErdGpwZ0N0b0ZlOEhLVDJ6UFVlaEQ2ZjVNQkhmU2ZUZ1crTlhFSXNvVDNsampjY1hsYXhPcFJWCkNQNWxCczNmekxyYnBxbUlLaWZhdWlTNWM4TzlSUjhjQTVzeWlBOTBmbmJIdDlmdGxpRG9jcFRzNUtrbjk2NkIKZUxMM1dXVldCYUtvanJzY1RkVXJoalNnVVBmam5FTXpnVzR2eEc3d3BVNHR2ME4yaEtHUWc0bVhhcDV0SU5Pcwp4WktnZXRHUldnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=\"\n }\n }\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"resolver\": \"Google\",\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 \"acme_issuer\": \"ACME example issuer\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"acme_issuers\": [\n {\n \"name\": \"ACME example issuer\",\n \"uri\": \"https://acme.example.com/directory\",\n \"contact\": \"admin@example.test\",\n \"account_key\": \"rsa:2048\",\n \"ssl_verify\": true,\n \"ssl_trusted_certificate\": \"cacert\",\n \"accept_terms_of_service\": true\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\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_acme_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"resolver\": \"Google\",\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 \"acme_issuer\": \"ACME example issuer\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"acme_issuers\": [\n {\n \"name\": \"ACME example issuer\",\n \"uri\": \"https://acme.example.com/directory\",\n \"contact\": \"admin@example.test\",\n \"account_key\": \"rsa:2048\",\n \"ssl_verify\": true,\n \"ssl_trusted_certificate\": \"cacert\",\n \"accept_terms_of_service\": true\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"cacert\",\n \"contents\": {\n \"content\": \"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZjekNDQTF1Z0F3SUJBZ0lVVnNRZkFaTW4vazNRTU9nc0RuVEdUaU9PbGJ3d0RRWUpLb1pJaHZjTkFRRUwKQlFBd1NURUxNQWtHQTFVRUJoTUNTVlF4RFRBTEJnTlZCQWdNQkVGemRHa3hFVEFQQmdOVkJBb01DRlJsYzNRZwpUR0ZpTVJnd0ZnWURWUVFEREE5MmJTMWliR0Z1YXk1bVppNXNZVzR3SGhjTk1qTXdOakE0TURrMU5EQTRXaGNOCk1qUXdOakEzTURrMU5EQTRXakJKTVFzd0NRWURWUVFHRXdKSlZERU5NQXNHQTFVRUNBd0VRWE4wYVRFUk1BOEcKQTFVRUNnd0lWR1Z6ZENCTVlXSXhHREFXQmdOVkJBTU1EM1p0TFdKc1lXNXJMbVptTG14aGJqQ0NBaUl3RFFZSgpLb1pJaHZjTkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFLMlQwWXpkcjB0dWQzaVJRNGNzaGNhRVJTRzVjTDE2CkhRblhoYWw4emlUL1VRQUNIUGdzZDYwcWlEaldvQTJXb0lGWFFpUHkzOG1vZGtWRlR4Qmt5U2VldndOOFJiLzEKOFhaMS8yS1RnVmRDcHkvNm11WE15bXZYODJad05CVkV3QnoxUk5kbklUSk44cVh3a0d4bHozbDBib1loRkFyUQpNdmkxcW1RaHpDa2Zpb041MVkrYlBXOXpTQlFQdXNrcXJYYzRqTTJ0VENNQ2pTcFlvd1hXM1ppRmc5WEJ1Z09aCjFmdWd1Zmw4K1FJYzNZSEFoL1Z1NloraXFEOGxQeGRKODlBeDZaazVtOGdkVG9JdUhBbUNWaHFpUXBGRjkzSTgKbkYrSnRuYnBaNTRJUTZBbWYrYiswakMxdmY4Kzg0WUppaEVzWExyaGMxZTRTZ2dwdzEvcWpDb21QblhGVjEzUwpsUG5kVlhVR0taa1ZKdXdZTjJyZElmd3YrdCs5MGhwUVBmNmFBTjRCamRxOXdkdkQzSXVnS2JYZG5CQ0FUTEY4ClYyRTFTSE9VZGdRY3duK1d1WDVVOGdPa3B2b2VFN0g1REJ6Rks1WTZ2SHZlaTRlNkp3RTRDK3FJL1BmbTgreTEKNEpsOFBSOW5JQmdGQ3hrZWpwa2tRQ0I5U0dvMVZidzZhWmdZd0VQNHh6YXFYYXV3L3F4c0oxNUkrRTBndEs1OApuWUtkM0hqelk5Slh6V0NVNTdXbmc2SzNvTTIzNXpyRzJnNm1FaHQ4SStDckVMUFNuZURjZU8zVlJkc2dlblBCCis4U1JxVU8vWG9LWHNEU3I5amoxdWluVzYwTG5MZ0Zmc3JQeGlQVlZlMFh1TFZESlhCSlNoRDZDeGRyMnBSOGQKS25SRDZrTFpZZEtMQWdNQkFBR2pVekJSTUIwR0ExVWREZ1FXQkJRUzZnS2pMK3VFc0dXeXVjbTZyb0xVaXpqVwpWREFmQmdOVkhTTUVHREFXZ0JRUzZnS2pMK3VFc0dXeXVjbTZyb0xVaXpqV1ZEQVBCZ05WSFJNQkFmOEVCVEFECkFRSC9NQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUNBUUJad3B4Z2Z4N2thZFhvRHNyT1hUVXJ6dEFPMkFQRVJNaTAKaTkyNk9DTGFPbVVYZW1uKytXSUU1K2tUSE0wcS8vbUZCTURzSmdZSFVLUlNvRGNsNmh4TnVFNUNzS2trRVFTSgpMTHZrWlB0S2J5NGlxMitLZ1JtdVZxbXJNVTBYQzZMZDl3WmttL2huUjNtT3V6bko4MGZmV1JDQ0xGWDEwY2EzCnc5TGM1d1JLTFBZZXQvcEs5SitOYWN3TFJRYTczVFovMUpQNW9BU3czVjNoYkxlLy9UeWpnOURqUlZGY3FYWnEKWWs2Mm5qSkhZVzh3WmlhZzc0QXU4dHE5OG5KandBV1ROMFV5L2w1Q2VpWnV5bzZlU0RHVDNJNm1BdGU1VXBvWAppNXBkYlZ6VDdOZC9IOEwwZHZNdVZ2N0FmakZlcU91cUZNNkkzTnlvbStLWENxNmJQdGxBWEkzeVFZc0t4ZlRkCkw3SnRaTmx6MGJ6eHJhcHI4RmpYcjhML1ZkeHQza00xMnJwb2kzL3hsckR6Q2Q2b2YrQ1MxelBocUdpOUhvcUoKZEU5VGhYMklTdkd2akVSYzVVNFRsNjJBNHNyeGJQbUt0eWx3dGNGVEJacUJiRGY3ZjBBc2cveWhndXdTcktsQQpBNkRWVXVCRFErdGpwZ0N0b0ZlOEhLVDJ6UFVlaEQ2ZjVNQkhmU2ZUZ1crTlhFSXNvVDNsampjY1hsYXhPcFJWCkNQNWxCczNmekxyYnBxbUlLaWZhdWlTNWM4TzlSUjhjQTVzeWlBOTBmbmJIdDlmdGxpRG9jcFRzNUtrbjk2NkIKZUxMM1dXVldCYUtvanJzY1RkVXJoalNnVVBmam5FTXpnVzR2eEc3d3BVNHR2ME4yaEtHUWc0bVhhcDV0SU5Pcwp4WktnZXRHUldnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=\"\n }\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -5850,7 +5851,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -5859,7 +5861,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 \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -5895,7 +5897,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -5904,7 +5907,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 \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -5940,7 +5943,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -5949,7 +5953,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 \"ndk_http_module\",\n \"ngx_http_lua_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\n },\n \"visibility\": [\n {\n \"enabled\": true,\n \"type\": \"moesif\",\n \"moesif\": {\n \"application_id\": \"{{moesif_application_id}}\"\n }\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\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 \"ndk_http_module\",\n \"ngx_http_lua_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\n },\n \"visibility\": [\n {\n \"enabled\": true,\n \"type\": \"moesif\",\n \"moesif\": {\n \"application_id\": \"{{moesif_application_id}}\"\n }\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -5985,7 +5989,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -5994,7 +5999,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 ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\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 },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -6030,7 +6035,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -6039,7 +6045,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 ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"syslog:server=192.168.2.13:514\"\n },\n \"error\": {\n \"destination\": \"syslog:server=192.168.2.13:514\"\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 }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\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 },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"syslog:server=192.168.2.13:514\"\n },\n \"error\": {\n \"destination\": \"syslog:server=192.168.2.13:514\"\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 }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -6075,7 +6081,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -6084,7 +6091,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 \"ndk_http_module\",\n \"ngx_http_lua_module\",\n \"ngx_http_app_protect_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"cache\": {\n \"profile\": \"10m cache\",\n \"key\": \"$uri\",\n \"validity\": [\n {\n \"code\": \"200\",\n \"ttl\": \"5s\"\n }\n ]\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": false,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\n },\n \"visibility\": [\n {\n \"enabled\": true,\n \"type\": \"moesif\",\n \"moesif\": {\n \"application_id\": \"{{moesif_application_id}}\"\n }\n }\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 \"cache\": [\n {\n \"profile\": \"10m cache\",\n \"key\": \"$http_method$uri\",\n \"validity\": [\n {\n \"code\": \"any\",\n \"ttl\": \"30s\"\n },\n {\n \"code\": \"302\",\n \"ttl\": \"5m\"\n }\n ],\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/store/inventory\"\n ]\n }\n ]\n },\n \"cache\": {\n \"profile\": \"10m cache\",\n \"key\": \"$http_method$uri\",\n \"validity\": [\n {\n \"code\": \"any\",\n \"ttl\": \"30s\"\n },\n {\n \"code\": \"302\",\n \"ttl\": \"5m\"\n }\n ]\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"cache\": [\n {\n \"name\": \"10m cache\",\n \"basepath\": \"/tmp\",\n \"size\": \"10m\",\n \"ttl\": \"10m\"\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\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 \"ndk_http_module\",\n \"ngx_http_lua_module\",\n \"ngx_http_app_protect_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"cache\": {\n \"profile\": \"10m cache\",\n \"key\": \"$uri\",\n \"validity\": [\n {\n \"code\": \"200\",\n \"ttl\": \"5s\"\n }\n ]\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": false,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\n },\n \"visibility\": [\n {\n \"enabled\": true,\n \"type\": \"moesif\",\n \"moesif\": {\n \"application_id\": \"{{moesif_application_id}}\"\n }\n }\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 \"cache\": [\n {\n \"profile\": \"10m cache\",\n \"key\": \"$http_method$uri\",\n \"validity\": [\n {\n \"code\": \"any\",\n \"ttl\": \"30s\"\n },\n {\n \"code\": \"302\",\n \"ttl\": \"5m\"\n }\n ],\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/store/inventory\"\n ]\n }\n ]\n },\n \"cache\": {\n \"profile\": \"10m cache\",\n \"key\": \"$http_method$uri\",\n \"validity\": [\n {\n \"code\": \"any\",\n \"ttl\": \"30s\"\n },\n {\n \"code\": \"302\",\n \"ttl\": \"5m\"\n }\n ]\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"cache\": [\n {\n \"name\": \"10m cache\",\n \"basepath\": \"/tmp\",\n \"size\": \"10m\",\n \"ttl\": \"10m\"\n }\n ],\n ,\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -6438,7 +6445,7 @@ "response": [] }, { - "name": "5. Get declaration Copy", + "name": "5. Get declaration", "event": [ { "listen": "test", @@ -6913,7 +6920,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -6922,7 +6930,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\": 5,\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\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\": 5\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n }\n}", "options": { "raw": { "language": "json" @@ -6945,7 +6953,7 @@ "response": [] }, { - "name": "NGINX App Protect WAF and GitOps", + "name": "F5 WAF for NGINX and GitOps", "event": [ { "listen": "test", @@ -6958,7 +6966,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -6967,7 +6976,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\": 5,\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}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.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}}/{{ngc_api_version}}/nap-policy-gitops.json\"\n }\n }\n ]\n }\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\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\": 5,\n \"modules\": [\n \"ngx_http_app_protect_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.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}}/{{ngc_api_version}}/nap-policy-gitops.json\"\n }\n }\n ]\n }\n ]\n }\n }\n}", "options": { "raw": { "language": "json" @@ -7461,7 +7470,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -7470,7 +7480,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 \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n }\n}", "options": { "raw": { "language": "json" @@ -7506,7 +7516,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -7515,7 +7526,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 ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-blocked.json\"\n }\n }\n ]\n }\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\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 },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-blocked.json\"\n }\n }\n ]\n }\n ]\n }\n }\n}", "options": { "raw": { "language": "json" @@ -7794,7 +7805,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -7803,7 +7815,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 \"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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"vm-blank.ff.lan\"\n ],\n \"resolver\": \"internal_lan\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"internal_lan\",\n \"address\": \"192.168.2.13\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"vm-blank.ff.lan\"\n ],\n \"resolver\": \"internal_lan\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\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 \"resolvers\": [\n {\n \"name\": \"internal_lan\",\n \"address\": \"192.168.2.13\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -7828,10 +7840,10 @@ ] }, { - "name": "NGINX App Protect WAF", + "name": "F5 WAF for NGINX", "item": [ { - "name": "Create initial NGINX configuration with NGINX App Protect WAF", + "name": "Create initial NGINX configuration with F5 WAF for NGINX", "event": [ { "listen": "test", @@ -7844,7 +7856,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -7853,7 +7866,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 ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\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 },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n }\n }\n}", "options": { "raw": { "language": "json" @@ -7876,7 +7889,7 @@ "response": [] }, { - "name": "Change active NGINX App Protect policy", + "name": "Change active F5 WAF for NGINX policy", "event": [ { "listen": "test", @@ -7889,7 +7902,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -7898,7 +7912,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 ],\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}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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 },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\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}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n }\n }\n}", "options": { "raw": { "language": "json" @@ -7935,7 +7949,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -7944,7 +7959,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 ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert2.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert2.key\"\n }\n }\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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 },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert2.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert2.key\"\n }\n }\n ]\n }\n }\n}", "options": { "raw": { "language": "json" @@ -7968,7 +7983,7 @@ "response": [] }, { - "name": "Disable NGINX App Protect WAF", + "name": "Disable F5 WAF for NGINX", "event": [ { "listen": "test", @@ -8177,7 +8192,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -8186,7 +8202,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 \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.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}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.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}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n }\n}", "options": { "raw": { "language": "json" @@ -8222,7 +8238,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -8231,7 +8248,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 \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.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}}/{{ngc_api_version}}/testcert.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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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}", + "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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.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}}/{{ngc_api_version}}/testcert.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}", "options": { "raw": { "language": "json" @@ -8327,7 +8344,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -8336,7 +8354,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_acme_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"cacert\",\n \"contents\": {\n \"content\": \"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZjekNDQTF1Z0F3SUJBZ0lVVnNRZkFaTW4vazNRTU9nc0RuVEdUaU9PbGJ3d0RRWUpLb1pJaHZjTkFRRUwKQlFBd1NURUxNQWtHQTFVRUJoTUNTVlF4RFRBTEJnTlZCQWdNQkVGemRHa3hFVEFQQmdOVkJBb01DRlJsYzNRZwpUR0ZpTVJnd0ZnWURWUVFEREE5MmJTMWliR0Z1YXk1bVppNXNZVzR3SGhjTk1qTXdOakE0TURrMU5EQTRXaGNOCk1qUXdOakEzTURrMU5EQTRXakJKTVFzd0NRWURWUVFHRXdKSlZERU5NQXNHQTFVRUNBd0VRWE4wYVRFUk1BOEcKQTFVRUNnd0lWR1Z6ZENCTVlXSXhHREFXQmdOVkJBTU1EM1p0TFdKc1lXNXJMbVptTG14aGJqQ0NBaUl3RFFZSgpLb1pJaHZjTkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFLMlQwWXpkcjB0dWQzaVJRNGNzaGNhRVJTRzVjTDE2CkhRblhoYWw4emlUL1VRQUNIUGdzZDYwcWlEaldvQTJXb0lGWFFpUHkzOG1vZGtWRlR4Qmt5U2VldndOOFJiLzEKOFhaMS8yS1RnVmRDcHkvNm11WE15bXZYODJad05CVkV3QnoxUk5kbklUSk44cVh3a0d4bHozbDBib1loRkFyUQpNdmkxcW1RaHpDa2Zpb041MVkrYlBXOXpTQlFQdXNrcXJYYzRqTTJ0VENNQ2pTcFlvd1hXM1ppRmc5WEJ1Z09aCjFmdWd1Zmw4K1FJYzNZSEFoL1Z1NloraXFEOGxQeGRKODlBeDZaazVtOGdkVG9JdUhBbUNWaHFpUXBGRjkzSTgKbkYrSnRuYnBaNTRJUTZBbWYrYiswakMxdmY4Kzg0WUppaEVzWExyaGMxZTRTZ2dwdzEvcWpDb21QblhGVjEzUwpsUG5kVlhVR0taa1ZKdXdZTjJyZElmd3YrdCs5MGhwUVBmNmFBTjRCamRxOXdkdkQzSXVnS2JYZG5CQ0FUTEY4ClYyRTFTSE9VZGdRY3duK1d1WDVVOGdPa3B2b2VFN0g1REJ6Rks1WTZ2SHZlaTRlNkp3RTRDK3FJL1BmbTgreTEKNEpsOFBSOW5JQmdGQ3hrZWpwa2tRQ0I5U0dvMVZidzZhWmdZd0VQNHh6YXFYYXV3L3F4c0oxNUkrRTBndEs1OApuWUtkM0hqelk5Slh6V0NVNTdXbmc2SzNvTTIzNXpyRzJnNm1FaHQ4SStDckVMUFNuZURjZU8zVlJkc2dlblBCCis4U1JxVU8vWG9LWHNEU3I5amoxdWluVzYwTG5MZ0Zmc3JQeGlQVlZlMFh1TFZESlhCSlNoRDZDeGRyMnBSOGQKS25SRDZrTFpZZEtMQWdNQkFBR2pVekJSTUIwR0ExVWREZ1FXQkJRUzZnS2pMK3VFc0dXeXVjbTZyb0xVaXpqVwpWREFmQmdOVkhTTUVHREFXZ0JRUzZnS2pMK3VFc0dXeXVjbTZyb0xVaXpqV1ZEQVBCZ05WSFJNQkFmOEVCVEFECkFRSC9NQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUNBUUJad3B4Z2Z4N2thZFhvRHNyT1hUVXJ6dEFPMkFQRVJNaTAKaTkyNk9DTGFPbVVYZW1uKytXSUU1K2tUSE0wcS8vbUZCTURzSmdZSFVLUlNvRGNsNmh4TnVFNUNzS2trRVFTSgpMTHZrWlB0S2J5NGlxMitLZ1JtdVZxbXJNVTBYQzZMZDl3WmttL2huUjNtT3V6bko4MGZmV1JDQ0xGWDEwY2EzCnc5TGM1d1JLTFBZZXQvcEs5SitOYWN3TFJRYTczVFovMUpQNW9BU3czVjNoYkxlLy9UeWpnOURqUlZGY3FYWnEKWWs2Mm5qSkhZVzh3WmlhZzc0QXU4dHE5OG5KandBV1ROMFV5L2w1Q2VpWnV5bzZlU0RHVDNJNm1BdGU1VXBvWAppNXBkYlZ6VDdOZC9IOEwwZHZNdVZ2N0FmakZlcU91cUZNNkkzTnlvbStLWENxNmJQdGxBWEkzeVFZc0t4ZlRkCkw3SnRaTmx6MGJ6eHJhcHI4RmpYcjhML1ZkeHQza00xMnJwb2kzL3hsckR6Q2Q2b2YrQ1MxelBocUdpOUhvcUoKZEU5VGhYMklTdkd2akVSYzVVNFRsNjJBNHNyeGJQbUt0eWx3dGNGVEJacUJiRGY3ZjBBc2cveWhndXdTcktsQQpBNkRWVXVCRFErdGpwZ0N0b0ZlOEhLVDJ6UFVlaEQ2ZjVNQkhmU2ZUZ1crTlhFSXNvVDNsampjY1hsYXhPcFJWCkNQNWxCczNmekxyYnBxbUlLaWZhdWlTNWM4TzlSUjhjQTVzeWlBOTBmbmJIdDlmdGxpRG9jcFRzNUtrbjk2NkIKZUxMM1dXVldCYUtvanJzY1RkVXJoalNnVVBmam5FTXpnVzR2eEc3d3BVNHR2ME4yaEtHUWc0bVhhcDV0SU5Pcwp4WktnZXRHUldnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=\"\n }\n }\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"resolver\": \"Google\",\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 \"acme_issuer\": \"ACME example issuer\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"acme_issuers\": [\n {\n \"name\": \"ACME example issuer\",\n \"uri\": \"https://acme.example.com/directory\",\n \"contact\": \"admin@example.test\",\n \"account_key\": \"rsa:2048\",\n \"ssl_verify\": true,\n \"ssl_trusted_certificate\": \"cacert\",\n \"accept_terms_of_service\": true\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", + "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_acme_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"resolver\": \"Google\",\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 \"acme_issuer\": \"ACME example issuer\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"acme_issuers\": [\n {\n \"name\": \"ACME example issuer\",\n \"uri\": \"https://acme.example.com/directory\",\n \"contact\": \"admin@example.test\",\n \"account_key\": \"rsa:2048\",\n \"ssl_verify\": true,\n \"ssl_trusted_certificate\": \"cacert\",\n \"accept_terms_of_service\": true\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"cacert\",\n \"contents\": {\n \"content\": \"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZjekNDQTF1Z0F3SUJBZ0lVVnNRZkFaTW4vazNRTU9nc0RuVEdUaU9PbGJ3d0RRWUpLb1pJaHZjTkFRRUwKQlFBd1NURUxNQWtHQTFVRUJoTUNTVlF4RFRBTEJnTlZCQWdNQkVGemRHa3hFVEFQQmdOVkJBb01DRlJsYzNRZwpUR0ZpTVJnd0ZnWURWUVFEREE5MmJTMWliR0Z1YXk1bVppNXNZVzR3SGhjTk1qTXdOakE0TURrMU5EQTRXaGNOCk1qUXdOakEzTURrMU5EQTRXakJKTVFzd0NRWURWUVFHRXdKSlZERU5NQXNHQTFVRUNBd0VRWE4wYVRFUk1BOEcKQTFVRUNnd0lWR1Z6ZENCTVlXSXhHREFXQmdOVkJBTU1EM1p0TFdKc1lXNXJMbVptTG14aGJqQ0NBaUl3RFFZSgpLb1pJaHZjTkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFLMlQwWXpkcjB0dWQzaVJRNGNzaGNhRVJTRzVjTDE2CkhRblhoYWw4emlUL1VRQUNIUGdzZDYwcWlEaldvQTJXb0lGWFFpUHkzOG1vZGtWRlR4Qmt5U2VldndOOFJiLzEKOFhaMS8yS1RnVmRDcHkvNm11WE15bXZYODJad05CVkV3QnoxUk5kbklUSk44cVh3a0d4bHozbDBib1loRkFyUQpNdmkxcW1RaHpDa2Zpb041MVkrYlBXOXpTQlFQdXNrcXJYYzRqTTJ0VENNQ2pTcFlvd1hXM1ppRmc5WEJ1Z09aCjFmdWd1Zmw4K1FJYzNZSEFoL1Z1NloraXFEOGxQeGRKODlBeDZaazVtOGdkVG9JdUhBbUNWaHFpUXBGRjkzSTgKbkYrSnRuYnBaNTRJUTZBbWYrYiswakMxdmY4Kzg0WUppaEVzWExyaGMxZTRTZ2dwdzEvcWpDb21QblhGVjEzUwpsUG5kVlhVR0taa1ZKdXdZTjJyZElmd3YrdCs5MGhwUVBmNmFBTjRCamRxOXdkdkQzSXVnS2JYZG5CQ0FUTEY4ClYyRTFTSE9VZGdRY3duK1d1WDVVOGdPa3B2b2VFN0g1REJ6Rks1WTZ2SHZlaTRlNkp3RTRDK3FJL1BmbTgreTEKNEpsOFBSOW5JQmdGQ3hrZWpwa2tRQ0I5U0dvMVZidzZhWmdZd0VQNHh6YXFYYXV3L3F4c0oxNUkrRTBndEs1OApuWUtkM0hqelk5Slh6V0NVNTdXbmc2SzNvTTIzNXpyRzJnNm1FaHQ4SStDckVMUFNuZURjZU8zVlJkc2dlblBCCis4U1JxVU8vWG9LWHNEU3I5amoxdWluVzYwTG5MZ0Zmc3JQeGlQVlZlMFh1TFZESlhCSlNoRDZDeGRyMnBSOGQKS25SRDZrTFpZZEtMQWdNQkFBR2pVekJSTUIwR0ExVWREZ1FXQkJRUzZnS2pMK3VFc0dXeXVjbTZyb0xVaXpqVwpWREFmQmdOVkhTTUVHREFXZ0JRUzZnS2pMK3VFc0dXeXVjbTZyb0xVaXpqV1ZEQVBCZ05WSFJNQkFmOEVCVEFECkFRSC9NQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUNBUUJad3B4Z2Z4N2thZFhvRHNyT1hUVXJ6dEFPMkFQRVJNaTAKaTkyNk9DTGFPbVVYZW1uKytXSUU1K2tUSE0wcS8vbUZCTURzSmdZSFVLUlNvRGNsNmh4TnVFNUNzS2trRVFTSgpMTHZrWlB0S2J5NGlxMitLZ1JtdVZxbXJNVTBYQzZMZDl3WmttL2huUjNtT3V6bko4MGZmV1JDQ0xGWDEwY2EzCnc5TGM1d1JLTFBZZXQvcEs5SitOYWN3TFJRYTczVFovMUpQNW9BU3czVjNoYkxlLy9UeWpnOURqUlZGY3FYWnEKWWs2Mm5qSkhZVzh3WmlhZzc0QXU4dHE5OG5KandBV1ROMFV5L2w1Q2VpWnV5bzZlU0RHVDNJNm1BdGU1VXBvWAppNXBkYlZ6VDdOZC9IOEwwZHZNdVZ2N0FmakZlcU91cUZNNkkzTnlvbStLWENxNmJQdGxBWEkzeVFZc0t4ZlRkCkw3SnRaTmx6MGJ6eHJhcHI4RmpYcjhML1ZkeHQza00xMnJwb2kzL3hsckR6Q2Q2b2YrQ1MxelBocUdpOUhvcUoKZEU5VGhYMklTdkd2akVSYzVVNFRsNjJBNHNyeGJQbUt0eWx3dGNGVEJacUJiRGY3ZjBBc2cveWhndXdTcktsQQpBNkRWVXVCRFErdGpwZ0N0b0ZlOEhLVDJ6UFVlaEQ2ZjVNQkhmU2ZUZ1crTlhFSXNvVDNsampjY1hsYXhPcFJWCkNQNWxCczNmekxyYnBxbUlLaWZhdWlTNWM4TzlSUjhjQTVzeWlBOTBmbmJIdDlmdGxpRG9jcFRzNUtrbjk2NkIKZUxMM1dXVldCYUtvanJzY1RkVXJoalNnVVBmam5FTXpnVzR2eEc3d3BVNHR2ME4yaEtHUWc0bVhhcDV0SU5Pcwp4WktnZXRHUldnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=\"\n }\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -9120,7 +9138,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -9129,7 +9148,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", + "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": []\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -9165,7 +9184,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -9174,7 +9194,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"syslog:server=192.168.2.13:514\"\n },\n \"error\": {\n \"destination\": \"syslog:server=192.168.2.13: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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", + "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": []\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"syslog:server=192.168.2.13:514\"\n },\n \"error\": {\n \"destination\": \"syslog:server=192.168.2.13: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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -9210,7 +9230,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -9219,7 +9240,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ndk_http_module\",\n \"ngx_http_app_protect_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": false,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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 }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", + "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ndk_http_module\",\n \"ngx_http_app_protect_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": false,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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 }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -9255,7 +9276,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -9264,7 +9286,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", + "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": []\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -9300,7 +9322,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -9309,7 +9332,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ndk_http_module\",\n \"ngx_http_lua_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\n },\n \"visibility\": [\n {\n \"enabled\": true,\n \"type\": \"moesif\",\n \"moesif\": {\n \"application_id\": \"{{moesif_application_id}}\"\n }\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", + "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ndk_http_module\",\n \"ngx_http_lua_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\n },\n \"visibility\": [\n {\n \"enabled\": true,\n \"type\": \"moesif\",\n \"moesif\": {\n \"application_id\": \"{{moesif_application_id}}\"\n }\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -9345,7 +9368,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -9354,7 +9378,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ndk_http_module\",\n \"ngx_http_lua_module\"\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"cache\": {\n \"profile\": \"10m cache\",\n \"key\": \"$uri\",\n \"validity\": [\n {\n \"code\": \"200\",\n \"ttl\": \"5s\"\n }\n ]\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": false,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\n },\n \"visibility\": [\n {\n \"enabled\": true,\n \"type\": \"moesif\",\n \"moesif\": {\n \"application_id\": \"{{moesif_application_id}}\"\n }\n }\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 \"cache\": [\n {\n \"profile\": \"10m cache\",\n \"key\": \"$http_method$uri\",\n \"validity\": [\n {\n \"code\": \"any\",\n \"ttl\": \"30s\"\n },\n {\n \"code\": \"302\",\n \"ttl\": \"5m\"\n }\n ],\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/store/inventory\"\n ]\n }\n ]\n },\n \"cache\": {\n \"profile\": \"10m cache\",\n \"key\": \"$http_method$uri\",\n \"validity\": [\n {\n \"code\": \"any\",\n \"ttl\": \"30s\"\n },\n {\n \"code\": \"302\",\n \"ttl\": \"5m\"\n }\n ]\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"cache\": [\n {\n \"name\": \"10m cache\",\n \"basepath\": \"/tmp\",\n \"size\": \"10m\",\n \"ttl\": \"10m\"\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", + "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ndk_http_module\",\n \"ngx_http_lua_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"cache\": {\n \"profile\": \"10m cache\",\n \"key\": \"$uri\",\n \"validity\": [\n {\n \"code\": \"200\",\n \"ttl\": \"5s\"\n }\n ]\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": false,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\n },\n \"visibility\": [\n {\n \"enabled\": true,\n \"type\": \"moesif\",\n \"moesif\": {\n \"application_id\": \"{{moesif_application_id}}\"\n }\n }\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 \"cache\": [\n {\n \"profile\": \"10m cache\",\n \"key\": \"$http_method$uri\",\n \"validity\": [\n {\n \"code\": \"any\",\n \"ttl\": \"30s\"\n },\n {\n \"code\": \"302\",\n \"ttl\": \"5m\"\n }\n ],\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/store/inventory\"\n ]\n }\n ]\n },\n \"cache\": {\n \"profile\": \"10m cache\",\n \"key\": \"$http_method$uri\",\n \"validity\": [\n {\n \"code\": \"any\",\n \"ttl\": \"30s\"\n },\n {\n \"code\": \"302\",\n \"ttl\": \"5m\"\n }\n ]\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"cache\": [\n {\n \"name\": \"10m cache\",\n \"basepath\": \"/tmp\",\n \"size\": \"10m\",\n \"ttl\": \"10m\"\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -9769,7 +9793,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -9778,7 +9803,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n }\n }\n}", + "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n }\n}", "options": { "raw": { "language": "json" @@ -10272,7 +10297,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -10281,7 +10307,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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}", + "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n }\n}", "options": { "raw": { "language": "json" @@ -10560,7 +10586,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -10569,7 +10596,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"vm-blank.ff.lan\"\n ],\n \"resolver\": \"private DNS\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"resolvers\": [\n {\n \"name\": \"private DNS\",\n \"address\": \"192.168.2.13\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", + "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"vm-blank.ff.lan\"\n ],\n \"resolver\": \"private DNS\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"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 \"resolvers\": [\n {\n \"name\": \"private DNS\",\n \"address\": \"192.168.2.13\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -10755,7 +10782,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -10764,7 +10792,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\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}}/{{ngc_api_version}}/testcert.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}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.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}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n }\n}", "options": { "raw": { "language": "json" @@ -10800,7 +10828,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -10809,7 +10838,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\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}}/{{ngc_api_version}}/testcert.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}}/{{ngc_api_version}}/testcert.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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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}", + "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.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}}/{{ngc_api_version}}/testcert.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}", "options": { "raw": { "language": "json" diff --git a/src/v5_6/DeclarationPatcher.py b/src/v5_6/DeclarationPatcher.py index d5b6b593..41462008 100644 --- a/src/v5_6/DeclarationPatcher.py +++ b/src/v5_6/DeclarationPatcher.py @@ -170,14 +170,14 @@ def patchNAPPolicies(sourceDeclaration: dict, patchedNAPPolicies: dict): if 'policies' not in sourceDeclaration['declaration']['http']: return sourceDeclaration - # NGINX App Protect WAF policies patch + # F5 WAF for NGINX policies patch for p in sourceDeclaration['declaration']['http']['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 + # Patching an existing F5 WAF for NGINX 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 diff --git a/src/v5_6/NGINXOneNAPUtils.py b/src/v5_6/NGINXOneNAPUtils.py index 45d9e254..ea24b610 100644 --- a/src/v5_6/NGINXOneNAPUtils.py +++ b/src/v5_6/NGINXOneNAPUtils.py @@ -170,57 +170,58 @@ def provisionPolicies(nginxOneUrl: str, nginxOneToken: str, nginxOneNamespace: s # 'staging-policy': '7b4b850a-ff9e-42a0-85d0-850171474224' } all_policy_active_names_and_uids = {} - for p in declaration['output']['nginxone']['policies']: - policy_name = p['name'] - if policy_name: - policy_active_tag = p['active_tag'] - - # Iterates over all NGINX App Protect policies - if p['type'] == 'app_protect': - # Iterates over all policy versions - - # Remove pre-existing policy versions - allPoliciesJSON = __getAllPolicies__(nginxOneUrl=nginxOneUrl, nginxOneToken=nginxOneToken, nginxOneNamespace=nginxOneNamespace) - polId = __getPolicyId__(allPoliciesJSON = json.loads(allPoliciesJSON.text), policyName=policy_name) - if polId != "": - __deletePolicy__(nginxOneUrl=nginxOneUrl, nginxOneToken=nginxOneToken, nginxOneNamespace=nginxOneNamespace, policyUids=[polId]) - - # Create all policy versions - for policyVersion in p['versions']: - status, policyBody = v5_6.GitOps.getObjectFromRepo(policyVersion['contents'],base64Encode=False) - - if status != 200: - return JSONResponse( - status_code=422, - content={"code": status, - "details": policyBody['content']} + if 'http' in declaration['declaration'] and 'policies' in declaration['declaration']['http']: + for p in declaration['declaration']['http']['policies']: + policy_name = p['name'] + if policy_name: + policy_active_tag = p['active_tag'] + + # Iterates over all NGINX App Protect policies + if p['type'] == 'app_protect': + # Iterates over all policy versions + + # Remove pre-existing policy versions + allPoliciesJSON = __getAllPolicies__(nginxOneUrl=nginxOneUrl, nginxOneToken=nginxOneToken, nginxOneNamespace=nginxOneNamespace) + polId = __getPolicyId__(allPoliciesJSON = json.loads(allPoliciesJSON.text), policyName=policy_name) + if polId != "": + __deletePolicy__(nginxOneUrl=nginxOneUrl, nginxOneToken=nginxOneToken, nginxOneNamespace=nginxOneNamespace, policyUids=[polId]) + + # Create all policy versions + for policyVersion in p['versions']: + status, policyBody = v5_6.GitOps.getObjectFromRepo(policyVersion['contents'],base64Encode=False) + + if status != 200: + return JSONResponse( + status_code=422, + content={"code": status, + "details": policyBody['content']} + ) + + # Create the NGINX App Protect policy on NGINX One Console + r = __definePolicyOnNGINXOne__( + nginxOneUrl=nginxOneUrl, nginxOneToken=nginxOneToken, nginxOneNamespace=nginxOneNamespace, + policyJson=policyBody['content'] ) - # Create the NGINX App Protect policy on NGINX One Console - r = __definePolicyOnNGINXOne__( - nginxOneUrl=nginxOneUrl, nginxOneToken=nginxOneToken, nginxOneNamespace=nginxOneNamespace, - policyJson=policyBody['content'] - ) - - # Check for errors creating NGINX App Protect policy - if r.status_code != 201: - return JSONResponse( - status_code=r.status_code, - content={"code": r.status_code, "details": json.loads(r.text)} - ) - else: - # Policy was created, retrieve metadata.uid for each policy version - if policy_name not in all_policy_names_and_versions: - all_policy_names_and_versions[policy_name] = [] - - # Stores the policy version - uid = json.loads(r.text)['latest']['object_id'] - tag = policyVersion['tag'] - - if policy_active_tag == tag: - all_policy_active_names_and_uids[policy_name] = uid - - all_policy_names_and_versions[policy_name].append({'tag': tag, 'uid': uid}) + # Check for errors creating NGINX App Protect policy + if r.status_code != 201: + return JSONResponse( + status_code=r.status_code, + content={"code": r.status_code, "details": json.loads(r.text)} + ) + else: + # Policy was created, retrieve metadata.uid for each policy version + if policy_name not in all_policy_names_and_versions: + all_policy_names_and_versions[policy_name] = [] + + # Stores the policy version + uid = json.loads(r.text)['latest']['object_id'] + tag = policyVersion['tag'] + + if policy_active_tag == tag: + all_policy_active_names_and_uids[policy_name] = uid + + all_policy_names_and_versions[policy_name].append({'tag': tag, 'uid': uid}) return JSONResponse(status_code=200, content={"all_policy_names_and_versions": all_policy_names_and_versions, "all_policy_active_names_and_uids": all_policy_active_names_and_uids}) diff --git a/src/v5_6/NGINXOneOutput.py b/src/v5_6/NGINXOneOutput.py index 82a854bd..f4f288d1 100644 --- a/src/v5_6/NGINXOneOutput.py +++ b/src/v5_6/NGINXOneOutput.py @@ -70,7 +70,7 @@ def NGINXOneOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpCo "headers": {'Content-Type': 'application/json'}} # Fetch NGINX App Protect WAF policies from source of truth if needed - d_policies = v5_6.MiscUtils.getDictKey(d, 'output.nginxone.policies') + d_policies = v5_6.MiscUtils.getDictKey(d, 'declaration.http.policies') if d_policies is not None: for policy in d_policies: if 'versions' in policy: @@ -87,7 +87,7 @@ def NGINXOneOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpCo # Check TLS items validity all_tls = {'certificate': {}, 'key': {}} - d_certs = v5_6.MiscUtils.getDictKey(d, 'output.nginxone.certificates') + d_certs = v5_6.MiscUtils.getDictKey(d, 'declaration.http.certificates') if d_certs is not None: for i in range(len(d_certs)): if d_certs[i]['name']: @@ -146,10 +146,10 @@ def NGINXOneOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpCo issuer['name']) +"] must be one of [" + ",".join(all_tls['certificate']) + "]"} }} - # Add optional certificates specified under output.nginxone.certificates + # Add optional certificates specified under declaration.http.certificates extensions_map = {'certificate': '.crt', 'key': '.key'} - d_certificates = v5_6.MiscUtils.getDictKey(d, 'output.nginxone.certificates') + d_certificates = v5_6.MiscUtils.getDictKey(d, 'declaration.http.certificates') if d_certificates is not None: for c in d_certificates: status, certContent = v5_6.GitOps.getObjectFromRepo(object=c['contents'], @@ -163,7 +163,7 @@ def NGINXOneOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpCo '/' + c['name'] + extensions_map[c['type']]} auxFiles['files'].append(newAuxFile) - ### / Add optional certificates specified under output.nginxone.certificates + ### / Add optional certificates specified under declaration.http.certificates # NGINX main configuration file through template j2_env = Environment(loader=FileSystemLoader(NcgConfig.config['templates']['root_dir'] + '/' + apiversion), @@ -261,7 +261,7 @@ def NGINXOneOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpCo if ppReply.status_code >= 400: return {"status_code": ppReply.status_code, - "message": {"status_code": ppReply.status_code, "message": {"code": ppReply.status_code, "content": ppReply.content} }} + "message": {"status_code": ppReply.status_code, "message": {"code": ppReply.status_code, "content": json.loads(ppReply.body)['details']} }} napPolicies = json.loads(ppReply.body) provisionedNapPolicies = napPolicies['all_policy_names_and_versions'] diff --git a/src/v5_6/NIMOutput.py b/src/v5_6/NIMOutput.py index 3c52ab53..fb68ffe5 100644 --- a/src/v5_6/NIMOutput.py +++ b/src/v5_6/NIMOutput.py @@ -69,7 +69,7 @@ def NIMOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpConf: s "headers": {'Content-Type': 'application/json'}} # Fetch F5 WAF for NGINX WAF policies from source of truth if needed - d_policies = v5_6.MiscUtils.getDictKey(d, 'output.nms.policies') + d_policies = v5_6.MiscUtils.getDictKey(d, 'output.declaration.http.policies') if d_policies is not None: for policy in d_policies: if 'versions' in policy: @@ -261,7 +261,7 @@ def NIMOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpConf: s if ppReply.status_code >= 400: return {"status_code": ppReply.status_code, - "message": {"status_code": ppReply.status_code, "message": {"code": ppReply.status_code, "content": ppReply.content} }} + "message": {"status_code": ppReply.status_code, "message": {"code": ppReply.status_code, "content": json.loads(ppReply.body)['details']} }} napPolicies = json.loads(ppReply.body) provisionedNapPolicies = napPolicies['all_policy_names_and_versions'] From 6733e03c64d68d88e8342e1993a3eaeabed90748 Mon Sep 17 00:00:00 2001 From: Fabrizio Fiorucci Date: Tue, 5 May 2026 17:28:33 +0100 Subject: [PATCH 06/12] Postman collection updated, USAGE-v5.5/5.6 updated --- USAGE-v5.5.md | 1 + USAGE-v5.6.md | 11 +++++----- ...NX Declarative API.postman_collection.json | 20 +++++++++++++++++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/USAGE-v5.5.md b/USAGE-v5.5.md index 0e0aaf3e..e0b37887 100644 --- a/USAGE-v5.5.md +++ b/USAGE-v5.5.md @@ -58,6 +58,7 @@ The JSON schema is self explanatory. See also the [sample Postman collection](/c ### API endpoints +- `GET /v5.5/schema` - Get Declarative API JSON schema - `POST /v5.5/config/` - Publish a new declaration - `PATCH /v5.5/config/{config_uid}` - Update an existing declaration - Per-HTTP server CRUD diff --git a/USAGE-v5.6.md b/USAGE-v5.6.md index 6aee0d26..3c46f7d0 100644 --- a/USAGE-v5.6.md +++ b/USAGE-v5.6.md @@ -54,13 +54,14 @@ The JSON schema is self explanatory. See also the [sample Postman collection](/c ### API endpoints -- `POST /v5.5/config/` - Publish a new declaration -- `PATCH /v5.5/config/{config_uid}` - Update an existing declaration +- `GET /v5.6/schema` - Get Declarative API JSON schema +- `POST /v5.6/config/` - Publish a new declaration +- `PATCH /v5.6/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.5/config/{configUid}/submission/{submissionUid}` - Retrieve a submission (asynchronous `PATCH` request) status -- `GET /v5.5/config/{config_uid}` - Retrieve an existing declaration -- `DELETE /v5.5/config/{config_uid}` - Delete an existing declaration +- `GET /v5.6/config/{configUid}/submission/{submissionUid}` - Retrieve a submission (asynchronous `PATCH` request) status +- `GET /v5.6/config/{config_uid}` - Retrieve an existing declaration +- `DELETE /v5.6/config/{config_uid}` - Delete an existing declaration diff --git a/contrib/postman/NGINX Declarative API.postman_collection.json b/contrib/postman/NGINX Declarative API.postman_collection.json index 78e1cc87..b58c1122 100644 --- a/contrib/postman/NGINX Declarative API.postman_collection.json +++ b/contrib/postman/NGINX Declarative API.postman_collection.json @@ -10916,6 +10916,26 @@ } ], "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)" + }, + { + "name": "Get API schema", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/schema", + "protocol": "http", + "host": [ + "{{ncg_host}}" + ], + "port": "{{ncg_port}}", + "path": [ + "{{ngc_api_version}}", + "schema" + ] + } + }, + "response": [] } ], "event": [ From 77202da3342b1af21600a8a3bdfa8635b58a978f Mon Sep 17 00:00:00 2001 From: Fabrizio Fiorucci Date: Wed, 6 May 2026 15:27:43 +0100 Subject: [PATCH 07/12] Moved .declaration.http.certificates to .declaration.certificates --- USAGE-v5.5.md | 2 +- USAGE-v5.6.md | 10 +- ...NX Declarative API.postman_collection.json | 1516 +++++++++++------ src/V5_6_CreateConfig.py | 2 +- src/V5_6_NginxConfigDeclaration.py | 2 +- src/v5_6/NGINXOneOutput.py | 8 +- src/v5_6/NIMOutput.py | 8 +- 7 files changed, 1058 insertions(+), 490 deletions(-) diff --git a/USAGE-v5.5.md b/USAGE-v5.5.md index e0b37887..8d7da3a3 100644 --- a/USAGE-v5.5.md +++ b/USAGE-v5.5.md @@ -59,7 +59,7 @@ The JSON schema is self explanatory. See also the [sample Postman collection](/c ### API endpoints - `GET /v5.5/schema` - Get Declarative API JSON schema -- `POST /v5.5/config/` - Publish a new declaration +- `POST /v5.5/config` - Publish a new declaration - `PATCH /v5.5/config/{config_uid}` - Update an existing declaration - Per-HTTP server CRUD - Per-HTTP upstream CRUD diff --git a/USAGE-v5.6.md b/USAGE-v5.6.md index 3c46f7d0..b41c0bbb 100644 --- a/USAGE-v5.6.md +++ b/USAGE-v5.6.md @@ -36,10 +36,6 @@ The JSON schema is self explanatory. See also the [sample Postman collection](/c - `.output.nginxone.modules` an optional array of NGINX module names (ie. 'ngx_http_app_protect_module', 'ngx_http_js_module','ngx_stream_js_module') - `.declaration` describes the NGINX configuration to be created - `.declaration.http` NGINX HTTP definitions - - `.declaration.http.certificates` an optional array of TLS certificates/keys/chains to be published - - `.declaration.http.certificates[].type` the item type ('certificate', 'key', 'chain') - - `.declaration.http.certificates[].name` the certificate/key/chain name with no path/extension (ie. 'test-application') - - `.declaration.http.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 - `.declaration.http.policies[]` an optional array of NGINX App Protect security policies - `.declaration.http.policies[].type` the policy type ('app_protect') - `.declaration.http.policies[].name` the policy name (ie. 'prod-policy') @@ -51,11 +47,15 @@ The JSON schema is self explanatory. See also the [sample Postman collection](/c - `.declaration.http.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.layer4` NGINX TCP/UDP definitions - `.declaration.resolvers` DNS resolvers definitions + - `.declaration.certificates` an optional array of TLS certificates/keys/chains to be published + - `.declaration.certificates[].type` the item type ('certificate', 'key', 'chain') + - `.declaration.certificates[].name` the certificate/key/chain name with no path/extension (ie. 'test-application') + - `.declaration.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 ### API endpoints - `GET /v5.6/schema` - Get Declarative API JSON schema -- `POST /v5.6/config/` - Publish a new declaration +- `POST /v5.6/config` - Publish a new declaration - `PATCH /v5.6/config/{config_uid}` - Update an existing declaration - Per-HTTP server CRUD - Per-HTTP upstream CRUD diff --git a/contrib/postman/NGINX Declarative API.postman_collection.json b/contrib/postman/NGINX Declarative API.postman_collection.json index b58c1122..92420df3 100644 --- a/contrib/postman/NGINX Declarative API.postman_collection.json +++ b/contrib/postman/NGINX Declarative API.postman_collection.json @@ -5481,7 +5481,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_acme_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"resolver\": \"Google\",\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 \"acme_issuer\": \"ACME example issuer\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"acme_issuers\": [\n {\n \"name\": \"ACME example issuer\",\n \"uri\": \"https://acme.example.com/directory\",\n \"contact\": \"admin@example.test\",\n \"account_key\": \"rsa:2048\",\n \"ssl_verify\": true,\n \"ssl_trusted_certificate\": \"cacert\",\n \"accept_terms_of_service\": true\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"cacert\",\n \"contents\": {\n \"content\": \"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZjekNDQTF1Z0F3SUJBZ0lVVnNRZkFaTW4vazNRTU9nc0RuVEdUaU9PbGJ3d0RRWUpLb1pJaHZjTkFRRUwKQlFBd1NURUxNQWtHQTFVRUJoTUNTVlF4RFRBTEJnTlZCQWdNQkVGemRHa3hFVEFQQmdOVkJBb01DRlJsYzNRZwpUR0ZpTVJnd0ZnWURWUVFEREE5MmJTMWliR0Z1YXk1bVppNXNZVzR3SGhjTk1qTXdOakE0TURrMU5EQTRXaGNOCk1qUXdOakEzTURrMU5EQTRXakJKTVFzd0NRWURWUVFHRXdKSlZERU5NQXNHQTFVRUNBd0VRWE4wYVRFUk1BOEcKQTFVRUNnd0lWR1Z6ZENCTVlXSXhHREFXQmdOVkJBTU1EM1p0TFdKc1lXNXJMbVptTG14aGJqQ0NBaUl3RFFZSgpLb1pJaHZjTkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFLMlQwWXpkcjB0dWQzaVJRNGNzaGNhRVJTRzVjTDE2CkhRblhoYWw4emlUL1VRQUNIUGdzZDYwcWlEaldvQTJXb0lGWFFpUHkzOG1vZGtWRlR4Qmt5U2VldndOOFJiLzEKOFhaMS8yS1RnVmRDcHkvNm11WE15bXZYODJad05CVkV3QnoxUk5kbklUSk44cVh3a0d4bHozbDBib1loRkFyUQpNdmkxcW1RaHpDa2Zpb041MVkrYlBXOXpTQlFQdXNrcXJYYzRqTTJ0VENNQ2pTcFlvd1hXM1ppRmc5WEJ1Z09aCjFmdWd1Zmw4K1FJYzNZSEFoL1Z1NloraXFEOGxQeGRKODlBeDZaazVtOGdkVG9JdUhBbUNWaHFpUXBGRjkzSTgKbkYrSnRuYnBaNTRJUTZBbWYrYiswakMxdmY4Kzg0WUppaEVzWExyaGMxZTRTZ2dwdzEvcWpDb21QblhGVjEzUwpsUG5kVlhVR0taa1ZKdXdZTjJyZElmd3YrdCs5MGhwUVBmNmFBTjRCamRxOXdkdkQzSXVnS2JYZG5CQ0FUTEY4ClYyRTFTSE9VZGdRY3duK1d1WDVVOGdPa3B2b2VFN0g1REJ6Rks1WTZ2SHZlaTRlNkp3RTRDK3FJL1BmbTgreTEKNEpsOFBSOW5JQmdGQ3hrZWpwa2tRQ0I5U0dvMVZidzZhWmdZd0VQNHh6YXFYYXV3L3F4c0oxNUkrRTBndEs1OApuWUtkM0hqelk5Slh6V0NVNTdXbmc2SzNvTTIzNXpyRzJnNm1FaHQ4SStDckVMUFNuZURjZU8zVlJkc2dlblBCCis4U1JxVU8vWG9LWHNEU3I5amoxdWluVzYwTG5MZ0Zmc3JQeGlQVlZlMFh1TFZESlhCSlNoRDZDeGRyMnBSOGQKS25SRDZrTFpZZEtMQWdNQkFBR2pVekJSTUIwR0ExVWREZ1FXQkJRUzZnS2pMK3VFc0dXeXVjbTZyb0xVaXpqVwpWREFmQmdOVkhTTUVHREFXZ0JRUzZnS2pMK3VFc0dXeXVjbTZyb0xVaXpqV1ZEQVBCZ05WSFJNQkFmOEVCVEFECkFRSC9NQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUNBUUJad3B4Z2Z4N2thZFhvRHNyT1hUVXJ6dEFPMkFQRVJNaTAKaTkyNk9DTGFPbVVYZW1uKytXSUU1K2tUSE0wcS8vbUZCTURzSmdZSFVLUlNvRGNsNmh4TnVFNUNzS2trRVFTSgpMTHZrWlB0S2J5NGlxMitLZ1JtdVZxbXJNVTBYQzZMZDl3WmttL2huUjNtT3V6bko4MGZmV1JDQ0xGWDEwY2EzCnc5TGM1d1JLTFBZZXQvcEs5SitOYWN3TFJRYTczVFovMUpQNW9BU3czVjNoYkxlLy9UeWpnOURqUlZGY3FYWnEKWWs2Mm5qSkhZVzh3WmlhZzc0QXU4dHE5OG5KandBV1ROMFV5L2w1Q2VpWnV5bzZlU0RHVDNJNm1BdGU1VXBvWAppNXBkYlZ6VDdOZC9IOEwwZHZNdVZ2N0FmakZlcU91cUZNNkkzTnlvbStLWENxNmJQdGxBWEkzeVFZc0t4ZlRkCkw3SnRaTmx6MGJ6eHJhcHI4RmpYcjhML1ZkeHQza00xMnJwb2kzL3hsckR6Q2Q2b2YrQ1MxelBocUdpOUhvcUoKZEU5VGhYMklTdkd2akVSYzVVNFRsNjJBNHNyeGJQbUt0eWx3dGNGVEJacUJiRGY3ZjBBc2cveWhndXdTcktsQQpBNkRWVXVCRFErdGpwZ0N0b0ZlOEhLVDJ6UFVlaEQ2ZjVNQkhmU2ZUZ1crTlhFSXNvVDNsampjY1hsYXhPcFJWCkNQNWxCczNmekxyYnBxbUlLaWZhdWlTNWM4TzlSUjhjQTVzeWlBOTBmbmJIdDlmdGxpRG9jcFRzNUtrbjk2NkIKZUxMM1dXVldCYUtvanJzY1RkVXJoalNnVVBmam5FTXpnVzR2eEc3d3BVNHR2ME4yaEtHUWc0bVhhcDV0SU5Pcwp4WktnZXRHUldnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=\"\n }\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\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_acme_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"resolver\": \"Google\",\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 \"acme_issuer\": \"ACME example issuer\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"acme_issuers\": [\n {\n \"name\": \"ACME example issuer\",\n \"uri\": \"https://acme.example.com/directory\",\n \"contact\": \"admin@example.test\",\n \"account_key\": \"rsa:2048\",\n \"ssl_verify\": true,\n \"ssl_trusted_certificate\": \"cacert\",\n \"accept_terms_of_service\": true\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"cacert\",\n \"contents\": {\n \"content\": \"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZjekNDQTF1Z0F3SUJBZ0lVVnNRZkFaTW4vazNRTU9nc0RuVEdUaU9PbGJ3d0RRWUpLb1pJaHZjTkFRRUwKQlFBd1NURUxNQWtHQTFVRUJoTUNTVlF4RFRBTEJnTlZCQWdNQkVGemRHa3hFVEFQQmdOVkJBb01DRlJsYzNRZwpUR0ZpTVJnd0ZnWURWUVFEREE5MmJTMWliR0Z1YXk1bVppNXNZVzR3SGhjTk1qTXdOakE0TURrMU5EQTRXaGNOCk1qUXdOakEzTURrMU5EQTRXakJKTVFzd0NRWURWUVFHRXdKSlZERU5NQXNHQTFVRUNBd0VRWE4wYVRFUk1BOEcKQTFVRUNnd0lWR1Z6ZENCTVlXSXhHREFXQmdOVkJBTU1EM1p0TFdKc1lXNXJMbVptTG14aGJqQ0NBaUl3RFFZSgpLb1pJaHZjTkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFLMlQwWXpkcjB0dWQzaVJRNGNzaGNhRVJTRzVjTDE2CkhRblhoYWw4emlUL1VRQUNIUGdzZDYwcWlEaldvQTJXb0lGWFFpUHkzOG1vZGtWRlR4Qmt5U2VldndOOFJiLzEKOFhaMS8yS1RnVmRDcHkvNm11WE15bXZYODJad05CVkV3QnoxUk5kbklUSk44cVh3a0d4bHozbDBib1loRkFyUQpNdmkxcW1RaHpDa2Zpb041MVkrYlBXOXpTQlFQdXNrcXJYYzRqTTJ0VENNQ2pTcFlvd1hXM1ppRmc5WEJ1Z09aCjFmdWd1Zmw4K1FJYzNZSEFoL1Z1NloraXFEOGxQeGRKODlBeDZaazVtOGdkVG9JdUhBbUNWaHFpUXBGRjkzSTgKbkYrSnRuYnBaNTRJUTZBbWYrYiswakMxdmY4Kzg0WUppaEVzWExyaGMxZTRTZ2dwdzEvcWpDb21QblhGVjEzUwpsUG5kVlhVR0taa1ZKdXdZTjJyZElmd3YrdCs5MGhwUVBmNmFBTjRCamRxOXdkdkQzSXVnS2JYZG5CQ0FUTEY4ClYyRTFTSE9VZGdRY3duK1d1WDVVOGdPa3B2b2VFN0g1REJ6Rks1WTZ2SHZlaTRlNkp3RTRDK3FJL1BmbTgreTEKNEpsOFBSOW5JQmdGQ3hrZWpwa2tRQ0I5U0dvMVZidzZhWmdZd0VQNHh6YXFYYXV3L3F4c0oxNUkrRTBndEs1OApuWUtkM0hqelk5Slh6V0NVNTdXbmc2SzNvTTIzNXpyRzJnNm1FaHQ4SStDckVMUFNuZURjZU8zVlJkc2dlblBCCis4U1JxVU8vWG9LWHNEU3I5amoxdWluVzYwTG5MZ0Zmc3JQeGlQVlZlMFh1TFZESlhCSlNoRDZDeGRyMnBSOGQKS25SRDZrTFpZZEtMQWdNQkFBR2pVekJSTUIwR0ExVWREZ1FXQkJRUzZnS2pMK3VFc0dXeXVjbTZyb0xVaXpqVwpWREFmQmdOVkhTTUVHREFXZ0JRUzZnS2pMK3VFc0dXeXVjbTZyb0xVaXpqV1ZEQVBCZ05WSFJNQkFmOEVCVEFECkFRSC9NQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUNBUUJad3B4Z2Z4N2thZFhvRHNyT1hUVXJ6dEFPMkFQRVJNaTAKaTkyNk9DTGFPbVVYZW1uKytXSUU1K2tUSE0wcS8vbUZCTURzSmdZSFVLUlNvRGNsNmh4TnVFNUNzS2trRVFTSgpMTHZrWlB0S2J5NGlxMitLZ1JtdVZxbXJNVTBYQzZMZDl3WmttL2huUjNtT3V6bko4MGZmV1JDQ0xGWDEwY2EzCnc5TGM1d1JLTFBZZXQvcEs5SitOYWN3TFJRYTczVFovMUpQNW9BU3czVjNoYkxlLy9UeWpnOURqUlZGY3FYWnEKWWs2Mm5qSkhZVzh3WmlhZzc0QXU4dHE5OG5KandBV1ROMFV5L2w1Q2VpWnV5bzZlU0RHVDNJNm1BdGU1VXBvWAppNXBkYlZ6VDdOZC9IOEwwZHZNdVZ2N0FmakZlcU91cUZNNkkzTnlvbStLWENxNmJQdGxBWEkzeVFZc0t4ZlRkCkw3SnRaTmx6MGJ6eHJhcHI4RmpYcjhML1ZkeHQza00xMnJwb2kzL3hsckR6Q2Q2b2YrQ1MxelBocUdpOUhvcUoKZEU5VGhYMklTdkd2akVSYzVVNFRsNjJBNHNyeGJQbUt0eWx3dGNGVEJacUJiRGY3ZjBBc2cveWhndXdTcktsQQpBNkRWVXVCRFErdGpwZ0N0b0ZlOEhLVDJ6UFVlaEQ2ZjVNQkhmU2ZUZ1crTlhFSXNvVDNsampjY1hsYXhPcFJWCkNQNWxCczNmekxyYnBxbUlLaWZhdWlTNWM4TzlSUjhjQTVzeWlBOTBmbmJIdDlmdGxpRG9jcFRzNUtrbjk2NkIKZUxMM1dXVldCYUtvanJzY1RkVXJoalNnVVBmam5FTXpnVzR2eEc3d3BVNHR2ME4yaEtHUWc0bVhhcDV0SU5Pcwp4WktnZXRHUldnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -5509,68 +5509,18 @@ "name": "API Gateway", "item": [ { - "name": "Petstore API", + "name": "APIs.guru", "item": [ { "name": "API Client test requests", "item": [ { - "name": "Get Inventory (legitimate request)", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "https://apigw.nginx.lab/petstore/store/inventory", - "protocol": "https", - "host": [ - "apigw", - "nginx", - "lab" - ], - "path": [ - "petstore", - "store", - "inventory" - ] - } - }, - "response": [] - }, - { - "name": "Get Inventory (malicious query string)", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "https://apigw.nginx.lab/petstore/store/inventory?/etc/passwd", - "protocol": "https", - "host": [ - "apigw", - "nginx", - "lab" - ], - "path": [ - "petstore", - "store", - "inventory" - ], - "query": [ - { - "key": "/etc/passwd", - "value": null - } - ] - } - }, - "response": [] - }, - { - "name": "Get Inventory (XSS attack)", + "name": "Metrics", "request": { "method": "GET", "header": [], "url": { - "raw": "https://apigw.nginx.lab/petstore/store/inventory?", + "raw": "https://apigw.nginx.lab/apiguru/metrics.json", "protocol": "https", "host": [ "apigw", @@ -5578,27 +5528,20 @@ "lab" ], "path": [ - "petstore", - "store", - "inventory" - ], - "query": [ - { - "key": "", - "value": null - } + "apiguru", + "metrics.json" ] } }, "response": [] }, { - "name": "Login without token", + "name": "Providers - no authentication", "request": { "method": "GET", "header": [], "url": { - "raw": "https://apigw.nginx.lab/petstore/user/login", + "raw": "https://apigw.nginx.lab/apiguru/providers.json", "protocol": "https", "host": [ "apigw", @@ -5606,16 +5549,15 @@ "lab" ], "path": [ - "petstore", - "user", - "login" + "apiguru", + "providers.json" ] } }, "response": [] }, { - "name": "Login with \"DevOps\" token", + "name": "Providers - auth with \"DevOps\" token", "request": { "auth": { "type": "bearer", @@ -5630,7 +5572,7 @@ "method": "GET", "header": [], "url": { - "raw": "https://apigw.nginx.lab/petstore/user/login", + "raw": "https://apigw.nginx.lab/apiguru/providers.json", "protocol": "https", "host": [ "apigw", @@ -5638,16 +5580,15 @@ "lab" ], "path": [ - "petstore", - "user", - "login" + "apiguru", + "providers.json" ] } }, "response": [] }, { - "name": "Login with \"Guest\" token", + "name": "Providers - auth with \"Guest\" token", "request": { "auth": { "type": "bearer", @@ -5662,7 +5603,7 @@ "method": "GET", "header": [], "url": { - "raw": "https://apigw.nginx.lab/petstore/user/login", + "raw": "https://apigw.nginx.lab/apiguru/providers.json", "protocol": "https", "host": [ "apigw", @@ -5670,16 +5611,15 @@ "lab" ], "path": [ - "petstore", - "user", - "login" + "apiguru", + "providers.json" ] } }, "response": [] }, { - "name": "Login with dual (DevOps & Guest) role token", + "name": "Providers - auth with \"DevOps\" and \"Guest\" token", "request": { "auth": { "type": "bearer", @@ -5694,130 +5634,7 @@ "method": "GET", "header": [], "url": { - "raw": "https://apigw.nginx.lab/petstore/user/login", - "protocol": "https", - "host": [ - "apigw", - "nginx", - "lab" - ], - "path": [ - "petstore", - "user", - "login" - ] - } - }, - "response": [] - }, - { - "name": "Upload pet image without token", - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/octet-stream", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TS0UqChYRcchQXbSLijjWKhShQqgVWnUwuX5Ck4YkxcVRcC04+LFYdXBx1tXBVRAEP0CcHZwUXaTE/yWFFjEeHPfj3b3H3TtAaFSYanbFAFWzjFQiLmayq2LwFQEI6Mc4BmVm6nOSlITn+LqHj693UZ7lfe7P0ZvLmwzwicQxphsW8QbxzKalc94nDrOSnCM+J54w6ILEj1xXXH7jXHRY4JlhI52aJw4Ti8UOVjqYlQyVeJo4klM1yhcyLuc4b3FWKzXWuid/YSivrSxzneYIEljEEiSIUFBDGRVYiNKqkWIiRftxD/+w45fIpZCrDEaOBVShQnb84H/wu1uzMDXpJoXiQODFtj9GgeAu0Kzb9vexbTdPAP8zcKW1/dUGMPtJer2tRY6Avm3g4rqtKXvA5Q4w9KTLhuxIfppCoQC8n9E3ZYGBW6Bnze2ttY/TByBNXSVvgINDYKxI2ese7+7u7O3fM63+fgB5bXKpzZcBIwAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAAd0SU1FB+gFAhArKAvJglcAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAADElEQVQI12P4//8/AAX+Av7czFnnAAAAAElFTkSuQmCC" - }, - "url": { - "raw": "https://apigw.nginx.lab/petstore/pet/1/uploadImage", - "protocol": "https", - "host": [ - "apigw", - "nginx", - "lab" - ], - "path": [ - "petstore", - "pet", - "1", - "uploadImage" - ] - } - }, - "response": [] - }, - { - "name": "Upload pet image with \"DevOps\" token", - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDI0ODEzNjcsImV4cCI6MTcwMjQ4MTM2OH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIl19.SKA_7MszAypMEtX5NDQ0TcUbVYx_Wt0hrtmuyTmrVKU", - "type": "string" - } - ] - }, - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/octet-stream", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TS0UqChYRcchQXbSLijjWKhShQqgVWnUwuX5Ck4YkxcVRcC04+LFYdXBx1tXBVRAEP0CcHZwUXaTE/yWFFjEeHPfj3b3H3TtAaFSYanbFAFWzjFQiLmayq2LwFQEI6Mc4BmVm6nOSlITn+LqHj693UZ7lfe7P0ZvLmwzwicQxphsW8QbxzKalc94nDrOSnCM+J54w6ILEj1xXXH7jXHRY4JlhI52aJw4Ti8UOVjqYlQyVeJo4klM1yhcyLuc4b3FWKzXWuid/YSivrSxzneYIEljEEiSIUFBDGRVYiNKqkWIiRftxD/+w45fIpZCrDEaOBVShQnb84H/wu1uzMDXpJoXiQODFtj9GgeAu0Kzb9vexbTdPAP8zcKW1/dUGMPtJer2tRY6Avm3g4rqtKXvA5Q4w9KTLhuxIfppCoQC8n9E3ZYGBW6Bnze2ttY/TByBNXSVvgINDYKxI2ese7+7u7O3fM63+fgB5bXKpzZcBIwAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAAd0SU1FB+gFAhArKAvJglcAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAADElEQVQI12P4//8/AAX+Av7czFnnAAAAAElFTkSuQmCC" - }, - "url": { - "raw": "https://apigw.nginx.lab/petstore/pet/1/uploadImage", - "protocol": "https", - "host": [ - "apigw", - "nginx", - "lab" - ], - "path": [ - "petstore", - "pet", - "1", - "uploadImage" - ] - } - }, - "response": [] - }, - { - "name": "Upload pet image with \"Guest\" token", - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDk3NjQ3NTMsImV4cCI6MTcwOTc2NDc1NH0.eyJuYW1lIjoiQWxpY2UgR3Vlc3QiLCJzdWIiOiJKV1Qgc3ViIGNsYWltIiwiaXNzIjoiSldUIGlzcyBjbGFpbSIsInJvbGVzIjpbImd1ZXN0Il19.jFJDq-33irz7uFxdI8c8fIb5TwTAU5BlemmIFVALUAE", - "type": "string" - } - ] - }, - "method": "POST", - "header": [], - "body": { - "mode": "formdata", - "formdata": [ - { - "key": "file", - "value": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TS0UqChYRcchQXbSLijjWKhShQqgVWnUwuX5Ck4YkxcVRcC04+LFYdXBx1tXBVRAEP0CcHZwUXaTE/yWFFjEeHPfj3b3H3TtAaFSYanbFAFWzjFQiLmayq2LwFQEI6Mc4BmVm6nOSlITn+LqHj693UZ7lfe7P0ZvLmwzwicQxphsW8QbxzKalc94nDrOSnCM+J54w6ILEj1xXXH7jXHRY4JlhI52aJw4Ti8UOVjqYlQyVeJo4klM1yhcyLuc4b3FWKzXWuid/YSivrSxzneYIEljEEiSIUFBDGRVYiNKqkWIiRftxD/+w45fIpZCrDEaOBVShQnb84H/wu1uzMDXpJoXiQODFtj9GgeAu0Kzb9vexbTdPAP8zcKW1/dUGMPtJer2tRY6Avm3g4rqtKXvA5Q4w9KTLhuxIfppCoQC8n9E3ZYGBW6Bnze2ttY/TByBNXSVvgINDYKxI2ese7+7u7O3fM63+fgB5bXKpzZcBIwAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAAd0SU1FB+gFAhArKAvJglcAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAADElEQVQI12P4//8/AAX+Av7czFnnAAAAAElFTkSuQmCC", - "type": "text" - }, - { - "key": "type", - "value": "image/png", - "type": "text" - } - ] - }, - "url": { - "raw": "https://apigw.nginx.lab/petstore/pet/1/uploadImage", + "raw": "https://apigw.nginx.lab/apiguru/providers.json", "protocol": "https", "host": [ "apigw", @@ -5825,10 +5642,8 @@ "lab" ], "path": [ - "petstore", - "pet", - "1", - "uploadImage" + "apiguru", + "providers.json" ] } }, @@ -5838,7 +5653,7 @@ "description": "This folder contains requests to access the Petstore API published through NGINX using the Declarative API" }, { - "name": "Petstore 3 API Gateway RateLimit + JWT AuthN/AuthZ + redocly", + "name": "APIGuru API Gateway RateLimit + JWT AuthN/AuthZ + redocly - YAML OpenAPI schema", "event": [ { "listen": "test", @@ -5861,7 +5676,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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"APIGuru\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/apiguru\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://api.apis.guru/v2/openapi.yaml\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://api.apis.guru/v2/\"\n },\n \"developer_portal\": {\n \"enabled\": false,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/apiguru-devportal.html\"\n }\n },\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"JWT Authentication\"\n }\n ],\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/providers.json\"\n ]\n },\n \"authorization\": [\n {\n \"profile\": \"JWT role based authorization\",\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/providers.json\"\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"profile\": \"apigw_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 0,\n \"delay\": 0,\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/metrics.json\"\n ]\n }\n ]\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\n }\n }\n }\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"apigw_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"2r/s\"\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"JWT Authentication\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"API 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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -5884,7 +5699,7 @@ "response": [] }, { - "name": "Petstore 3 API Gateway RateLimit + JWT AuthN/AuthZ + backstage", + "name": "APIGuru API Gateway RateLimit + JWT AuthN/AuthZ + redocly - local OpenAPI schema", "event": [ { "listen": "test", @@ -5907,7 +5722,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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"APIGuru\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/apiguru\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"eyJvcGVuYXBpIjoiMy4wLjAiLCJ4LW9wdGljLXVybCI6Imh0dHBzOi8vYXBwLnVzZW9wdGljLmNvbS9vcmdhbml6YXRpb25zL2ZlYmY4YWM2LWVlNjctNDU2NS1iNDVhLTVjODVhNDY5ZGNhNy9hcGlzL18wZktXcVV2aHM5c3NZTmtxMWstYyIsIngtb3B0aWMtc3RhbmRhcmQiOiJAZmViZjhhYzYtZWU2Ny00NTY1LWI0NWEtNWM4NWE0NjlkY2E3L0Z6NktVM193TUlPNWlKNl9WVVozMCIsImluZm8iOnsidmVyc2lvbiI6IjIuMi4wIiwidGl0bGUiOiJBUElzLmd1cnUiLCJkZXNjcmlwdGlvbiI6Ildpa2lwZWRpYSBmb3IgV2ViIEFQSXMuIFJlcG9zaXRvcnkgb2YgQVBJIGRlZmluaXRpb25zIGluIE9wZW5BUEkgZm9ybWF0LlxuKipXYXJuaW5nKio6IElmIHlvdSB3YW50IHRvIGJlIG5vdGlmaWVkIGFib3V0IGNoYW5nZXMgaW4gYWR2YW5jZSBwbGVhc2Ugam9pbiBvdXIgW1NsYWNrIGNoYW5uZWxdKGh0dHBzOi8vam9pbi5zbGFjay5jb20vdC9tZXJtYWRlL3NoYXJlZF9pbnZpdGUvenQtZzc4Zzd4aXItTUxFX0NUQ2NYQ2RmSmZHM0NKZTlxQSkuXG5DbGllbnQgc2FtcGxlOiBbW0RlbW9dXShodHRwczovL2FwaXMuZ3VydS9zaW1wbGUtdWkpIFtbUmVwb11dKGh0dHBzOi8vZ2l0aHViLmNvbS9BUElzLWd1cnUvc2ltcGxlLXVpKVxuIiwiY29udGFjdCI6eyJuYW1lIjoiQVBJcy5ndXJ1IiwidXJsIjoiaHR0cHM6Ly9BUElzLmd1cnUiLCJlbWFpbCI6Im1pa2UucmFscGhzb25AZ21haWwuY29tIn0sImxpY2Vuc2UiOnsibmFtZSI6IkNDMCAxLjAiLCJ1cmwiOiJodHRwczovL2dpdGh1Yi5jb20vQVBJcy1ndXJ1L29wZW5hcGktZGlyZWN0b3J5I2xpY2Vuc2VzIn0sIngtbG9nbyI6eyJ1cmwiOiJodHRwczovL2FwaXMuZ3VydS9icmFuZGluZy9sb2dvX3ZlcnRpY2FsLnN2ZyJ9fSwiZXh0ZXJuYWxEb2NzIjp7InVybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9BUElzLWd1cnUvb3BlbmFwaS1kaXJlY3RvcnkvYmxvYi9tYXN0ZXIvQVBJLm1kIn0sInNlcnZlcnMiOlt7InVybCI6Imh0dHBzOi8vYXBpLmFwaXMuZ3VydS92MiJ9XSwic2VjdXJpdHkiOltdLCJ0YWdzIjpbeyJuYW1lIjoiQVBJcyIsImRlc2NyaXB0aW9uIjoiQWN0aW9ucyByZWxhdGluZyB0byBBUElzIGluIHRoZSBjb2xsZWN0aW9uIn1dLCJwYXRocyI6eyIvcHJvdmlkZXJzLmpzb24iOnsiZ2V0Ijp7Im9wZXJhdGlvbklkIjoiZ2V0UHJvdmlkZXJzIiwidGFncyI6WyJBUElzIl0sInN1bW1hcnkiOiJMaXN0IGFsbCBwcm92aWRlcnMiLCJkZXNjcmlwdGlvbiI6Ikxpc3QgYWxsIHRoZSBwcm92aWRlcnMgaW4gdGhlIGRpcmVjdG9yeVxuIiwicmVzcG9uc2VzIjp7IjIwMCI6eyJkZXNjcmlwdGlvbiI6Ik9LIiwiY29udGVudCI6eyJhcHBsaWNhdGlvbi9qc29uIjp7InNjaGVtYSI6eyJ0eXBlIjoib2JqZWN0IiwicHJvcGVydGllcyI6eyJkYXRhIjp7InR5cGUiOiJhcnJheSIsIml0ZW1zIjp7InR5cGUiOiJzdHJpbmciLCJtaW5MZW5ndGgiOjF9LCJtaW5JdGVtcyI6MX19fX19fX19fSwiL3twcm92aWRlcn0uanNvbiI6eyJnZXQiOnsib3BlcmF0aW9uSWQiOiJnZXRQcm92aWRlciIsInRhZ3MiOlsiQVBJcyJdLCJzdW1tYXJ5IjoiTGlzdCBhbGwgQVBJcyBmb3IgYSBwYXJ0aWN1bGFyIHByb3ZpZGVyIiwiZGVzY3JpcHRpb24iOiJMaXN0IGFsbCBBUElzIGluIHRoZSBkaXJlY3RvcnkgZm9yIGEgcGFydGljdWxhciBwcm92aWRlck5hbWVcblJldHVybnMgbGlua3MgdG8gdGhlIGluZGl2aWR1YWwgQVBJIGVudHJ5IGZvciBlYWNoIEFQSS5cbiIsInBhcmFtZXRlcnMiOlt7IiRyZWYiOiIjL2NvbXBvbmVudHMvcGFyYW1ldGVycy9wcm92aWRlciJ9XSwicmVzcG9uc2VzIjp7IjIwMCI6eyJkZXNjcmlwdGlvbiI6Ik9LIiwiY29udGVudCI6eyJhcHBsaWNhdGlvbi9qc29uIjp7InNjaGVtYSI6eyIkcmVmIjoiIy9jb21wb25lbnRzL3NjaGVtYXMvQVBJcyJ9fX19fX19LCIve3Byb3ZpZGVyfS9zZXJ2aWNlcy5qc29uIjp7ImdldCI6eyJvcGVyYXRpb25JZCI6ImdldFNlcnZpY2VzIiwidGFncyI6WyJBUElzIl0sInN1bW1hcnkiOiJMaXN0IGFsbCBzZXJ2aWNlTmFtZXMgZm9yIGEgcGFydGljdWxhciBwcm92aWRlciIsImRlc2NyaXB0aW9uIjoiTGlzdCBhbGwgc2VydmljZU5hbWVzIGluIHRoZSBkaXJlY3RvcnkgZm9yIGEgcGFydGljdWxhciBwcm92aWRlck5hbWVcbiIsInBhcmFtZXRlcnMiOlt7IiRyZWYiOiIjL2NvbXBvbmVudHMvcGFyYW1ldGVycy9wcm92aWRlciJ9XSwicmVzcG9uc2VzIjp7IjIwMCI6eyJkZXNjcmlwdGlvbiI6Ik9LIiwiY29udGVudCI6eyJhcHBsaWNhdGlvbi9qc29uIjp7InNjaGVtYSI6eyJ0eXBlIjoib2JqZWN0IiwicHJvcGVydGllcyI6eyJkYXRhIjp7InR5cGUiOiJhcnJheSIsIml0ZW1zIjp7InR5cGUiOiJzdHJpbmciLCJtaW5MZW5ndGgiOjB9LCJtaW5JdGVtcyI6MX19fX19fX19fSwiL3NwZWNzL3twcm92aWRlcn0ve2FwaX0uanNvbiI6eyJnZXQiOnsib3BlcmF0aW9uSWQiOiJnZXRBUEkiLCJ0YWdzIjpbIkFQSXMiXSwic3VtbWFyeSI6IlJldHJpZXZlIG9uZSB2ZXJzaW9uIG9mIGEgcGFydGljdWxhciBBUEkiLCJkZXNjcmlwdGlvbiI6IlJldHVybnMgdGhlIEFQSSBlbnRyeSBmb3Igb25lIHNwZWNpZmljIHZlcnNpb24gb2YgYW4gQVBJIHdoZXJlIHRoZXJlIGlzIG5vIHNlcnZpY2VOYW1lLiIsInBhcmFtZXRlcnMiOlt7IiRyZWYiOiIjL2NvbXBvbmVudHMvcGFyYW1ldGVycy9wcm92aWRlciJ9LHsiJHJlZiI6IiMvY29tcG9uZW50cy9wYXJhbWV0ZXJzL2FwaSJ9XSwicmVzcG9uc2VzIjp7IjIwMCI6eyJkZXNjcmlwdGlvbiI6Ik9LIiwiY29udGVudCI6eyJhcHBsaWNhdGlvbi9qc29uIjp7InNjaGVtYSI6eyIkcmVmIjoiIy9jb21wb25lbnRzL3NjaGVtYXMvQVBJIn19fX19fX0sIi9zcGVjcy97cHJvdmlkZXJ9L3tzZXJ2aWNlfS97YXBpfS5qc29uIjp7ImdldCI6eyJvcGVyYXRpb25JZCI6ImdldFNlcnZpY2VBUEkiLCJ0YWdzIjpbIkFQSXMiXSwic3VtbWFyeSI6IlJldHJpZXZlIG9uZSB2ZXJzaW9uIG9mIGEgcGFydGljdWxhciBBUEkgd2l0aCBhIHNlcnZpY2VOYW1lLiIsImRlc2NyaXB0aW9uIjoiUmV0dXJucyB0aGUgQVBJIGVudHJ5IGZvciBvbmUgc3BlY2lmaWMgdmVyc2lvbiBvZiBhbiBBUEkgd2hlcmUgdGhlcmUgaXMgYSBzZXJ2aWNlTmFtZS4iLCJwYXJhbWV0ZXJzIjpbeyIkcmVmIjoiIy9jb21wb25lbnRzL3BhcmFtZXRlcnMvcHJvdmlkZXIifSx7Im5hbWUiOiJzZXJ2aWNlIiwiaW4iOiJwYXRoIiwicmVxdWlyZWQiOnRydWUsInNjaGVtYSI6eyJ0eXBlIjoic3RyaW5nIiwibWluTGVuZ3RoIjoxLCJtYXhMZW5ndGgiOjI1NSwiZXhhbXBsZSI6ImdyYXBoIn19LHsiJHJlZiI6IiMvY29tcG9uZW50cy9wYXJhbWV0ZXJzL2FwaSJ9XSwicmVzcG9uc2VzIjp7IjIwMCI6eyJkZXNjcmlwdGlvbiI6Ik9LIiwiY29udGVudCI6eyJhcHBsaWNhdGlvbi9qc29uIjp7InNjaGVtYSI6eyIkcmVmIjoiIy9jb21wb25lbnRzL3NjaGVtYXMvQVBJIn19fX19fX0sIi9saXN0Lmpzb24iOnsiZ2V0Ijp7Im9wZXJhdGlvbklkIjoibGlzdEFQSXMiLCJ0YWdzIjpbIkFQSXMiXSwic3VtbWFyeSI6Ikxpc3QgYWxsIEFQSXMiLCJkZXNjcmlwdGlvbiI6Ikxpc3QgYWxsIEFQSXMgaW4gdGhlIGRpcmVjdG9yeS5cblJldHVybnMgbGlua3MgdG8gdGhlIE9wZW5BUEkgZGVmaW5pdGlvbnMgZm9yIGVhY2ggQVBJIGluIHRoZSBkaXJlY3RvcnkuXG5JZiBBUEkgZXhpc3QgaW4gbXVsdGlwbGUgdmVyc2lvbnMgYHByZWZlcnJlZGAgb25lIGlzIGV4cGxpY2l0bHkgbWFya2VkLlxuU29tZSBiYXNpYyBpbmZvIGZyb20gdGhlIE9wZW5BUEkgZGVmaW5pdGlvbiBpcyBjYWNoZWQgaW5zaWRlIGVhY2ggb2JqZWN0LlxuVGhpcyBhbGxvd3MgeW91IHRvIGdlbmVyYXRlIHNvbWUgc2ltcGxlIHZpZXdzIHdpdGhvdXQgbmVlZGluZyB0byBmZXRjaCB0aGUgT3BlbkFQSSBkZWZpbml0aW9uIGZvciBlYWNoIEFQSS5cbiIsInJlc3BvbnNlcyI6eyIyMDAiOnsiZGVzY3JpcHRpb24iOiJPSyIsImNvbnRlbnQiOnsiYXBwbGljYXRpb24vanNvbiI6eyJzY2hlbWEiOnsiJHJlZiI6IiMvY29tcG9uZW50cy9zY2hlbWFzL0FQSXMifX19fX19fSwiL21ldHJpY3MuanNvbiI6eyJnZXQiOnsib3BlcmF0aW9uSWQiOiJnZXRNZXRyaWNzIiwic3VtbWFyeSI6IkdldCBiYXNpYyBtZXRyaWNzIiwiZGVzY3JpcHRpb24iOiJTb21lIGJhc2ljIG1ldHJpY3MgZm9yIHRoZSBlbnRpcmUgZGlyZWN0b3J5LlxuSnVzdCBzdHVubmluZyBudW1iZXJzIHRvIHB1dCBvbiBhIGZyb250IHBhZ2UgYW5kIGFyZSBpbnRlbmRlZCBwdXJlbHkgZm9yIFdvVyBlZmZlY3QgOilcbiIsInRhZ3MiOlsiQVBJcyJdLCJyZXNwb25zZXMiOnsiMjAwIjp7ImRlc2NyaXB0aW9uIjoiT0siLCJjb250ZW50Ijp7ImFwcGxpY2F0aW9uL2pzb24iOnsic2NoZW1hIjp7IiRyZWYiOiIjL2NvbXBvbmVudHMvc2NoZW1hcy9NZXRyaWNzIn19fX19fX19LCJjb21wb25lbnRzIjp7InNjaGVtYXMiOnsiQVBJcyI6eyJkZXNjcmlwdGlvbiI6Ikxpc3Qgb2YgQVBJIGRldGFpbHMuXG5JdCBpcyBhIEpTT04gb2JqZWN0IHdpdGggQVBJIElEcyhgPHByb3ZpZGVyPls6PHNlcnZpY2U+XWApIGFzIGtleXMuXG4iLCJ0eXBlIjoib2JqZWN0IiwiYWRkaXRpb25hbFByb3BlcnRpZXMiOnsiJHJlZiI6IiMvY29tcG9uZW50cy9zY2hlbWFzL0FQSSJ9LCJtaW5Qcm9wZXJ0aWVzIjoxLCJleGFtcGxlIjp7Imdvb2dsZWFwaXMuY29tOmRyaXZlIjp7ImFkZGVkIjoiMjAxNS0wMi0yMlQyMDowMDo0NS4wMDBaIiwicHJlZmVycmVkIjoidjMiLCJ2ZXJzaW9ucyI6eyJ2MiI6eyJhZGRlZCI6IjIwMTUtMDItMjJUMjA6MDA6NDUuMDAwWiIsImluZm8iOnsidGl0bGUiOiJEcml2ZSIsInZlcnNpb24iOiJ2MiIsIngtYXBpQ2xpZW50UmVnaXN0cmF0aW9uIjp7InVybCI6Imh0dHBzOi8vY29uc29sZS5kZXZlbG9wZXJzLmdvb2dsZS5jb20ifSwieC1sb2dvIjp7InVybCI6Imh0dHBzOi8vYXBpLmFwaXMuZ3VydS92Mi9jYWNoZS9sb2dvL2h0dHBzX3d3dy5nc3RhdGljLmNvbV9pbWFnZXNfaWNvbnNfbWF0ZXJpYWxfcHJvZHVjdF8yeF9kcml2ZV8zMmRwLnBuZyJ9LCJ4LW9yaWdpbiI6eyJmb3JtYXQiOiJnb29nbGUiLCJ1cmwiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kaXNjb3ZlcnkvdjEvYXBpcy9kcml2ZS92Mi9yZXN0IiwidmVyc2lvbiI6InYxIn0sIngtcHJlZmVycmVkIjpmYWxzZSwieC1wcm92aWRlck5hbWUiOiJnb29nbGVhcGlzLmNvbSIsIngtc2VydmljZU5hbWUiOiJkcml2ZSJ9LCJzd2FnZ2VyVXJsIjoiaHR0cHM6Ly9hcGkuYXBpcy5ndXJ1L3YyL3NwZWNzL2dvb2dsZWFwaXMuY29tL2RyaXZlL3YyL3N3YWdnZXIuanNvbiIsInN3YWdnZXJZYW1sVXJsIjoiaHR0cHM6Ly9hcGkuYXBpcy5ndXJ1L3YyL3NwZWNzL2dvb2dsZWFwaXMuY29tL2RyaXZlL3YyL3N3YWdnZXIueWFtbCIsInVwZGF0ZWQiOiIyMDE2LTA2LTE3VDAwOjIxOjQ0LjAwMFoifSwidjMiOnsiYWRkZWQiOiIyMDE1LTEyLTEyVDAwOjI1OjEzLjAwMFoiLCJpbmZvIjp7InRpdGxlIjoiRHJpdmUiLCJ2ZXJzaW9uIjoidjMiLCJ4LWFwaUNsaWVudFJlZ2lzdHJhdGlvbiI6eyJ1cmwiOiJodHRwczovL2NvbnNvbGUuZGV2ZWxvcGVycy5nb29nbGUuY29tIn0sIngtbG9nbyI6eyJ1cmwiOiJodHRwczovL2FwaS5hcGlzLmd1cnUvdjIvY2FjaGUvbG9nby9odHRwc193d3cuZ3N0YXRpYy5jb21faW1hZ2VzX2ljb25zX21hdGVyaWFsX3Byb2R1Y3RfMnhfZHJpdmVfMzJkcC5wbmcifSwieC1vcmlnaW4iOnsiZm9ybWF0IjoiZ29vZ2xlIiwidXJsIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZGlzY292ZXJ5L3YxL2FwaXMvZHJpdmUvdjMvcmVzdCIsInZlcnNpb24iOiJ2MSJ9LCJ4LXByZWZlcnJlZCI6dHJ1ZSwieC1wcm92aWRlck5hbWUiOiJnb29nbGVhcGlzLmNvbSIsIngtc2VydmljZU5hbWUiOiJkcml2ZSJ9LCJzd2FnZ2VyVXJsIjoiaHR0cHM6Ly9hcGkuYXBpcy5ndXJ1L3YyL3NwZWNzL2dvb2dsZWFwaXMuY29tL2RyaXZlL3YzL3N3YWdnZXIuanNvbiIsInN3YWdnZXJZYW1sVXJsIjoiaHR0cHM6Ly9hcGkuYXBpcy5ndXJ1L3YyL3NwZWNzL2dvb2dsZWFwaXMuY29tL2RyaXZlL3YzL3N3YWdnZXIueWFtbCIsInVwZGF0ZWQiOiIyMDE2LTA2LTE3VDAwOjIxOjQ0LjAwMFoifX19fX0sIkFQSSI6eyJkZXNjcmlwdGlvbiI6Ik1ldGEgaW5mb3JtYXRpb24gYWJvdXQgQVBJIiwidHlwZSI6Im9iamVjdCIsInJlcXVpcmVkIjpbImFkZGVkIiwicHJlZmVycmVkIiwidmVyc2lvbnMiXSwicHJvcGVydGllcyI6eyJhZGRlZCI6eyJkZXNjcmlwdGlvbiI6IlRpbWVzdGFtcCB3aGVuIHRoZSBBUEkgd2FzIGZpcnN0IGFkZGVkIHRvIHRoZSBkaXJlY3RvcnkiLCJ0eXBlIjoic3RyaW5nIiwiZm9ybWF0IjoiZGF0ZS10aW1lIn0sInByZWZlcnJlZCI6eyJkZXNjcmlwdGlvbiI6IlJlY29tbWVuZGVkIHZlcnNpb24iLCJ0eXBlIjoic3RyaW5nIn0sInZlcnNpb25zIjp7ImRlc2NyaXB0aW9uIjoiTGlzdCBvZiBzdXBwb3J0ZWQgdmVyc2lvbnMgb2YgdGhlIEFQSSIsInR5cGUiOiJvYmplY3QiLCJhZGRpdGlvbmFsUHJvcGVydGllcyI6eyIkcmVmIjoiIy9jb21wb25lbnRzL3NjaGVtYXMvQXBpVmVyc2lvbiJ9LCJtaW5Qcm9wZXJ0aWVzIjoxfX0sImFkZGl0aW9uYWxQcm9wZXJ0aWVzIjpmYWxzZX0sIkFwaVZlcnNpb24iOnsidHlwZSI6Im9iamVjdCIsInJlcXVpcmVkIjpbImFkZGVkIiwidXBkYXRlZCIsInN3YWdnZXJVcmwiLCJzd2FnZ2VyWWFtbFVybCIsImluZm8iLCJvcGVuYXBpVmVyIl0sInByb3BlcnRpZXMiOnsiYWRkZWQiOnsiZGVzY3JpcHRpb24iOiJUaW1lc3RhbXAgd2hlbiB0aGUgdmVyc2lvbiB3YXMgYWRkZWQiLCJ0eXBlIjoic3RyaW5nIiwiZm9ybWF0IjoiZGF0ZS10aW1lIn0sInVwZGF0ZWQiOnsiZGVzY3JpcHRpb24iOiJUaW1lc3RhbXAgd2hlbiB0aGUgdmVyc2lvbiB3YXMgdXBkYXRlZCIsInR5cGUiOiJzdHJpbmciLCJmb3JtYXQiOiJkYXRlLXRpbWUifSwic3dhZ2dlclVybCI6eyJkZXNjcmlwdGlvbiI6IlVSTCB0byBPcGVuQVBJIGRlZmluaXRpb24gaW4gSlNPTiBmb3JtYXQiLCJ0eXBlIjoic3RyaW5nIiwiZm9ybWF0IjoidXJsIn0sInN3YWdnZXJZYW1sVXJsIjp7ImRlc2NyaXB0aW9uIjoiVVJMIHRvIE9wZW5BUEkgZGVmaW5pdGlvbiBpbiBZQU1MIGZvcm1hdCIsInR5cGUiOiJzdHJpbmciLCJmb3JtYXQiOiJ1cmwifSwibGluayI6eyJkZXNjcmlwdGlvbiI6IkxpbmsgdG8gdGhlIGluZGl2aWR1YWwgQVBJIGVudHJ5IGZvciB0aGlzIEFQSSIsInR5cGUiOiJzdHJpbmciLCJmb3JtYXQiOiJ1cmwifSwiaW5mbyI6eyJkZXNjcmlwdGlvbiI6IkNvcHkgb2YgYGluZm9gIHNlY3Rpb24gZnJvbSBPcGVuQVBJIGRlZmluaXRpb24iLCJ0eXBlIjoib2JqZWN0IiwibWluUHJvcGVydGllcyI6MX0sImV4dGVybmFsRG9jcyI6eyJkZXNjcmlwdGlvbiI6IkNvcHkgb2YgYGV4dGVybmFsRG9jc2Agc2VjdGlvbiBmcm9tIE9wZW5BUEkgZGVmaW5pdGlvbiIsInR5cGUiOiJvYmplY3QiLCJtaW5Qcm9wZXJ0aWVzIjoxfSwib3BlbmFwaVZlciI6eyJkZXNjcmlwdGlvbiI6IlRoZSB2YWx1ZSBvZiB0aGUgYG9wZW5hcGlgIG9yIGBzd2FnZ2VyYCBwcm9wZXJ0eSBvZiB0aGUgc291cmNlIGRlZmluaXRpb24iLCJ0eXBlIjoic3RyaW5nIn19LCJhZGRpdGlvbmFsUHJvcGVydGllcyI6ZmFsc2V9LCJNZXRyaWNzIjp7ImRlc2NyaXB0aW9uIjoiTGlzdCBvZiBiYXNpYyBtZXRyaWNzIiwidHlwZSI6Im9iamVjdCIsInJlcXVpcmVkIjpbIm51bVNwZWNzIiwibnVtQVBJcyIsIm51bUVuZHBvaW50cyJdLCJwcm9wZXJ0aWVzIjp7Im51bVNwZWNzIjp7ImRlc2NyaXB0aW9uIjoiTnVtYmVyIG9mIEFQSSBkZWZpbml0aW9ucyBpbmNsdWRpbmcgZGlmZmVyZW50IHZlcnNpb25zIG9mIHRoZSBzYW1lIEFQSSIsInR5cGUiOiJpbnRlZ2VyIiwibWluaW11bSI6MX0sIm51bUFQSXMiOnsiZGVzY3JpcHRpb24iOiJOdW1iZXIgb2YgdW5pcXVlIEFQSXMiLCJ0eXBlIjoiaW50ZWdlciIsIm1pbmltdW0iOjF9LCJudW1FbmRwb2ludHMiOnsiZGVzY3JpcHRpb24iOiJUb3RhbCBudW1iZXIgb2YgZW5kcG9pbnRzIGluc2lkZSBhbGwgZGVmaW5pdGlvbnMiLCJ0eXBlIjoiaW50ZWdlciIsIm1pbmltdW0iOjF9LCJ1bnJlYWNoYWJsZSI6eyJkZXNjcmlwdGlvbiI6Ik51bWJlciBvZiB1bnJlYWNoYWJsZSAoNFhYLDVYWCBzdGF0dXMpIEFQSXMiLCJ0eXBlIjoiaW50ZWdlciJ9LCJpbnZhbGlkIjp7ImRlc2NyaXB0aW9uIjoiTnVtYmVyIG9mIG5ld2x5IGludmFsaWQgQVBJcyIsInR5cGUiOiJpbnRlZ2VyIn0sInVub2ZmaWNpYWwiOnsiZGVzY3JpcHRpb24iOiJOdW1iZXIgb2YgdW5vZmZpY2lhbCBBUElzIiwidHlwZSI6ImludGVnZXIifSwiZml4ZXMiOnsiZGVzY3JpcHRpb24iOiJUb3RhbCBudW1iZXIgb2YgZml4ZXMgYXBwbGllZCBhY3Jvc3MgYWxsIEFQSXMiLCJ0eXBlIjoiaW50ZWdlciJ9LCJmaXhlZFBjdCI6eyJkZXNjcmlwdGlvbiI6IlBlcmNlbnRhZ2Ugb2YgYWxsIEFQSXMgd2hlcmUgYXV0byBmaXhlcyBoYXZlIGJlZW4gYXBwbGllZCIsInR5cGUiOiJpbnRlZ2VyIn0sImRhdGFzZXRzIjp7ImRlc2NyaXB0aW9uIjoiRGF0YSB1c2VkIGZvciBjaGFydGluZyBldGMiLCJ0eXBlIjoiYXJyYXkiLCJpdGVtcyI6e319LCJzdGFycyI6eyJkZXNjcmlwdGlvbiI6IkdpdEh1YiBzdGFycyBmb3Igb3VyIG1haW4gcmVwbyIsInR5cGUiOiJpbnRlZ2VyIn0sImlzc3VlcyI6eyJkZXNjcmlwdGlvbiI6Ik9wZW4gR2l0SHViIGlzc3VlcyBvbiBvdXIgbWFpbiByZXBvIiwidHlwZSI6ImludGVnZXIifSwidGhpc1dlZWsiOnsiZGVzY3JpcHRpb24iOiJTdW1tYXJ5IHRvdGFscyBmb3IgdGhlIGxhc3QgNyBkYXlzIiwidHlwZSI6Im9iamVjdCIsInByb3BlcnRpZXMiOnsiYWRkZWQiOnsiZGVzY3JpcHRpb24iOiJBUElzIGFkZGVkIGluIHRoZSBsYXN0IHdlZWsiLCJ0eXBlIjoiaW50ZWdlciJ9LCJ1cGRhdGVkIjp7ImRlc2NyaXB0aW9uIjoiQVBJcyB1cGRhdGVkIGluIHRoZSBsYXN0IHdlZWsiLCJ0eXBlIjoiaW50ZWdlciJ9fX0sIm51bURyaXZlcnMiOnsiZGVzY3JpcHRpb24iOiJOdW1iZXIgb2YgbWV0aG9kcyBvZiBBUEkgcmV0cmlldmFsIiwidHlwZSI6ImludGVnZXIifSwibnVtUHJvdmlkZXJzIjp7ImRlc2NyaXB0aW9uIjoiTnVtYmVyIG9mIEFQSSBwcm92aWRlcnMgaW4gZGlyZWN0b3J5IiwidHlwZSI6ImludGVnZXIifX0sImFkZGl0aW9uYWxQcm9wZXJ0aWVzIjpmYWxzZSwiZXhhbXBsZSI6eyJudW1BUElzIjoyNTAxLCJudW1FbmRwb2ludHMiOjEwNjQ0OCwibnVtU3BlY3MiOjMzMjksInVucmVhY2hhYmxlIjoxMjMsImludmFsaWQiOjU5OCwidW5vZmZpY2lhbCI6MjUsImZpeGVzIjo4MTExOSwiZml4ZWRQY3QiOjIyLCJkYXRhc2V0cyI6W10sInN0YXJzIjoyNDI5LCJpc3N1ZXMiOjI4LCJ0aGlzV2VlayI6eyJhZGRlZCI6NDUsInVwZGF0ZWQiOjE3MX0sIm51bURyaXZlcnMiOjEwLCJudW1Qcm92aWRlcnMiOjY1OX19fSwicGFyYW1ldGVycyI6eyJwcm92aWRlciI6eyJuYW1lIjoicHJvdmlkZXIiLCJpbiI6InBhdGgiLCJyZXF1aXJlZCI6dHJ1ZSwic2NoZW1hIjp7InR5cGUiOiJzdHJpbmciLCJtaW5MZW5ndGgiOjEsIm1heExlbmd0aCI6MjU1LCJleGFtcGxlIjoiYXBpcy5ndXJ1In19LCJhcGkiOnsibmFtZSI6ImFwaSIsImluIjoicGF0aCIsInJlcXVpcmVkIjp0cnVlLCJzY2hlbWEiOnsidHlwZSI6InN0cmluZyIsIm1pbkxlbmd0aCI6MSwibWF4TGVuZ3RoIjoyNTUsImV4YW1wbGUiOiIyLjEuMCJ9fX19fQo=\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://api.apis.guru/v2/\"\n },\n \"developer_portal\": {\n \"enabled\": false,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/apiguru-devportal.html\"\n }\n },\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"JWT Authentication\"\n }\n ],\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/providers.json\"\n ]\n },\n \"authorization\": [\n {\n \"profile\": \"JWT role based authorization\",\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/providers.json\"\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"profile\": \"apigw_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 0,\n \"delay\": 0,\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/metrics.json\"\n ]\n }\n ]\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\n }\n }\n }\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"apigw_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"2r/s\"\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"JWT Authentication\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"API 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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -5930,7 +5745,7 @@ "response": [] }, { - "name": "Petstore 3 API Gateway RateLimit + JWT AuthN/AuthZ + redocly + moesif", + "name": "APIGuru API Gateway RateLimit + JWT AuthN/AuthZ + redocly + moesif", "event": [ { "listen": "test", @@ -5953,7 +5768,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 \"ndk_http_module\",\n \"ngx_http_lua_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\n },\n \"visibility\": [\n {\n \"enabled\": true,\n \"type\": \"moesif\",\n \"moesif\": {\n \"application_id\": \"{{moesif_application_id}}\"\n }\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\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 \"ndk_http_module\",\n \"ngx_http_lua_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"APIGuru\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/apiguru\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://api.apis.guru/v2/openapi.yaml\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://api.apis.guru/v2/\"\n },\n \"developer_portal\": {\n \"enabled\": false,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/apiguru-devportal.html\"\n }\n },\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"JWT Authentication\"\n }\n ],\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/providers.json\"\n ]\n },\n \"authorization\": [\n {\n \"profile\": \"JWT role based authorization\",\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/providers.json\"\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"profile\": \"apigw_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 0,\n \"delay\": 0,\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/metrics.json\"\n ]\n }\n ],\n \"visibility\": [\n {\n \"enabled\": true,\n \"type\": \"moesif\",\n \"moesif\": {\n \"application_id\": \"{{moesif_application_id}}\"\n }\n }\n ]\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\n }\n }\n }\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"apigw_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"2r/s\"\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"JWT Authentication\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"API 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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -5974,48 +5789,517 @@ } }, "response": [] - }, + } + ] + }, + { + "name": "Petstore API", + "item": [ { - "name": "Petstore 3 API Gateway RateLimit + JWT AuthN/AuthZ + redocly + WAF", - "event": [ + "name": "API Client test requests", + "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": {}, - "requests": {} - } - } - ], - "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 },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\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" + "name": "Get Inventory (legitimate request)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "https://apigw.nginx.lab/petstore/store/inventory", + "protocol": "https", + "host": [ + "apigw", + "nginx", + "lab" + ], + "path": [ + "petstore", + "store", + "inventory" + ] + } + }, + "response": [] + }, + { + "name": "Get Inventory (malicious query string)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "https://apigw.nginx.lab/petstore/store/inventory?/etc/passwd", + "protocol": "https", + "host": [ + "apigw", + "nginx", + "lab" + ], + "path": [ + "petstore", + "store", + "inventory" + ], + "query": [ + { + "key": "/etc/passwd", + "value": null + } + ] + } + }, + "response": [] + }, + { + "name": "Get Inventory (XSS attack)", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "https://apigw.nginx.lab/petstore/store/inventory?", + "protocol": "https", + "host": [ + "apigw", + "nginx", + "lab" + ], + "path": [ + "petstore", + "store", + "inventory" + ], + "query": [ + { + "key": "", + "value": null + } + ] + } + }, + "response": [] + }, + { + "name": "Login without token", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "https://apigw.nginx.lab/petstore/user/login", + "protocol": "https", + "host": [ + "apigw", + "nginx", + "lab" + ], + "path": [ + "petstore", + "user", + "login" + ] + } + }, + "response": [] + }, + { + "name": "Login with \"DevOps\" token", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDI0ODEzNjcsImV4cCI6MTcwMjQ4MTM2OH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIl19.SKA_7MszAypMEtX5NDQ0TcUbVYx_Wt0hrtmuyTmrVKU", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "https://apigw.nginx.lab/petstore/user/login", + "protocol": "https", + "host": [ + "apigw", + "nginx", + "lab" + ], + "path": [ + "petstore", + "user", + "login" + ] + } + }, + "response": [] + }, + { + "name": "Login with \"Guest\" token", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDk3NjQ3NTMsImV4cCI6MTcwOTc2NDc1NH0.eyJuYW1lIjoiQWxpY2UgR3Vlc3QiLCJzdWIiOiJKV1Qgc3ViIGNsYWltIiwiaXNzIjoiSldUIGlzcyBjbGFpbSIsInJvbGVzIjpbImd1ZXN0Il19.jFJDq-33irz7uFxdI8c8fIb5TwTAU5BlemmIFVALUAE", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "https://apigw.nginx.lab/petstore/user/login", + "protocol": "https", + "host": [ + "apigw", + "nginx", + "lab" + ], + "path": [ + "petstore", + "user", + "login" + ] + } + }, + "response": [] + }, + { + "name": "Login with dual (DevOps & Guest) role token", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDk3NjQ3NTMsImV4cCI6MTcwOTc2NDc1NH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIiwiZ3Vlc3QiXX0.3ES7aVquklWqlZ4OWzt8rBz5px4kKZRgvifFVNomCsU", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "https://apigw.nginx.lab/petstore/user/login", + "protocol": "https", + "host": [ + "apigw", + "nginx", + "lab" + ], + "path": [ + "petstore", + "user", + "login" + ] + } + }, + "response": [] + }, + { + "name": "Upload pet image without token", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/octet-stream", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TS0UqChYRcchQXbSLijjWKhShQqgVWnUwuX5Ck4YkxcVRcC04+LFYdXBx1tXBVRAEP0CcHZwUXaTE/yWFFjEeHPfj3b3H3TtAaFSYanbFAFWzjFQiLmayq2LwFQEI6Mc4BmVm6nOSlITn+LqHj693UZ7lfe7P0ZvLmwzwicQxphsW8QbxzKalc94nDrOSnCM+J54w6ILEj1xXXH7jXHRY4JlhI52aJw4Ti8UOVjqYlQyVeJo4klM1yhcyLuc4b3FWKzXWuid/YSivrSxzneYIEljEEiSIUFBDGRVYiNKqkWIiRftxD/+w45fIpZCrDEaOBVShQnb84H/wu1uzMDXpJoXiQODFtj9GgeAu0Kzb9vexbTdPAP8zcKW1/dUGMPtJer2tRY6Avm3g4rqtKXvA5Q4w9KTLhuxIfppCoQC8n9E3ZYGBW6Bnze2ttY/TByBNXSVvgINDYKxI2ese7+7u7O3fM63+fgB5bXKpzZcBIwAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAAd0SU1FB+gFAhArKAvJglcAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAADElEQVQI12P4//8/AAX+Av7czFnnAAAAAElFTkSuQmCC" + }, + "url": { + "raw": "https://apigw.nginx.lab/petstore/pet/1/uploadImage", + "protocol": "https", + "host": [ + "apigw", + "nginx", + "lab" + ], + "path": [ + "petstore", + "pet", + "1", + "uploadImage" + ] + } + }, + "response": [] + }, + { + "name": "Upload pet image with \"DevOps\" token", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDI0ODEzNjcsImV4cCI6MTcwMjQ4MTM2OH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIl19.SKA_7MszAypMEtX5NDQ0TcUbVYx_Wt0hrtmuyTmrVKU", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/octet-stream", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TS0UqChYRcchQXbSLijjWKhShQqgVWnUwuX5Ck4YkxcVRcC04+LFYdXBx1tXBVRAEP0CcHZwUXaTE/yWFFjEeHPfj3b3H3TtAaFSYanbFAFWzjFQiLmayq2LwFQEI6Mc4BmVm6nOSlITn+LqHj693UZ7lfe7P0ZvLmwzwicQxphsW8QbxzKalc94nDrOSnCM+J54w6ILEj1xXXH7jXHRY4JlhI52aJw4Ti8UOVjqYlQyVeJo4klM1yhcyLuc4b3FWKzXWuid/YSivrSxzneYIEljEEiSIUFBDGRVYiNKqkWIiRftxD/+w45fIpZCrDEaOBVShQnb84H/wu1uzMDXpJoXiQODFtj9GgeAu0Kzb9vexbTdPAP8zcKW1/dUGMPtJer2tRY6Avm3g4rqtKXvA5Q4w9KTLhuxIfppCoQC8n9E3ZYGBW6Bnze2ttY/TByBNXSVvgINDYKxI2ese7+7u7O3fM63+fgB5bXKpzZcBIwAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAAd0SU1FB+gFAhArKAvJglcAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAADElEQVQI12P4//8/AAX+Av7czFnnAAAAAElFTkSuQmCC" + }, + "url": { + "raw": "https://apigw.nginx.lab/petstore/pet/1/uploadImage", + "protocol": "https", + "host": [ + "apigw", + "nginx", + "lab" + ], + "path": [ + "petstore", + "pet", + "1", + "uploadImage" + ] + } + }, + "response": [] + }, + { + "name": "Upload pet image with \"Guest\" token", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDk3NjQ3NTMsImV4cCI6MTcwOTc2NDc1NH0.eyJuYW1lIjoiQWxpY2UgR3Vlc3QiLCJzdWIiOiJKV1Qgc3ViIGNsYWltIiwiaXNzIjoiSldUIGlzcyBjbGFpbSIsInJvbGVzIjpbImd1ZXN0Il19.jFJDq-33irz7uFxdI8c8fIb5TwTAU5BlemmIFVALUAE", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "file", + "value": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TS0UqChYRcchQXbSLijjWKhShQqgVWnUwuX5Ck4YkxcVRcC04+LFYdXBx1tXBVRAEP0CcHZwUXaTE/yWFFjEeHPfj3b3H3TtAaFSYanbFAFWzjFQiLmayq2LwFQEI6Mc4BmVm6nOSlITn+LqHj693UZ7lfe7P0ZvLmwzwicQxphsW8QbxzKalc94nDrOSnCM+J54w6ILEj1xXXH7jXHRY4JlhI52aJw4Ti8UOVjqYlQyVeJo4klM1yhcyLuc4b3FWKzXWuid/YSivrSxzneYIEljEEiSIUFBDGRVYiNKqkWIiRftxD/+w45fIpZCrDEaOBVShQnb84H/wu1uzMDXpJoXiQODFtj9GgeAu0Kzb9vexbTdPAP8zcKW1/dUGMPtJer2tRY6Avm3g4rqtKXvA5Q4w9KTLhuxIfppCoQC8n9E3ZYGBW6Bnze2ttY/TByBNXSVvgINDYKxI2ese7+7u7O3fM63+fgB5bXKpzZcBIwAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAAd0SU1FB+gFAhArKAvJglcAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAADElEQVQI12P4//8/AAX+Av7czFnnAAAAAElFTkSuQmCC", + "type": "text" + }, + { + "key": "type", + "value": "image/png", + "type": "text" + } + ] + }, + "url": { + "raw": "https://apigw.nginx.lab/petstore/pet/1/uploadImage", + "protocol": "https", + "host": [ + "apigw", + "nginx", + "lab" + ], + "path": [ + "petstore", + "pet", + "1", + "uploadImage" + ] + } + }, + "response": [] + } + ], + "description": "This folder contains requests to access the Petstore API published through NGINX using the Declarative API" + }, + { + "name": "Petstore 3 API Gateway RateLimit + JWT AuthN/AuthZ + redocly", + "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": {}, + "requests": {} + } + } + ], + "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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\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 3 API Gateway RateLimit + JWT AuthN/AuthZ + backstage", + "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": {}, + "requests": {} + } + } + ], + "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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\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 3 API Gateway RateLimit + JWT AuthN/AuthZ + redocly + moesif", + "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": {}, + "requests": {} + } + } + ], + "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 \"ndk_http_module\",\n \"ngx_http_lua_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\n },\n \"visibility\": [\n {\n \"enabled\": true,\n \"type\": \"moesif\",\n \"moesif\": {\n \"application_id\": \"{{moesif_application_id}}\"\n }\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\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 3 API Gateway RateLimit + JWT AuthN/AuthZ + redocly + 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": {}, + "requests": {} + } + } + ], + "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 },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\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}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\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" ] } }, @@ -6045,7 +6329,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 ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"syslog:server=192.168.2.13:514\"\n },\n \"error\": {\n \"destination\": \"syslog:server=192.168.2.13:514\"\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 }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\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 },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"syslog:server=192.168.2.13:514\"\n },\n \"error\": {\n \"destination\": \"syslog:server=192.168.2.13:514\"\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 }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\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}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -6091,7 +6375,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 \"ndk_http_module\",\n \"ngx_http_lua_module\",\n \"ngx_http_app_protect_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"cache\": {\n \"profile\": \"10m cache\",\n \"key\": \"$uri\",\n \"validity\": [\n {\n \"code\": \"200\",\n \"ttl\": \"5s\"\n }\n ]\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": false,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\n },\n \"visibility\": [\n {\n \"enabled\": true,\n \"type\": \"moesif\",\n \"moesif\": {\n \"application_id\": \"{{moesif_application_id}}\"\n }\n }\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 \"cache\": [\n {\n \"profile\": \"10m cache\",\n \"key\": \"$http_method$uri\",\n \"validity\": [\n {\n \"code\": \"any\",\n \"ttl\": \"30s\"\n },\n {\n \"code\": \"302\",\n \"ttl\": \"5m\"\n }\n ],\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/store/inventory\"\n ]\n }\n ]\n },\n \"cache\": {\n \"profile\": \"10m cache\",\n \"key\": \"$http_method$uri\",\n \"validity\": [\n {\n \"code\": \"any\",\n \"ttl\": \"30s\"\n },\n {\n \"code\": \"302\",\n \"ttl\": \"5m\"\n }\n ]\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"cache\": [\n {\n \"name\": \"10m cache\",\n \"basepath\": \"/tmp\",\n \"size\": \"10m\",\n \"ttl\": \"10m\"\n }\n ],\n ,\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\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 \"ndk_http_module\",\n \"ngx_http_lua_module\",\n \"ngx_http_app_protect_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"cache\": {\n \"profile\": \"10m cache\",\n \"key\": \"$uri\",\n \"validity\": [\n {\n \"code\": \"200\",\n \"ttl\": \"5s\"\n }\n ]\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": false,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\n },\n \"visibility\": [\n {\n \"enabled\": true,\n \"type\": \"moesif\",\n \"moesif\": {\n \"application_id\": \"{{moesif_application_id}}\"\n }\n }\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 \"cache\": [\n {\n \"profile\": \"10m cache\",\n \"key\": \"$http_method$uri\",\n \"validity\": [\n {\n \"code\": \"any\",\n \"ttl\": \"30s\"\n },\n {\n \"code\": \"302\",\n \"ttl\": \"5m\"\n }\n ],\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/store/inventory\"\n ]\n }\n ]\n },\n \"cache\": {\n \"profile\": \"10m cache\",\n \"key\": \"$http_method$uri\",\n \"validity\": [\n {\n \"code\": \"any\",\n \"ttl\": \"30s\"\n },\n {\n \"code\": \"302\",\n \"ttl\": \"5m\"\n }\n ]\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"cache\": [\n {\n \"name\": \"10m cache\",\n \"basepath\": \"/tmp\",\n \"size\": \"10m\",\n \"ttl\": \"10m\"\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}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -6930,7 +7214,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\": 5\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.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\": 5\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -6976,7 +7260,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\": 5,\n \"modules\": [\n \"ngx_http_app_protect_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.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}}/{{ngc_api_version}}/nap-policy-gitops.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\": 5,\n \"modules\": [\n \"ngx_http_app_protect_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\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}}/{{ngc_api_version}}/nap-policy-gitops.json\"\n }\n }\n ]\n }\n ]\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -7480,7 +7764,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 },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -7526,7 +7810,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 ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-blocked.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 \"ngx_http_app_protect_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\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}}/{{ngc_api_version}}/nap-policy-xss-blocked.json\"\n }\n }\n ]\n }\n ]\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -7815,7 +8099,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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"vm-blank.ff.lan\"\n ],\n \"resolver\": \"internal_lan\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\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 \"resolvers\": [\n {\n \"name\": \"internal_lan\",\n \"address\": \"192.168.2.13\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"vm-blank.ff.lan\"\n ],\n \"resolver\": \"internal_lan\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"internal_lan\",\n \"address\": \"192.168.2.13\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\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}", "options": { "raw": { "language": "json" @@ -7866,7 +8150,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 ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/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 \"ngx_http_app_protect_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\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}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -7959,7 +8243,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 ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert2.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert2.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 \"modules\": [\n \"ngx_http_app_protect_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert2.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert2.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -8202,7 +8486,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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.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}}/{{ngc_api_version}}/testcert.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 \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.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}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -8248,7 +8532,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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.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}}/{{ngc_api_version}}/testcert.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}", + "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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.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}}/{{ngc_api_version}}/testcert.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}", "options": { "raw": { "language": "json" @@ -8354,7 +8638,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_acme_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"resolver\": \"Google\",\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 \"acme_issuer\": \"ACME example issuer\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"acme_issuers\": [\n {\n \"name\": \"ACME example issuer\",\n \"uri\": \"https://acme.example.com/directory\",\n \"contact\": \"admin@example.test\",\n \"account_key\": \"rsa:2048\",\n \"ssl_verify\": true,\n \"ssl_trusted_certificate\": \"cacert\",\n \"accept_terms_of_service\": true\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"cacert\",\n \"contents\": {\n \"content\": \"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZjekNDQTF1Z0F3SUJBZ0lVVnNRZkFaTW4vazNRTU9nc0RuVEdUaU9PbGJ3d0RRWUpLb1pJaHZjTkFRRUwKQlFBd1NURUxNQWtHQTFVRUJoTUNTVlF4RFRBTEJnTlZCQWdNQkVGemRHa3hFVEFQQmdOVkJBb01DRlJsYzNRZwpUR0ZpTVJnd0ZnWURWUVFEREE5MmJTMWliR0Z1YXk1bVppNXNZVzR3SGhjTk1qTXdOakE0TURrMU5EQTRXaGNOCk1qUXdOakEzTURrMU5EQTRXakJKTVFzd0NRWURWUVFHRXdKSlZERU5NQXNHQTFVRUNBd0VRWE4wYVRFUk1BOEcKQTFVRUNnd0lWR1Z6ZENCTVlXSXhHREFXQmdOVkJBTU1EM1p0TFdKc1lXNXJMbVptTG14aGJqQ0NBaUl3RFFZSgpLb1pJaHZjTkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFLMlQwWXpkcjB0dWQzaVJRNGNzaGNhRVJTRzVjTDE2CkhRblhoYWw4emlUL1VRQUNIUGdzZDYwcWlEaldvQTJXb0lGWFFpUHkzOG1vZGtWRlR4Qmt5U2VldndOOFJiLzEKOFhaMS8yS1RnVmRDcHkvNm11WE15bXZYODJad05CVkV3QnoxUk5kbklUSk44cVh3a0d4bHozbDBib1loRkFyUQpNdmkxcW1RaHpDa2Zpb041MVkrYlBXOXpTQlFQdXNrcXJYYzRqTTJ0VENNQ2pTcFlvd1hXM1ppRmc5WEJ1Z09aCjFmdWd1Zmw4K1FJYzNZSEFoL1Z1NloraXFEOGxQeGRKODlBeDZaazVtOGdkVG9JdUhBbUNWaHFpUXBGRjkzSTgKbkYrSnRuYnBaNTRJUTZBbWYrYiswakMxdmY4Kzg0WUppaEVzWExyaGMxZTRTZ2dwdzEvcWpDb21QblhGVjEzUwpsUG5kVlhVR0taa1ZKdXdZTjJyZElmd3YrdCs5MGhwUVBmNmFBTjRCamRxOXdkdkQzSXVnS2JYZG5CQ0FUTEY4ClYyRTFTSE9VZGdRY3duK1d1WDVVOGdPa3B2b2VFN0g1REJ6Rks1WTZ2SHZlaTRlNkp3RTRDK3FJL1BmbTgreTEKNEpsOFBSOW5JQmdGQ3hrZWpwa2tRQ0I5U0dvMVZidzZhWmdZd0VQNHh6YXFYYXV3L3F4c0oxNUkrRTBndEs1OApuWUtkM0hqelk5Slh6V0NVNTdXbmc2SzNvTTIzNXpyRzJnNm1FaHQ4SStDckVMUFNuZURjZU8zVlJkc2dlblBCCis4U1JxVU8vWG9LWHNEU3I5amoxdWluVzYwTG5MZ0Zmc3JQeGlQVlZlMFh1TFZESlhCSlNoRDZDeGRyMnBSOGQKS25SRDZrTFpZZEtMQWdNQkFBR2pVekJSTUIwR0ExVWREZ1FXQkJRUzZnS2pMK3VFc0dXeXVjbTZyb0xVaXpqVwpWREFmQmdOVkhTTUVHREFXZ0JRUzZnS2pMK3VFc0dXeXVjbTZyb0xVaXpqV1ZEQVBCZ05WSFJNQkFmOEVCVEFECkFRSC9NQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUNBUUJad3B4Z2Z4N2thZFhvRHNyT1hUVXJ6dEFPMkFQRVJNaTAKaTkyNk9DTGFPbVVYZW1uKytXSUU1K2tUSE0wcS8vbUZCTURzSmdZSFVLUlNvRGNsNmh4TnVFNUNzS2trRVFTSgpMTHZrWlB0S2J5NGlxMitLZ1JtdVZxbXJNVTBYQzZMZDl3WmttL2huUjNtT3V6bko4MGZmV1JDQ0xGWDEwY2EzCnc5TGM1d1JLTFBZZXQvcEs5SitOYWN3TFJRYTczVFovMUpQNW9BU3czVjNoYkxlLy9UeWpnOURqUlZGY3FYWnEKWWs2Mm5qSkhZVzh3WmlhZzc0QXU4dHE5OG5KandBV1ROMFV5L2w1Q2VpWnV5bzZlU0RHVDNJNm1BdGU1VXBvWAppNXBkYlZ6VDdOZC9IOEwwZHZNdVZ2N0FmakZlcU91cUZNNkkzTnlvbStLWENxNmJQdGxBWEkzeVFZc0t4ZlRkCkw3SnRaTmx6MGJ6eHJhcHI4RmpYcjhML1ZkeHQza00xMnJwb2kzL3hsckR6Q2Q2b2YrQ1MxelBocUdpOUhvcUoKZEU5VGhYMklTdkd2akVSYzVVNFRsNjJBNHNyeGJQbUt0eWx3dGNGVEJacUJiRGY3ZjBBc2cveWhndXdTcktsQQpBNkRWVXVCRFErdGpwZ0N0b0ZlOEhLVDJ6UFVlaEQ2ZjVNQkhmU2ZUZ1crTlhFSXNvVDNsampjY1hsYXhPcFJWCkNQNWxCczNmekxyYnBxbUlLaWZhdWlTNWM4TzlSUjhjQTVzeWlBOTBmbmJIdDlmdGxpRG9jcFRzNUtrbjk2NkIKZUxMM1dXVldCYUtvanJzY1RkVXJoalNnVVBmam5FTXpnVzR2eEc3d3BVNHR2ME4yaEtHUWc0bVhhcDV0SU5Pcwp4WktnZXRHUldnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=\"\n }\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", + "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_acme_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"resolver\": \"Google\",\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 \"acme_issuer\": \"ACME example issuer\",\n \"ciphers\": \"DEFAULT\",\n \"protocols\": [\n \"TLSv1.2\",\n \"TLSv1.3\"\n ]\n }\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"acme_issuers\": [\n {\n \"name\": \"ACME example issuer\",\n \"uri\": \"https://acme.example.com/directory\",\n \"contact\": \"admin@example.test\",\n \"account_key\": \"rsa:2048\",\n \"ssl_verify\": true,\n \"ssl_trusted_certificate\": \"cacert\",\n \"accept_terms_of_service\": true\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"cacert\",\n \"contents\": {\n \"content\": \"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZjekNDQTF1Z0F3SUJBZ0lVVnNRZkFaTW4vazNRTU9nc0RuVEdUaU9PbGJ3d0RRWUpLb1pJaHZjTkFRRUwKQlFBd1NURUxNQWtHQTFVRUJoTUNTVlF4RFRBTEJnTlZCQWdNQkVGemRHa3hFVEFQQmdOVkJBb01DRlJsYzNRZwpUR0ZpTVJnd0ZnWURWUVFEREE5MmJTMWliR0Z1YXk1bVppNXNZVzR3SGhjTk1qTXdOakE0TURrMU5EQTRXaGNOCk1qUXdOakEzTURrMU5EQTRXakJKTVFzd0NRWURWUVFHRXdKSlZERU5NQXNHQTFVRUNBd0VRWE4wYVRFUk1BOEcKQTFVRUNnd0lWR1Z6ZENCTVlXSXhHREFXQmdOVkJBTU1EM1p0TFdKc1lXNXJMbVptTG14aGJqQ0NBaUl3RFFZSgpLb1pJaHZjTkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFLMlQwWXpkcjB0dWQzaVJRNGNzaGNhRVJTRzVjTDE2CkhRblhoYWw4emlUL1VRQUNIUGdzZDYwcWlEaldvQTJXb0lGWFFpUHkzOG1vZGtWRlR4Qmt5U2VldndOOFJiLzEKOFhaMS8yS1RnVmRDcHkvNm11WE15bXZYODJad05CVkV3QnoxUk5kbklUSk44cVh3a0d4bHozbDBib1loRkFyUQpNdmkxcW1RaHpDa2Zpb041MVkrYlBXOXpTQlFQdXNrcXJYYzRqTTJ0VENNQ2pTcFlvd1hXM1ppRmc5WEJ1Z09aCjFmdWd1Zmw4K1FJYzNZSEFoL1Z1NloraXFEOGxQeGRKODlBeDZaazVtOGdkVG9JdUhBbUNWaHFpUXBGRjkzSTgKbkYrSnRuYnBaNTRJUTZBbWYrYiswakMxdmY4Kzg0WUppaEVzWExyaGMxZTRTZ2dwdzEvcWpDb21QblhGVjEzUwpsUG5kVlhVR0taa1ZKdXdZTjJyZElmd3YrdCs5MGhwUVBmNmFBTjRCamRxOXdkdkQzSXVnS2JYZG5CQ0FUTEY4ClYyRTFTSE9VZGdRY3duK1d1WDVVOGdPa3B2b2VFN0g1REJ6Rks1WTZ2SHZlaTRlNkp3RTRDK3FJL1BmbTgreTEKNEpsOFBSOW5JQmdGQ3hrZWpwa2tRQ0I5U0dvMVZidzZhWmdZd0VQNHh6YXFYYXV3L3F4c0oxNUkrRTBndEs1OApuWUtkM0hqelk5Slh6V0NVNTdXbmc2SzNvTTIzNXpyRzJnNm1FaHQ4SStDckVMUFNuZURjZU8zVlJkc2dlblBCCis4U1JxVU8vWG9LWHNEU3I5amoxdWluVzYwTG5MZ0Zmc3JQeGlQVlZlMFh1TFZESlhCSlNoRDZDeGRyMnBSOGQKS25SRDZrTFpZZEtMQWdNQkFBR2pVekJSTUIwR0ExVWREZ1FXQkJRUzZnS2pMK3VFc0dXeXVjbTZyb0xVaXpqVwpWREFmQmdOVkhTTUVHREFXZ0JRUzZnS2pMK3VFc0dXeXVjbTZyb0xVaXpqV1ZEQVBCZ05WSFJNQkFmOEVCVEFECkFRSC9NQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUNBUUJad3B4Z2Z4N2thZFhvRHNyT1hUVXJ6dEFPMkFQRVJNaTAKaTkyNk9DTGFPbVVYZW1uKytXSUU1K2tUSE0wcS8vbUZCTURzSmdZSFVLUlNvRGNsNmh4TnVFNUNzS2trRVFTSgpMTHZrWlB0S2J5NGlxMitLZ1JtdVZxbXJNVTBYQzZMZDl3WmttL2huUjNtT3V6bko4MGZmV1JDQ0xGWDEwY2EzCnc5TGM1d1JLTFBZZXQvcEs5SitOYWN3TFJRYTczVFovMUpQNW9BU3czVjNoYkxlLy9UeWpnOURqUlZGY3FYWnEKWWs2Mm5qSkhZVzh3WmlhZzc0QXU4dHE5OG5KandBV1ROMFV5L2w1Q2VpWnV5bzZlU0RHVDNJNm1BdGU1VXBvWAppNXBkYlZ6VDdOZC9IOEwwZHZNdVZ2N0FmakZlcU91cUZNNkkzTnlvbStLWENxNmJQdGxBWEkzeVFZc0t4ZlRkCkw3SnRaTmx6MGJ6eHJhcHI4RmpYcjhML1ZkeHQza00xMnJwb2kzL3hsckR6Q2Q2b2YrQ1MxelBocUdpOUhvcUoKZEU5VGhYMklTdkd2akVSYzVVNFRsNjJBNHNyeGJQbUt0eWx3dGNGVEJacUJiRGY3ZjBBc2cveWhndXdTcktsQQpBNkRWVXVCRFErdGpwZ0N0b0ZlOEhLVDJ6UFVlaEQ2ZjVNQkhmU2ZUZ1crTlhFSXNvVDNsampjY1hsYXhPcFJWCkNQNWxCczNmekxyYnBxbUlLaWZhdWlTNWM4TzlSUjhjQTVzeWlBOTBmbmJIdDlmdGxpRG9jcFRzNUtrbjk2NkIKZUxMM1dXVldCYUtvanJzY1RkVXJoalNnVVBmam5FTXpnVzR2eEc3d3BVNHR2ME4yaEtHUWc0bVhhcDV0SU5Pcwp4WktnZXRHUldnPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -8464,15 +8748,155 @@ "path": [ "{{ngc_api_version}}", "config", - "{{configUid}}", - "status" + "{{configUid}}", + "status" + ] + } + }, + "response": [] + }, + { + "name": "1b. 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": "2. Publish application - echo test", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var respData = JSON.parse(responseBody);", + "", + "tests[\"configUid is: \" +respData.configUid] = respData.configUid;", + "tests[\"submissionUid is: \" + respData.submissionUid] = respData.submissionUid;", + "", + "pm.collectionVariables.set('configUid',respData.configUid);", + "pm.collectionVariables.set('submissionUid1',respData.submissionUid);" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "PATCH", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"synchronous\": false,\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\"\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": true\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test echo app\",\n \"names\": [\n \"echo.vm-blank.ie.ff.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:80\"\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/echo-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/echo-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test-echo-upstream\"\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 \"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": "3. Publish application - random joke", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var respData = JSON.parse(responseBody);", + "", + "tests[\"configUid is: \" +respData.configUid] = respData.configUid;", + "tests[\"submissionUid is: \" + respData.submissionUid] = respData.submissionUid;", + "", + "pm.collectionVariables.set('configUid',respData.configUid);", + "pm.collectionVariables.set('submissionUid2',respData.submissionUid);" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "PATCH", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"synchronous\": false,\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\"\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": true\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Random joke application\",\n \"names\": [\n \"randomjoke.vm-blank.ie.ff.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:80\"\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/joke-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/joke-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://randomjoke-upstream\"\n }\n ],\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"Host\",\n \"value\": \"official-joke-api.appspot.com\"\n }\n ]\n }\n }\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"randomjoke-upstream\",\n \"origin\": [\n {\n \"server\": \"official-joke-api.appspot.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": "1b. Get declaration", + "name": "4a. Get asynchronous submission status - echo test", "event": [ { "listen": "test", @@ -8480,7 +8904,8 @@ "exec": [ "" ], - "type": "text/javascript" + "type": "text/javascript", + "packages": {} } } ], @@ -8500,7 +8925,7 @@ } }, "url": { - "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}", + "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}/submission/{{submissionUid1}}", "protocol": "http", "host": [ "{{ncg_host}}" @@ -8509,38 +8934,37 @@ "path": [ "{{ngc_api_version}}", "config", - "{{configUid}}" + "{{configUid}}", + "submission", + "{{submissionUid1}}" ] } }, "response": [] }, { - "name": "2. Publish application - echo test", + "name": "4b. Get asynchronous submission status - random joke", "event": [ { "listen": "test", "script": { "exec": [ - "var respData = JSON.parse(responseBody);", - "", - "tests[\"configUid is: \" +respData.configUid] = respData.configUid;", - "tests[\"submissionUid is: \" + respData.submissionUid] = respData.submissionUid;", - "", - "pm.collectionVariables.set('configUid',respData.configUid);", - "pm.collectionVariables.set('submissionUid1',respData.submissionUid);" + "" ], "type": "text/javascript", "packages": {} } } ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, "request": { - "method": "PATCH", + "method": "GET", "header": [], "body": { "mode": "raw", - "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"synchronous\": false,\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\"\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": true\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test echo app\",\n \"names\": [\n \"echo.vm-blank.ie.ff.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:80\"\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/echo-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/echo-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test-echo-upstream\"\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 \"upstreams\": [\n {\n \"name\": \"test-echo-upstream\",\n \"origin\": [\n {\n \"server\": \"echo.free.beeceptor.com\"\n }\n ]\n }\n ]\n }\n }\n}", + "raw": "", "options": { "raw": { "language": "json" @@ -8548,7 +8972,7 @@ } }, "url": { - "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}", + "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}/submission/{{submissionUid2}}", "protocol": "http", "host": [ "{{ncg_host}}" @@ -8557,38 +8981,36 @@ "path": [ "{{ngc_api_version}}", "config", - "{{configUid}}" + "{{configUid}}", + "submission", + "{{submissionUid2}}" ] } }, "response": [] }, { - "name": "3. Publish application - random joke", + "name": "5. Get declaration", "event": [ { "listen": "test", "script": { "exec": [ - "var respData = JSON.parse(responseBody);", - "", - "tests[\"configUid is: \" +respData.configUid] = respData.configUid;", - "tests[\"submissionUid is: \" + respData.submissionUid] = respData.submissionUid;", - "", - "pm.collectionVariables.set('configUid',respData.configUid);", - "pm.collectionVariables.set('submissionUid2',respData.submissionUid);" + "" ], - "type": "text/javascript", - "packages": {} + "type": "text/javascript" } } ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, "request": { - "method": "PATCH", + "method": "GET", "header": [], "body": { "mode": "raw", - "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"synchronous\": false,\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\"\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": true\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Random joke application\",\n \"names\": [\n \"randomjoke.vm-blank.ie.ff.lan\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:80\"\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/joke-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/joke-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://randomjoke-upstream\"\n }\n ],\n \"headers\": {\n \"to_server\": {\n \"set\": [\n {\n \"name\": \"Host\",\n \"value\": \"official-joke-api.appspot.com\"\n }\n ]\n }\n }\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"randomjoke-upstream\",\n \"origin\": [\n {\n \"server\": \"official-joke-api.appspot.com\"\n }\n ]\n }\n ]\n }\n }\n}", + "raw": "", "options": { "raw": { "language": "json" @@ -8612,189 +9034,335 @@ "response": [] }, { - "name": "4a. Get asynchronous submission status - echo test", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "" - ], - "type": "text/javascript", - "packages": {} - } + "name": "6. Test application - echo test", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://echo.vm-blank.ie.ff.lan", + "protocol": "http", + "host": [ + "echo", + "vm-blank", + "ie", + "ff", + "lan" + ] } - ], - "protocolProfileBehavior": { - "disableBodyPruning": true }, + "response": [] + }, + { + "name": "7. Test application - random joke", "request": { "method": "GET", "header": [], - "body": { - "mode": "raw", - "raw": "", - "options": { - "raw": { - "language": "json" + "url": { + "raw": "http://randomjoke.vm-blank.ie.ff.lan/random_joke", + "protocol": "http", + "host": [ + "randomjoke", + "vm-blank", + "ie", + "ff", + "lan" + ], + "path": [ + "random_joke" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "API Gateway", + "item": [ + { + "name": "APIs.guru", + "item": [ + { + "name": "API Client test requests", + "item": [ + { + "name": "Metrics", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "https://apigw.nginx.lab/apiguru/metrics.json", + "protocol": "https", + "host": [ + "apigw", + "nginx", + "lab" + ], + "path": [ + "apiguru", + "metrics.json" + ] + } + }, + "response": [] + }, + { + "name": "Providers - no authentication", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "https://apigw.nginx.lab/apiguru/providers.json", + "protocol": "https", + "host": [ + "apigw", + "nginx", + "lab" + ], + "path": [ + "apiguru", + "providers.json" + ] + } + }, + "response": [] + }, + { + "name": "Providers - auth with \"DevOps\" token", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDI0ODEzNjcsImV4cCI6MTcwMjQ4MTM2OH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIl19.SKA_7MszAypMEtX5NDQ0TcUbVYx_Wt0hrtmuyTmrVKU", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "https://apigw.nginx.lab/apiguru/providers.json", + "protocol": "https", + "host": [ + "apigw", + "nginx", + "lab" + ], + "path": [ + "apiguru", + "providers.json" + ] + } + }, + "response": [] + }, + { + "name": "Providers - auth with \"Guest\" token", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDk3NjQ3NTMsImV4cCI6MTcwOTc2NDc1NH0.eyJuYW1lIjoiQWxpY2UgR3Vlc3QiLCJzdWIiOiJKV1Qgc3ViIGNsYWltIiwiaXNzIjoiSldUIGlzcyBjbGFpbSIsInJvbGVzIjpbImd1ZXN0Il19.jFJDq-33irz7uFxdI8c8fIb5TwTAU5BlemmIFVALUAE", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "https://apigw.nginx.lab/apiguru/providers.json", + "protocol": "https", + "host": [ + "apigw", + "nginx", + "lab" + ], + "path": [ + "apiguru", + "providers.json" + ] + } + }, + "response": [] + }, + { + "name": "Providers - auth with \"DevOps\" and \"Guest\" token", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDk3NjQ3NTMsImV4cCI6MTcwOTc2NDc1NH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIiwiZ3Vlc3QiXX0.3ES7aVquklWqlZ4OWzt8rBz5px4kKZRgvifFVNomCsU", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "https://apigw.nginx.lab/apiguru/providers.json", + "protocol": "https", + "host": [ + "apigw", + "nginx", + "lab" + ], + "path": [ + "apiguru", + "providers.json" + ] + } + }, + "response": [] + } + ], + "description": "This folder contains requests to access the Petstore API published through NGINX using the Declarative API" + }, + { + "name": "APIGuru API Gateway RateLimit + JWT AuthN/AuthZ + redocly - YAML OpenAPI schema", + "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": {}, + "requests": {} + } } - } - }, - "url": { - "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}/submission/{{submissionUid1}}", - "protocol": "http", - "host": [ - "{{ncg_host}}" ], - "port": "{{ncg_port}}", - "path": [ - "{{ngc_api_version}}", - "config", - "{{configUid}}", - "submission", - "{{submissionUid1}}" - ] - } - }, - "response": [] - }, - { - "name": "4b. Get asynchronous submission status - random joke", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [], - "body": { - "mode": "raw", - "raw": "", - "options": { - "raw": { - "language": "json" + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": []\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"APIGuru\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/apiguru\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://api.apis.guru/v2/openapi.yaml\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://api.apis.guru/v2/\"\n },\n \"developer_portal\": {\n \"enabled\": false,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/apiguru-devportal.html\"\n }\n },\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"JWT Authentication\"\n }\n ],\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/providers.json\"\n ]\n },\n \"authorization\": [\n {\n \"profile\": \"JWT role based authorization\",\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/providers.json\"\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"profile\": \"apigw_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 0,\n \"delay\": 0,\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/metrics.json\"\n ]\n }\n ]\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\n }\n }\n }\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"apigw_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"2r/s\"\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"JWT Authentication\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"API 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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\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}}/submission/{{submissionUid2}}", - "protocol": "http", - "host": [ - "{{ncg_host}}" - ], - "port": "{{ncg_port}}", - "path": [ - "{{ngc_api_version}}", - "config", - "{{configUid}}", - "submission", - "{{submissionUid2}}" - ] - } - }, - "response": [] - }, - { - "name": "5. 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" + "name": "APIGuru API Gateway RateLimit + JWT AuthN/AuthZ + redocly - local OpenAPI schema", + "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": {}, + "requests": {} + } } - } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": []\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"APIGuru\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/apiguru\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"eyJvcGVuYXBpIjoiMy4wLjAiLCJ4LW9wdGljLXVybCI6Imh0dHBzOi8vYXBwLnVzZW9wdGljLmNvbS9vcmdhbml6YXRpb25zL2ZlYmY4YWM2LWVlNjctNDU2NS1iNDVhLTVjODVhNDY5ZGNhNy9hcGlzL18wZktXcVV2aHM5c3NZTmtxMWstYyIsIngtb3B0aWMtc3RhbmRhcmQiOiJAZmViZjhhYzYtZWU2Ny00NTY1LWI0NWEtNWM4NWE0NjlkY2E3L0Z6NktVM193TUlPNWlKNl9WVVozMCIsImluZm8iOnsidmVyc2lvbiI6IjIuMi4wIiwidGl0bGUiOiJBUElzLmd1cnUiLCJkZXNjcmlwdGlvbiI6Ildpa2lwZWRpYSBmb3IgV2ViIEFQSXMuIFJlcG9zaXRvcnkgb2YgQVBJIGRlZmluaXRpb25zIGluIE9wZW5BUEkgZm9ybWF0LlxuKipXYXJuaW5nKio6IElmIHlvdSB3YW50IHRvIGJlIG5vdGlmaWVkIGFib3V0IGNoYW5nZXMgaW4gYWR2YW5jZSBwbGVhc2Ugam9pbiBvdXIgW1NsYWNrIGNoYW5uZWxdKGh0dHBzOi8vam9pbi5zbGFjay5jb20vdC9tZXJtYWRlL3NoYXJlZF9pbnZpdGUvenQtZzc4Zzd4aXItTUxFX0NUQ2NYQ2RmSmZHM0NKZTlxQSkuXG5DbGllbnQgc2FtcGxlOiBbW0RlbW9dXShodHRwczovL2FwaXMuZ3VydS9zaW1wbGUtdWkpIFtbUmVwb11dKGh0dHBzOi8vZ2l0aHViLmNvbS9BUElzLWd1cnUvc2ltcGxlLXVpKVxuIiwiY29udGFjdCI6eyJuYW1lIjoiQVBJcy5ndXJ1IiwidXJsIjoiaHR0cHM6Ly9BUElzLmd1cnUiLCJlbWFpbCI6Im1pa2UucmFscGhzb25AZ21haWwuY29tIn0sImxpY2Vuc2UiOnsibmFtZSI6IkNDMCAxLjAiLCJ1cmwiOiJodHRwczovL2dpdGh1Yi5jb20vQVBJcy1ndXJ1L29wZW5hcGktZGlyZWN0b3J5I2xpY2Vuc2VzIn0sIngtbG9nbyI6eyJ1cmwiOiJodHRwczovL2FwaXMuZ3VydS9icmFuZGluZy9sb2dvX3ZlcnRpY2FsLnN2ZyJ9fSwiZXh0ZXJuYWxEb2NzIjp7InVybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9BUElzLWd1cnUvb3BlbmFwaS1kaXJlY3RvcnkvYmxvYi9tYXN0ZXIvQVBJLm1kIn0sInNlcnZlcnMiOlt7InVybCI6Imh0dHBzOi8vYXBpLmFwaXMuZ3VydS92MiJ9XSwic2VjdXJpdHkiOltdLCJ0YWdzIjpbeyJuYW1lIjoiQVBJcyIsImRlc2NyaXB0aW9uIjoiQWN0aW9ucyByZWxhdGluZyB0byBBUElzIGluIHRoZSBjb2xsZWN0aW9uIn1dLCJwYXRocyI6eyIvcHJvdmlkZXJzLmpzb24iOnsiZ2V0Ijp7Im9wZXJhdGlvbklkIjoiZ2V0UHJvdmlkZXJzIiwidGFncyI6WyJBUElzIl0sInN1bW1hcnkiOiJMaXN0IGFsbCBwcm92aWRlcnMiLCJkZXNjcmlwdGlvbiI6Ikxpc3QgYWxsIHRoZSBwcm92aWRlcnMgaW4gdGhlIGRpcmVjdG9yeVxuIiwicmVzcG9uc2VzIjp7IjIwMCI6eyJkZXNjcmlwdGlvbiI6Ik9LIiwiY29udGVudCI6eyJhcHBsaWNhdGlvbi9qc29uIjp7InNjaGVtYSI6eyJ0eXBlIjoib2JqZWN0IiwicHJvcGVydGllcyI6eyJkYXRhIjp7InR5cGUiOiJhcnJheSIsIml0ZW1zIjp7InR5cGUiOiJzdHJpbmciLCJtaW5MZW5ndGgiOjF9LCJtaW5JdGVtcyI6MX19fX19fX19fSwiL3twcm92aWRlcn0uanNvbiI6eyJnZXQiOnsib3BlcmF0aW9uSWQiOiJnZXRQcm92aWRlciIsInRhZ3MiOlsiQVBJcyJdLCJzdW1tYXJ5IjoiTGlzdCBhbGwgQVBJcyBmb3IgYSBwYXJ0aWN1bGFyIHByb3ZpZGVyIiwiZGVzY3JpcHRpb24iOiJMaXN0IGFsbCBBUElzIGluIHRoZSBkaXJlY3RvcnkgZm9yIGEgcGFydGljdWxhciBwcm92aWRlck5hbWVcblJldHVybnMgbGlua3MgdG8gdGhlIGluZGl2aWR1YWwgQVBJIGVudHJ5IGZvciBlYWNoIEFQSS5cbiIsInBhcmFtZXRlcnMiOlt7IiRyZWYiOiIjL2NvbXBvbmVudHMvcGFyYW1ldGVycy9wcm92aWRlciJ9XSwicmVzcG9uc2VzIjp7IjIwMCI6eyJkZXNjcmlwdGlvbiI6Ik9LIiwiY29udGVudCI6eyJhcHBsaWNhdGlvbi9qc29uIjp7InNjaGVtYSI6eyIkcmVmIjoiIy9jb21wb25lbnRzL3NjaGVtYXMvQVBJcyJ9fX19fX19LCIve3Byb3ZpZGVyfS9zZXJ2aWNlcy5qc29uIjp7ImdldCI6eyJvcGVyYXRpb25JZCI6ImdldFNlcnZpY2VzIiwidGFncyI6WyJBUElzIl0sInN1bW1hcnkiOiJMaXN0IGFsbCBzZXJ2aWNlTmFtZXMgZm9yIGEgcGFydGljdWxhciBwcm92aWRlciIsImRlc2NyaXB0aW9uIjoiTGlzdCBhbGwgc2VydmljZU5hbWVzIGluIHRoZSBkaXJlY3RvcnkgZm9yIGEgcGFydGljdWxhciBwcm92aWRlck5hbWVcbiIsInBhcmFtZXRlcnMiOlt7IiRyZWYiOiIjL2NvbXBvbmVudHMvcGFyYW1ldGVycy9wcm92aWRlciJ9XSwicmVzcG9uc2VzIjp7IjIwMCI6eyJkZXNjcmlwdGlvbiI6Ik9LIiwiY29udGVudCI6eyJhcHBsaWNhdGlvbi9qc29uIjp7InNjaGVtYSI6eyJ0eXBlIjoib2JqZWN0IiwicHJvcGVydGllcyI6eyJkYXRhIjp7InR5cGUiOiJhcnJheSIsIml0ZW1zIjp7InR5cGUiOiJzdHJpbmciLCJtaW5MZW5ndGgiOjB9LCJtaW5JdGVtcyI6MX19fX19fX19fSwiL3NwZWNzL3twcm92aWRlcn0ve2FwaX0uanNvbiI6eyJnZXQiOnsib3BlcmF0aW9uSWQiOiJnZXRBUEkiLCJ0YWdzIjpbIkFQSXMiXSwic3VtbWFyeSI6IlJldHJpZXZlIG9uZSB2ZXJzaW9uIG9mIGEgcGFydGljdWxhciBBUEkiLCJkZXNjcmlwdGlvbiI6IlJldHVybnMgdGhlIEFQSSBlbnRyeSBmb3Igb25lIHNwZWNpZmljIHZlcnNpb24gb2YgYW4gQVBJIHdoZXJlIHRoZXJlIGlzIG5vIHNlcnZpY2VOYW1lLiIsInBhcmFtZXRlcnMiOlt7IiRyZWYiOiIjL2NvbXBvbmVudHMvcGFyYW1ldGVycy9wcm92aWRlciJ9LHsiJHJlZiI6IiMvY29tcG9uZW50cy9wYXJhbWV0ZXJzL2FwaSJ9XSwicmVzcG9uc2VzIjp7IjIwMCI6eyJkZXNjcmlwdGlvbiI6Ik9LIiwiY29udGVudCI6eyJhcHBsaWNhdGlvbi9qc29uIjp7InNjaGVtYSI6eyIkcmVmIjoiIy9jb21wb25lbnRzL3NjaGVtYXMvQVBJIn19fX19fX0sIi9zcGVjcy97cHJvdmlkZXJ9L3tzZXJ2aWNlfS97YXBpfS5qc29uIjp7ImdldCI6eyJvcGVyYXRpb25JZCI6ImdldFNlcnZpY2VBUEkiLCJ0YWdzIjpbIkFQSXMiXSwic3VtbWFyeSI6IlJldHJpZXZlIG9uZSB2ZXJzaW9uIG9mIGEgcGFydGljdWxhciBBUEkgd2l0aCBhIHNlcnZpY2VOYW1lLiIsImRlc2NyaXB0aW9uIjoiUmV0dXJucyB0aGUgQVBJIGVudHJ5IGZvciBvbmUgc3BlY2lmaWMgdmVyc2lvbiBvZiBhbiBBUEkgd2hlcmUgdGhlcmUgaXMgYSBzZXJ2aWNlTmFtZS4iLCJwYXJhbWV0ZXJzIjpbeyIkcmVmIjoiIy9jb21wb25lbnRzL3BhcmFtZXRlcnMvcHJvdmlkZXIifSx7Im5hbWUiOiJzZXJ2aWNlIiwiaW4iOiJwYXRoIiwicmVxdWlyZWQiOnRydWUsInNjaGVtYSI6eyJ0eXBlIjoic3RyaW5nIiwibWluTGVuZ3RoIjoxLCJtYXhMZW5ndGgiOjI1NSwiZXhhbXBsZSI6ImdyYXBoIn19LHsiJHJlZiI6IiMvY29tcG9uZW50cy9wYXJhbWV0ZXJzL2FwaSJ9XSwicmVzcG9uc2VzIjp7IjIwMCI6eyJkZXNjcmlwdGlvbiI6Ik9LIiwiY29udGVudCI6eyJhcHBsaWNhdGlvbi9qc29uIjp7InNjaGVtYSI6eyIkcmVmIjoiIy9jb21wb25lbnRzL3NjaGVtYXMvQVBJIn19fX19fX0sIi9saXN0Lmpzb24iOnsiZ2V0Ijp7Im9wZXJhdGlvbklkIjoibGlzdEFQSXMiLCJ0YWdzIjpbIkFQSXMiXSwic3VtbWFyeSI6Ikxpc3QgYWxsIEFQSXMiLCJkZXNjcmlwdGlvbiI6Ikxpc3QgYWxsIEFQSXMgaW4gdGhlIGRpcmVjdG9yeS5cblJldHVybnMgbGlua3MgdG8gdGhlIE9wZW5BUEkgZGVmaW5pdGlvbnMgZm9yIGVhY2ggQVBJIGluIHRoZSBkaXJlY3RvcnkuXG5JZiBBUEkgZXhpc3QgaW4gbXVsdGlwbGUgdmVyc2lvbnMgYHByZWZlcnJlZGAgb25lIGlzIGV4cGxpY2l0bHkgbWFya2VkLlxuU29tZSBiYXNpYyBpbmZvIGZyb20gdGhlIE9wZW5BUEkgZGVmaW5pdGlvbiBpcyBjYWNoZWQgaW5zaWRlIGVhY2ggb2JqZWN0LlxuVGhpcyBhbGxvd3MgeW91IHRvIGdlbmVyYXRlIHNvbWUgc2ltcGxlIHZpZXdzIHdpdGhvdXQgbmVlZGluZyB0byBmZXRjaCB0aGUgT3BlbkFQSSBkZWZpbml0aW9uIGZvciBlYWNoIEFQSS5cbiIsInJlc3BvbnNlcyI6eyIyMDAiOnsiZGVzY3JpcHRpb24iOiJPSyIsImNvbnRlbnQiOnsiYXBwbGljYXRpb24vanNvbiI6eyJzY2hlbWEiOnsiJHJlZiI6IiMvY29tcG9uZW50cy9zY2hlbWFzL0FQSXMifX19fX19fSwiL21ldHJpY3MuanNvbiI6eyJnZXQiOnsib3BlcmF0aW9uSWQiOiJnZXRNZXRyaWNzIiwic3VtbWFyeSI6IkdldCBiYXNpYyBtZXRyaWNzIiwiZGVzY3JpcHRpb24iOiJTb21lIGJhc2ljIG1ldHJpY3MgZm9yIHRoZSBlbnRpcmUgZGlyZWN0b3J5LlxuSnVzdCBzdHVubmluZyBudW1iZXJzIHRvIHB1dCBvbiBhIGZyb250IHBhZ2UgYW5kIGFyZSBpbnRlbmRlZCBwdXJlbHkgZm9yIFdvVyBlZmZlY3QgOilcbiIsInRhZ3MiOlsiQVBJcyJdLCJyZXNwb25zZXMiOnsiMjAwIjp7ImRlc2NyaXB0aW9uIjoiT0siLCJjb250ZW50Ijp7ImFwcGxpY2F0aW9uL2pzb24iOnsic2NoZW1hIjp7IiRyZWYiOiIjL2NvbXBvbmVudHMvc2NoZW1hcy9NZXRyaWNzIn19fX19fX19LCJjb21wb25lbnRzIjp7InNjaGVtYXMiOnsiQVBJcyI6eyJkZXNjcmlwdGlvbiI6Ikxpc3Qgb2YgQVBJIGRldGFpbHMuXG5JdCBpcyBhIEpTT04gb2JqZWN0IHdpdGggQVBJIElEcyhgPHByb3ZpZGVyPls6PHNlcnZpY2U+XWApIGFzIGtleXMuXG4iLCJ0eXBlIjoib2JqZWN0IiwiYWRkaXRpb25hbFByb3BlcnRpZXMiOnsiJHJlZiI6IiMvY29tcG9uZW50cy9zY2hlbWFzL0FQSSJ9LCJtaW5Qcm9wZXJ0aWVzIjoxLCJleGFtcGxlIjp7Imdvb2dsZWFwaXMuY29tOmRyaXZlIjp7ImFkZGVkIjoiMjAxNS0wMi0yMlQyMDowMDo0NS4wMDBaIiwicHJlZmVycmVkIjoidjMiLCJ2ZXJzaW9ucyI6eyJ2MiI6eyJhZGRlZCI6IjIwMTUtMDItMjJUMjA6MDA6NDUuMDAwWiIsImluZm8iOnsidGl0bGUiOiJEcml2ZSIsInZlcnNpb24iOiJ2MiIsIngtYXBpQ2xpZW50UmVnaXN0cmF0aW9uIjp7InVybCI6Imh0dHBzOi8vY29uc29sZS5kZXZlbG9wZXJzLmdvb2dsZS5jb20ifSwieC1sb2dvIjp7InVybCI6Imh0dHBzOi8vYXBpLmFwaXMuZ3VydS92Mi9jYWNoZS9sb2dvL2h0dHBzX3d3dy5nc3RhdGljLmNvbV9pbWFnZXNfaWNvbnNfbWF0ZXJpYWxfcHJvZHVjdF8yeF9kcml2ZV8zMmRwLnBuZyJ9LCJ4LW9yaWdpbiI6eyJmb3JtYXQiOiJnb29nbGUiLCJ1cmwiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kaXNjb3ZlcnkvdjEvYXBpcy9kcml2ZS92Mi9yZXN0IiwidmVyc2lvbiI6InYxIn0sIngtcHJlZmVycmVkIjpmYWxzZSwieC1wcm92aWRlck5hbWUiOiJnb29nbGVhcGlzLmNvbSIsIngtc2VydmljZU5hbWUiOiJkcml2ZSJ9LCJzd2FnZ2VyVXJsIjoiaHR0cHM6Ly9hcGkuYXBpcy5ndXJ1L3YyL3NwZWNzL2dvb2dsZWFwaXMuY29tL2RyaXZlL3YyL3N3YWdnZXIuanNvbiIsInN3YWdnZXJZYW1sVXJsIjoiaHR0cHM6Ly9hcGkuYXBpcy5ndXJ1L3YyL3NwZWNzL2dvb2dsZWFwaXMuY29tL2RyaXZlL3YyL3N3YWdnZXIueWFtbCIsInVwZGF0ZWQiOiIyMDE2LTA2LTE3VDAwOjIxOjQ0LjAwMFoifSwidjMiOnsiYWRkZWQiOiIyMDE1LTEyLTEyVDAwOjI1OjEzLjAwMFoiLCJpbmZvIjp7InRpdGxlIjoiRHJpdmUiLCJ2ZXJzaW9uIjoidjMiLCJ4LWFwaUNsaWVudFJlZ2lzdHJhdGlvbiI6eyJ1cmwiOiJodHRwczovL2NvbnNvbGUuZGV2ZWxvcGVycy5nb29nbGUuY29tIn0sIngtbG9nbyI6eyJ1cmwiOiJodHRwczovL2FwaS5hcGlzLmd1cnUvdjIvY2FjaGUvbG9nby9odHRwc193d3cuZ3N0YXRpYy5jb21faW1hZ2VzX2ljb25zX21hdGVyaWFsX3Byb2R1Y3RfMnhfZHJpdmVfMzJkcC5wbmcifSwieC1vcmlnaW4iOnsiZm9ybWF0IjoiZ29vZ2xlIiwidXJsIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZGlzY292ZXJ5L3YxL2FwaXMvZHJpdmUvdjMvcmVzdCIsInZlcnNpb24iOiJ2MSJ9LCJ4LXByZWZlcnJlZCI6dHJ1ZSwieC1wcm92aWRlck5hbWUiOiJnb29nbGVhcGlzLmNvbSIsIngtc2VydmljZU5hbWUiOiJkcml2ZSJ9LCJzd2FnZ2VyVXJsIjoiaHR0cHM6Ly9hcGkuYXBpcy5ndXJ1L3YyL3NwZWNzL2dvb2dsZWFwaXMuY29tL2RyaXZlL3YzL3N3YWdnZXIuanNvbiIsInN3YWdnZXJZYW1sVXJsIjoiaHR0cHM6Ly9hcGkuYXBpcy5ndXJ1L3YyL3NwZWNzL2dvb2dsZWFwaXMuY29tL2RyaXZlL3YzL3N3YWdnZXIueWFtbCIsInVwZGF0ZWQiOiIyMDE2LTA2LTE3VDAwOjIxOjQ0LjAwMFoifX19fX0sIkFQSSI6eyJkZXNjcmlwdGlvbiI6Ik1ldGEgaW5mb3JtYXRpb24gYWJvdXQgQVBJIiwidHlwZSI6Im9iamVjdCIsInJlcXVpcmVkIjpbImFkZGVkIiwicHJlZmVycmVkIiwidmVyc2lvbnMiXSwicHJvcGVydGllcyI6eyJhZGRlZCI6eyJkZXNjcmlwdGlvbiI6IlRpbWVzdGFtcCB3aGVuIHRoZSBBUEkgd2FzIGZpcnN0IGFkZGVkIHRvIHRoZSBkaXJlY3RvcnkiLCJ0eXBlIjoic3RyaW5nIiwiZm9ybWF0IjoiZGF0ZS10aW1lIn0sInByZWZlcnJlZCI6eyJkZXNjcmlwdGlvbiI6IlJlY29tbWVuZGVkIHZlcnNpb24iLCJ0eXBlIjoic3RyaW5nIn0sInZlcnNpb25zIjp7ImRlc2NyaXB0aW9uIjoiTGlzdCBvZiBzdXBwb3J0ZWQgdmVyc2lvbnMgb2YgdGhlIEFQSSIsInR5cGUiOiJvYmplY3QiLCJhZGRpdGlvbmFsUHJvcGVydGllcyI6eyIkcmVmIjoiIy9jb21wb25lbnRzL3NjaGVtYXMvQXBpVmVyc2lvbiJ9LCJtaW5Qcm9wZXJ0aWVzIjoxfX0sImFkZGl0aW9uYWxQcm9wZXJ0aWVzIjpmYWxzZX0sIkFwaVZlcnNpb24iOnsidHlwZSI6Im9iamVjdCIsInJlcXVpcmVkIjpbImFkZGVkIiwidXBkYXRlZCIsInN3YWdnZXJVcmwiLCJzd2FnZ2VyWWFtbFVybCIsImluZm8iLCJvcGVuYXBpVmVyIl0sInByb3BlcnRpZXMiOnsiYWRkZWQiOnsiZGVzY3JpcHRpb24iOiJUaW1lc3RhbXAgd2hlbiB0aGUgdmVyc2lvbiB3YXMgYWRkZWQiLCJ0eXBlIjoic3RyaW5nIiwiZm9ybWF0IjoiZGF0ZS10aW1lIn0sInVwZGF0ZWQiOnsiZGVzY3JpcHRpb24iOiJUaW1lc3RhbXAgd2hlbiB0aGUgdmVyc2lvbiB3YXMgdXBkYXRlZCIsInR5cGUiOiJzdHJpbmciLCJmb3JtYXQiOiJkYXRlLXRpbWUifSwic3dhZ2dlclVybCI6eyJkZXNjcmlwdGlvbiI6IlVSTCB0byBPcGVuQVBJIGRlZmluaXRpb24gaW4gSlNPTiBmb3JtYXQiLCJ0eXBlIjoic3RyaW5nIiwiZm9ybWF0IjoidXJsIn0sInN3YWdnZXJZYW1sVXJsIjp7ImRlc2NyaXB0aW9uIjoiVVJMIHRvIE9wZW5BUEkgZGVmaW5pdGlvbiBpbiBZQU1MIGZvcm1hdCIsInR5cGUiOiJzdHJpbmciLCJmb3JtYXQiOiJ1cmwifSwibGluayI6eyJkZXNjcmlwdGlvbiI6IkxpbmsgdG8gdGhlIGluZGl2aWR1YWwgQVBJIGVudHJ5IGZvciB0aGlzIEFQSSIsInR5cGUiOiJzdHJpbmciLCJmb3JtYXQiOiJ1cmwifSwiaW5mbyI6eyJkZXNjcmlwdGlvbiI6IkNvcHkgb2YgYGluZm9gIHNlY3Rpb24gZnJvbSBPcGVuQVBJIGRlZmluaXRpb24iLCJ0eXBlIjoib2JqZWN0IiwibWluUHJvcGVydGllcyI6MX0sImV4dGVybmFsRG9jcyI6eyJkZXNjcmlwdGlvbiI6IkNvcHkgb2YgYGV4dGVybmFsRG9jc2Agc2VjdGlvbiBmcm9tIE9wZW5BUEkgZGVmaW5pdGlvbiIsInR5cGUiOiJvYmplY3QiLCJtaW5Qcm9wZXJ0aWVzIjoxfSwib3BlbmFwaVZlciI6eyJkZXNjcmlwdGlvbiI6IlRoZSB2YWx1ZSBvZiB0aGUgYG9wZW5hcGlgIG9yIGBzd2FnZ2VyYCBwcm9wZXJ0eSBvZiB0aGUgc291cmNlIGRlZmluaXRpb24iLCJ0eXBlIjoic3RyaW5nIn19LCJhZGRpdGlvbmFsUHJvcGVydGllcyI6ZmFsc2V9LCJNZXRyaWNzIjp7ImRlc2NyaXB0aW9uIjoiTGlzdCBvZiBiYXNpYyBtZXRyaWNzIiwidHlwZSI6Im9iamVjdCIsInJlcXVpcmVkIjpbIm51bVNwZWNzIiwibnVtQVBJcyIsIm51bUVuZHBvaW50cyJdLCJwcm9wZXJ0aWVzIjp7Im51bVNwZWNzIjp7ImRlc2NyaXB0aW9uIjoiTnVtYmVyIG9mIEFQSSBkZWZpbml0aW9ucyBpbmNsdWRpbmcgZGlmZmVyZW50IHZlcnNpb25zIG9mIHRoZSBzYW1lIEFQSSIsInR5cGUiOiJpbnRlZ2VyIiwibWluaW11bSI6MX0sIm51bUFQSXMiOnsiZGVzY3JpcHRpb24iOiJOdW1iZXIgb2YgdW5pcXVlIEFQSXMiLCJ0eXBlIjoiaW50ZWdlciIsIm1pbmltdW0iOjF9LCJudW1FbmRwb2ludHMiOnsiZGVzY3JpcHRpb24iOiJUb3RhbCBudW1iZXIgb2YgZW5kcG9pbnRzIGluc2lkZSBhbGwgZGVmaW5pdGlvbnMiLCJ0eXBlIjoiaW50ZWdlciIsIm1pbmltdW0iOjF9LCJ1bnJlYWNoYWJsZSI6eyJkZXNjcmlwdGlvbiI6Ik51bWJlciBvZiB1bnJlYWNoYWJsZSAoNFhYLDVYWCBzdGF0dXMpIEFQSXMiLCJ0eXBlIjoiaW50ZWdlciJ9LCJpbnZhbGlkIjp7ImRlc2NyaXB0aW9uIjoiTnVtYmVyIG9mIG5ld2x5IGludmFsaWQgQVBJcyIsInR5cGUiOiJpbnRlZ2VyIn0sInVub2ZmaWNpYWwiOnsiZGVzY3JpcHRpb24iOiJOdW1iZXIgb2YgdW5vZmZpY2lhbCBBUElzIiwidHlwZSI6ImludGVnZXIifSwiZml4ZXMiOnsiZGVzY3JpcHRpb24iOiJUb3RhbCBudW1iZXIgb2YgZml4ZXMgYXBwbGllZCBhY3Jvc3MgYWxsIEFQSXMiLCJ0eXBlIjoiaW50ZWdlciJ9LCJmaXhlZFBjdCI6eyJkZXNjcmlwdGlvbiI6IlBlcmNlbnRhZ2Ugb2YgYWxsIEFQSXMgd2hlcmUgYXV0byBmaXhlcyBoYXZlIGJlZW4gYXBwbGllZCIsInR5cGUiOiJpbnRlZ2VyIn0sImRhdGFzZXRzIjp7ImRlc2NyaXB0aW9uIjoiRGF0YSB1c2VkIGZvciBjaGFydGluZyBldGMiLCJ0eXBlIjoiYXJyYXkiLCJpdGVtcyI6e319LCJzdGFycyI6eyJkZXNjcmlwdGlvbiI6IkdpdEh1YiBzdGFycyBmb3Igb3VyIG1haW4gcmVwbyIsInR5cGUiOiJpbnRlZ2VyIn0sImlzc3VlcyI6eyJkZXNjcmlwdGlvbiI6Ik9wZW4gR2l0SHViIGlzc3VlcyBvbiBvdXIgbWFpbiByZXBvIiwidHlwZSI6ImludGVnZXIifSwidGhpc1dlZWsiOnsiZGVzY3JpcHRpb24iOiJTdW1tYXJ5IHRvdGFscyBmb3IgdGhlIGxhc3QgNyBkYXlzIiwidHlwZSI6Im9iamVjdCIsInByb3BlcnRpZXMiOnsiYWRkZWQiOnsiZGVzY3JpcHRpb24iOiJBUElzIGFkZGVkIGluIHRoZSBsYXN0IHdlZWsiLCJ0eXBlIjoiaW50ZWdlciJ9LCJ1cGRhdGVkIjp7ImRlc2NyaXB0aW9uIjoiQVBJcyB1cGRhdGVkIGluIHRoZSBsYXN0IHdlZWsiLCJ0eXBlIjoiaW50ZWdlciJ9fX0sIm51bURyaXZlcnMiOnsiZGVzY3JpcHRpb24iOiJOdW1iZXIgb2YgbWV0aG9kcyBvZiBBUEkgcmV0cmlldmFsIiwidHlwZSI6ImludGVnZXIifSwibnVtUHJvdmlkZXJzIjp7ImRlc2NyaXB0aW9uIjoiTnVtYmVyIG9mIEFQSSBwcm92aWRlcnMgaW4gZGlyZWN0b3J5IiwidHlwZSI6ImludGVnZXIifX0sImFkZGl0aW9uYWxQcm9wZXJ0aWVzIjpmYWxzZSwiZXhhbXBsZSI6eyJudW1BUElzIjoyNTAxLCJudW1FbmRwb2ludHMiOjEwNjQ0OCwibnVtU3BlY3MiOjMzMjksInVucmVhY2hhYmxlIjoxMjMsImludmFsaWQiOjU5OCwidW5vZmZpY2lhbCI6MjUsImZpeGVzIjo4MTExOSwiZml4ZWRQY3QiOjIyLCJkYXRhc2V0cyI6W10sInN0YXJzIjoyNDI5LCJpc3N1ZXMiOjI4LCJ0aGlzV2VlayI6eyJhZGRlZCI6NDUsInVwZGF0ZWQiOjE3MX0sIm51bURyaXZlcnMiOjEwLCJudW1Qcm92aWRlcnMiOjY1OX19fSwicGFyYW1ldGVycyI6eyJwcm92aWRlciI6eyJuYW1lIjoicHJvdmlkZXIiLCJpbiI6InBhdGgiLCJyZXF1aXJlZCI6dHJ1ZSwic2NoZW1hIjp7InR5cGUiOiJzdHJpbmciLCJtaW5MZW5ndGgiOjEsIm1heExlbmd0aCI6MjU1LCJleGFtcGxlIjoiYXBpcy5ndXJ1In19LCJhcGkiOnsibmFtZSI6ImFwaSIsImluIjoicGF0aCIsInJlcXVpcmVkIjp0cnVlLCJzY2hlbWEiOnsidHlwZSI6InN0cmluZyIsIm1pbkxlbmd0aCI6MSwibWF4TGVuZ3RoIjoyNTUsImV4YW1wbGUiOiIyLjEuMCJ9fX19fQo=\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://api.apis.guru/v2/\"\n },\n \"developer_portal\": {\n \"enabled\": false,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/apiguru-devportal.html\"\n }\n },\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"JWT Authentication\"\n }\n ],\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/providers.json\"\n ]\n },\n \"authorization\": [\n {\n \"profile\": \"JWT role based authorization\",\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/providers.json\"\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"profile\": \"apigw_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 0,\n \"delay\": 0,\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/metrics.json\"\n ]\n }\n ]\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\n }\n }\n }\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"apigw_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"2r/s\"\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"JWT Authentication\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"API 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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\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": "APIGuru API Gateway RateLimit + JWT AuthN/AuthZ + redocly + moesif", + "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": {}, + "requests": {} + } + } ], - "port": "{{ncg_port}}", - "path": [ - "{{ngc_api_version}}", - "config", - "{{configUid}}" - ] - } - }, - "response": [] - }, - { - "name": "6. Test application - echo test", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "http://echo.vm-blank.ie.ff.lan", - "protocol": "http", - "host": [ - "echo", - "vm-blank", - "ie", - "ff", - "lan" - ] + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": []\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"APIGuru\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/apiguru\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://intranet.ie.ff.lan/apiguru.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://api.apis.guru/v2/\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/apiguru-devportal.html\"\n }\n },\n \"visibility\": [\n {\n \"enabled\": true,\n \"type\": \"moesif\",\n \"moesif\": {\n \"application_id\": \"{{moesif_application_id}}\"\n }\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"JWT Authentication\"\n }\n ],\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/providers.json\"\n ]\n },\n \"authorization\": [\n {\n \"profile\": \"JWT role based authorization\",\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/providers.json\"\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"profile\": \"apigw_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 0,\n \"delay\": 0,\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/metrics.json\"\n ]\n }\n ]\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\n }\n }\n }\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"name\": \"apigw_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"2r/s\"\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"JWT Authentication\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"API 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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\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": "7. Test application - random joke", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "http://randomjoke.vm-blank.ie.ff.lan/random_joke", - "protocol": "http", - "host": [ - "randomjoke", - "vm-blank", - "ie", - "ff", - "lan" - ], - "path": [ - "random_joke" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "API Gateway", - "item": [ { "name": "Petstore API", "item": [ @@ -9148,7 +9716,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": []\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", + "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": []\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -9194,7 +9762,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": []\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"syslog:server=192.168.2.13:514\"\n },\n \"error\": {\n \"destination\": \"syslog:server=192.168.2.13: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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", + "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": []\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"syslog:server=192.168.2.13:514\"\n },\n \"error\": {\n \"destination\": \"syslog:server=192.168.2.13: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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -9240,7 +9808,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ndk_http_module\",\n \"ngx_http_app_protect_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": false,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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 }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", + "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ndk_http_module\",\n \"ngx_http_app_protect_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": false,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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 }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\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}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -9286,7 +9854,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": []\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", + "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": []\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -9332,7 +9900,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ndk_http_module\",\n \"ngx_http_lua_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\n },\n \"visibility\": [\n {\n \"enabled\": true,\n \"type\": \"moesif\",\n \"moesif\": {\n \"application_id\": \"{{moesif_application_id}}\"\n }\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", + "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ndk_http_module\",\n \"ngx_http_lua_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\n },\n \"visibility\": [\n {\n \"enabled\": true,\n \"type\": \"moesif\",\n \"moesif\": {\n \"application_id\": \"{{moesif_application_id}}\"\n }\n }\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\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -9378,7 +9946,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ndk_http_module\",\n \"ngx_http_lua_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"cache\": {\n \"profile\": \"10m cache\",\n \"key\": \"$uri\",\n \"validity\": [\n {\n \"code\": \"200\",\n \"ttl\": \"5s\"\n }\n ]\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": false,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\n },\n \"visibility\": [\n {\n \"enabled\": true,\n \"type\": \"moesif\",\n \"moesif\": {\n \"application_id\": \"{{moesif_application_id}}\"\n }\n }\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 \"cache\": [\n {\n \"profile\": \"10m cache\",\n \"key\": \"$http_method$uri\",\n \"validity\": [\n {\n \"code\": \"any\",\n \"ttl\": \"30s\"\n },\n {\n \"code\": \"302\",\n \"ttl\": \"5m\"\n }\n ],\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/store/inventory\"\n ]\n }\n ]\n },\n \"cache\": {\n \"profile\": \"10m cache\",\n \"key\": \"$http_method$uri\",\n \"validity\": [\n {\n \"code\": \"any\",\n \"ttl\": \"30s\"\n },\n {\n \"code\": \"302\",\n \"ttl\": \"5m\"\n }\n ]\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"cache\": [\n {\n \"name\": \"10m cache\",\n \"basepath\": \"/tmp\",\n \"size\": \"10m\",\n \"ttl\": \"10m\"\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", + "raw": "{\n \"output\": {\n \"type\": \"nms\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ndk_http_module\",\n \"ngx_http_lua_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Petstore API\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"cache\": {\n \"profile\": \"10m cache\",\n \"key\": \"$uri\",\n \"validity\": [\n {\n \"code\": \"200\",\n \"ttl\": \"5s\"\n }\n ]\n },\n \"locations\": [\n {\n \"uri\": \"/petstore\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://petstore3.swagger.io/api/v3/openapi.json\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://petstore3.swagger.io\"\n },\n \"developer_portal\": {\n \"enabled\": false,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/petstore-devportal.html\"\n }\n },\n \"visibility\": [\n {\n \"enabled\": true,\n \"type\": \"moesif\",\n \"moesif\": {\n \"application_id\": \"{{moesif_application_id}}\"\n }\n }\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 \"cache\": [\n {\n \"profile\": \"10m cache\",\n \"key\": \"$http_method$uri\",\n \"validity\": [\n {\n \"code\": \"any\",\n \"ttl\": \"30s\"\n },\n {\n \"code\": \"302\",\n \"ttl\": \"5m\"\n }\n ],\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/store/inventory\"\n ]\n }\n ]\n },\n \"cache\": {\n \"profile\": \"10m cache\",\n \"key\": \"$http_method$uri\",\n \"validity\": [\n {\n \"code\": \"any\",\n \"ttl\": \"30s\"\n },\n {\n \"code\": \"302\",\n \"ttl\": \"5m\"\n }\n ]\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"cache\": [\n {\n \"name\": \"10m cache\",\n \"basepath\": \"/tmp\",\n \"size\": \"10m\",\n \"ttl\": \"10m\"\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -9803,7 +10371,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n }\n}", + "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -10307,7 +10875,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n }\n}", + "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -10596,7 +11164,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"vm-blank.ff.lan\"\n ],\n \"resolver\": \"private DNS\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"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 \"resolvers\": [\n {\n \"name\": \"private DNS\",\n \"address\": \"192.168.2.13\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", + "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"vm-blank.ff.lan\"\n ],\n \"resolver\": \"private DNS\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"resolvers\": [\n {\n \"name\": \"private DNS\",\n \"address\": \"192.168.2.13\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\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}", "options": { "raw": { "language": "json" @@ -10792,7 +11360,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.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}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n }\n}", + "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.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}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -10838,7 +11406,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.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}}/{{ngc_api_version}}/testcert.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}", + "raw": "{\n \"output\": {\n \"type\": \"nginxone\",\n \"nginxone\": {\n \"url\": \"{{nginxone_url}}\",\n \"namespace\": \"{{nginxone_namespace}}\",\n \"token\": \"{{nginxone_token}}\",\n \"configsyncgroup\": \"{{nginxone_configsyncgroup}}\",\n \"synctime\": 0,\n \"modules\": [\n \"ngx_http_js_module\",\n \"ngx_stream_js_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.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}}/{{ngc_api_version}}/testcert.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}", "options": { "raw": { "language": "json" diff --git a/src/V5_6_CreateConfig.py b/src/V5_6_CreateConfig.py index 3f08250d..768588ed 100644 --- a/src/V5_6_CreateConfig.py +++ b/src/V5_6_CreateConfig.py @@ -843,7 +843,7 @@ def patch_config(declaration: ConfigDeclaration, configUid: str, apiversion: str sourceDeclaration=currentDeclaration, patchedNAPPolicies=p) # Handle certificate updates - d_certificates = v5_6.MiscUtils.getDictKey(declarationToPatch, 'declaration.http.certificates') + d_certificates = v5_6.MiscUtils.getDictKey(declarationToPatch, 'declaration.certificates') if d_certificates is not None: # TLS certificate/key updates for p in d_certificates: diff --git a/src/V5_6_NginxConfigDeclaration.py b/src/V5_6_NginxConfigDeclaration.py index d3436f08..ee6b64d3 100644 --- a/src/V5_6_NginxConfigDeclaration.py +++ b/src/V5_6_NginxConfigDeclaration.py @@ -943,7 +943,6 @@ class Http(BaseModel, extra="forbid"): logformats: Optional[List[HttpLogFormat]] = [] resolver: Optional[str] = "" acme_issuers: Optional[List[AcmeIssuers]] = [] - certificates: Optional[List[TLSCertificate]] = [] policies: Optional[List[NGINXPolicy]] = [] log_profiles: Optional[List[LogProfile]] = [] @@ -952,6 +951,7 @@ class Declaration(BaseModel, extra="forbid"): layer4: Optional[Layer4] = {} http: Optional[Http] = {} resolvers: Optional[List[Resolver]] = [] + certificates: Optional[List[TLSCertificate]] = [] class API_Gateway(BaseModel, extra="forbid"): diff --git a/src/v5_6/NGINXOneOutput.py b/src/v5_6/NGINXOneOutput.py index f4f288d1..eb7dbaa6 100644 --- a/src/v5_6/NGINXOneOutput.py +++ b/src/v5_6/NGINXOneOutput.py @@ -87,7 +87,7 @@ def NGINXOneOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpCo # Check TLS items validity all_tls = {'certificate': {}, 'key': {}} - d_certs = v5_6.MiscUtils.getDictKey(d, 'declaration.http.certificates') + d_certs = v5_6.MiscUtils.getDictKey(d, 'declaration.certificates') if d_certs is not None: for i in range(len(d_certs)): if d_certs[i]['name']: @@ -146,10 +146,10 @@ def NGINXOneOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpCo issuer['name']) +"] must be one of [" + ",".join(all_tls['certificate']) + "]"} }} - # Add optional certificates specified under declaration.http.certificates + # Add optional certificates specified under declaration.certificates extensions_map = {'certificate': '.crt', 'key': '.key'} - d_certificates = v5_6.MiscUtils.getDictKey(d, 'declaration.http.certificates') + d_certificates = v5_6.MiscUtils.getDictKey(d, 'declaration.certificates') if d_certificates is not None: for c in d_certificates: status, certContent = v5_6.GitOps.getObjectFromRepo(object=c['contents'], @@ -163,7 +163,7 @@ def NGINXOneOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpCo '/' + c['name'] + extensions_map[c['type']]} auxFiles['files'].append(newAuxFile) - ### / Add optional certificates specified under declaration.http.certificates + ### / Add optional certificates specified under declaration.certificates # NGINX main configuration file through template j2_env = Environment(loader=FileSystemLoader(NcgConfig.config['templates']['root_dir'] + '/' + apiversion), diff --git a/src/v5_6/NIMOutput.py b/src/v5_6/NIMOutput.py index fb68ffe5..add649f5 100644 --- a/src/v5_6/NIMOutput.py +++ b/src/v5_6/NIMOutput.py @@ -86,7 +86,7 @@ def NIMOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpConf: s # Check TLS items validity all_tls = {'certificate': {}, 'key': {}} - d_certs = v5_6.MiscUtils.getDictKey(d, 'declaration.http.certificates') + d_certs = v5_6.MiscUtils.getDictKey(d, 'declaration.certificates') if d_certs is not None: for i in range(len(d_certs)): if d_certs[i]['name']: @@ -145,10 +145,10 @@ def NIMOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpConf: s issuer['name']) +"] must be one of [" + ",".join(all_tls['certificate']) + "]"} }} - # Add optional certificates specified under declaration.http.certificates + # Add optional certificates specified under declaration.certificates extensions_map = {'certificate': '.crt', 'key': '.key'} - d_certificates = v5_6.MiscUtils.getDictKey(d, 'declaration.http.certificates') + d_certificates = v5_6.MiscUtils.getDictKey(d, 'declaration.certificates') if d_certificates is not None: for c in d_certificates: status, certContent = v5_6.GitOps.getObjectFromRepo(object=c['contents'], @@ -162,7 +162,7 @@ def NIMOutput(d, declaration: ConfigDeclaration, apiversion: str, b64HttpConf: s '/' + c['name'] + extensions_map[c['type']]} auxFiles['files'].append(newAuxFile) - ### / Add optional certificates specified under declaration.http.certificates + ### / Add optional certificates specified under declaration.certificates # NGINX main configuration file through template j2_env = Environment(loader=FileSystemLoader(NcgConfig.config['templates']['root_dir'] + '/' + apiversion), From 50ece09f947b45ec07b61d3898447d9aca558b14 Mon Sep 17 00:00:00 2001 From: Fabrizio Fiorucci Date: Thu, 7 May 2026 10:34:05 +0100 Subject: [PATCH 08/12] Added WAF example policy --- contrib/gitops-examples/v5.6/waf-policy-owasp-top10.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 contrib/gitops-examples/v5.6/waf-policy-owasp-top10.json diff --git a/contrib/gitops-examples/v5.6/waf-policy-owasp-top10.json b/contrib/gitops-examples/v5.6/waf-policy-owasp-top10.json new file mode 100644 index 00000000..0a76646b --- /dev/null +++ b/contrib/gitops-examples/v5.6/waf-policy-owasp-top10.json @@ -0,0 +1,8 @@ +{ + "policy": { + "name": "nms_app_protect_default_policy", + "template": { + "name": "POLICY_TEMPLATE_NGINX_BASE" + } + } +} \ No newline at end of file From 11c14e5904e36167a50e8cfed85f561e834a1d34 Mon Sep 17 00:00:00 2001 From: Fabrizio Fiorucci Date: Thu, 7 May 2026 14:07:29 +0100 Subject: [PATCH 09/12] Added WAF example policy --- contrib/gitops-examples/v5.6/waf-policy-owasp-top10.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/gitops-examples/v5.6/waf-policy-owasp-top10.json b/contrib/gitops-examples/v5.6/waf-policy-owasp-top10.json index 0a76646b..e5d89676 100644 --- a/contrib/gitops-examples/v5.6/waf-policy-owasp-top10.json +++ b/contrib/gitops-examples/v5.6/waf-policy-owasp-top10.json @@ -1,6 +1,6 @@ { "policy": { - "name": "nms_app_protect_default_policy", + "name": "nginx_waf_owasp_top10_policy", "template": { "name": "POLICY_TEMPLATE_NGINX_BASE" } From 86e8c8c115169e9cdec738c9f237f612278564c9 Mon Sep 17 00:00:00 2001 From: Fabrizio Fiorucci Date: Thu, 7 May 2026 14:17:10 +0100 Subject: [PATCH 10/12] v5.6 updates --- FEATURES.md | 28 +- README.md | 11 +- ...NX Declarative API.postman_collection.json | 406 ++++++++++-------- contrib/postman/README.md | 4 +- 4 files changed, 243 insertions(+), 206 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index 087256a2..948a0b70 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -4,14 +4,14 @@ NGINX Declarative API has been tested with the following NGINX control plane releases: -| Control plane | API v5.4 | API v5.5 | Notes | +| Control plane | API v5.5 | API v5.6 | Notes | |---------------------------|----------------------|----------------------|--------| | NGINX Instance Manager | 2.18+ | 2.20+ | | | NGINX One Console | General availability | General availability | | ### NGINX `http` and `stream` servers -| Feature | API v5.4 | API v5.5 | Notes | +| Feature | API v5.5 | API v5.6 | Notes | |-----------------------------|----------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Upstreams | X | X |
  • Snippets supported: static and from source of truth
  • | | HTTP servers | X | X |
  • Snippets supported (`http`, `servers`, `locations`): static and from source of truth
  • | @@ -43,7 +43,7 @@ Locations `.declaration.http.servers[].locations[].uri` match modifiers in `.dec ### NGINX API Gateway use case -| Feature | API v5.4 | API v5.5 | Notes | +| Feature | API v5.5 | API v5.6 | Notes | |--------------------------------------------------------------|-------------------------------------------------------------------------------|-------------------------------------------------------------------------------|-----------------------------------------------| | Configuration generation from OpenAPI schema | X | X | OpenAPI 2.0, 3.0, 3.0.1, YAML and JSON format | | HTTP methods enforcement | X | X | | @@ -92,21 +92,21 @@ See the [Postman collection](/contrib/) for usage examples ### NGINX API Gateway use case - Developer Portal -| Type | API v5.4 | API v5.5 | Notes | +| Type | API v5.5 | API v5.6 | Notes | |-----------------|----------|----------|------------------------------------------| | Redocly | X | X | Developer portal published by NGINX Plus | | Backstage.io | X | X | Backstage YAML manifest generated | ### NGINX API Gateway use case - Visibility -| Type | API v5.4 | API v5.5 | Notes | +| Type | API v5.5 | API v5.6 | Notes | |---------------|----------|----------|-----------------------------------------------------------------------------------------------| | Moesif | X | X | Integration with Moesif - see https://www.moesif.com/docs/server-integration/nginx-openresty/ | ### TLS -| Type | Description | API v5.4 | API v5.5 | Notes | +| Type | Description | API v5.5 | API v5.6 | Notes | |-------|-------------------------|----------|----------|-------| | ACME | ACME Protocol support | X | X | | @@ -130,7 +130,7 @@ For full details for all fields see https://nginx.org/en/docs/http/ngx_http_acme ### Client authentication -| Type | Description | API v5.4 | API v5.5 | Notes | +| Type | Description | API v5.5 | API v5.6 | Notes | |------|----------------------|----------|----------|-------------------------------------| | jwt | JSON Web Token (JWT) | X | X | | | mtls | Mutual TLS | X | X |
  • Supported for HTTP servers
  • | @@ -208,7 +208,7 @@ For additional details see https://nginx.org/en/docs/http/ngx_http_oidc_module.h ### Client authorization -| Type | Description | API v5.4 | API v5.5 | Notes | +| Type | Description | API v5.5 | API v5.6 | Notes | |------|------------------------|----------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | jwt | JSON Web Token (JWT) | X | X | Based on JWT claims. Supported under
  • .declaration.http.servers[]
  • .declaration.http.servers[].location[]
  • .declaration.http.servers[].location[].apigateway
  • | @@ -238,7 +238,7 @@ Client-side authorization profiles to be defined under `.declaration.http.author ### Upstream and Source of truth authentication -| Type | Description | API v5.4 | API v5.5 | Notes | +| Type | Description | API v5.5 | API v5.6 | 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 | X | `Basic` Authorization header is injected in requests to upstreams and source of truth | @@ -306,7 +306,7 @@ Server-side authentication profiles to be defined under `.declaration.http.authe ### HTTP Headers manipulation -| Type | API v5.4 | API v5.5 | Notes | +| Type | API v5.5 | API v5.6 | 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
  • | @@ -355,7 +355,7 @@ To be defined under `.declaration.http.servers[].headers` and/or `.declaration.h ### NGINX Javascript -| Hook type | API v5.4 | API v5.5 | Notes | +| Hook type | API v5.5 | API v5.6 | Notes | |---------------------|----------|----------|--------------------------------------------------------------------------------------------------------------------------------| | js_body_filter | X | X | Available in
  • `declaration.http.servers[].location[]`
  • | | js_content | X | X | Available in
  • `declaration.http.servers[].location[]`
  • | @@ -509,7 +509,7 @@ Example hooks: ### DNS resolvers -| | API v5.4 | API v5.5 | Notes | +| | API v5.5 | API v5.6 | Notes | |-------------------------|----------|----------|------------------------------------------------------------------------------------------------------------------------------------| | DNS resolver profiles | X | X | Available in
  • `declaration.http.servers[]`
  • `declaration.http.upstreams[]`
  • `declaration.layer4.upstreams[]`
  • | @@ -532,13 +532,13 @@ DNS resolver profiles to be defined under `.declaration.http.resolvers[]` #### HTTP Access and error logging -| | API v5.4 | API v5.5 | Notes | +| | API v5.5 | API v5.6 | Notes | |---------|----------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Logging | X | X | Available in
  • `.declaration.http.servers[].log`
  • `.declaration.http.servers[].locations[].log`

  • `condition` enables conditional logging. Logging will be disabled if `condition` evaluates to "0" or an empty string | ### Access logging formats -| | API v5.4 | API v5.5 | Notes | +| | API v5.5 | API v5.6 | Notes | |-----------------|----------|----------|-------| | Logging formats | X | X | | diff --git a/README.md b/README.md index 436ccfbe..676da378 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ A **blog article** to automate NGINX API Gateway management from OpenAPI schemas ## 🚀 Supported releases -- [F5 NGINX Instance Manager 2.14+](https://docs.nginx.com/nginx-instance-manager/) +- [F5 NGINX Instance Manager 2.20+](https://docs.nginx.com/nginx-instance-manager/) - [F5 NGINX One Console](https://docs.nginx.com/nginx-one/) - [F5 NGINX Plus R33+](https://docs.nginx.com/nginx/) - [F5 WAF for NGINX](https://docs.nginx.com/waf/) @@ -198,15 +198,6 @@ NGINX Declarative API ->> CI/CD Pipeline: Response end ``` -## 🧩 Input formats - -- [X] Declarative JSON - -## 🧾 Output formats - -- [X] Output to F5 NGINX Instance Manager 2.14+ imperative REST API (instance group) -- [X] Output to F5 NGINX One Console REST API (config sync group) - ## 🌟 Supported features See the [features list](/FEATURES.md) diff --git a/contrib/postman/NGINX Declarative API.postman_collection.json b/contrib/postman/NGINX Declarative API.postman_collection.json index 92420df3..70a3655f 100644 --- a/contrib/postman/NGINX Declarative API.postman_collection.json +++ b/contrib/postman/NGINX Declarative API.postman_collection.json @@ -5698,6 +5698,52 @@ }, "response": [] }, + { + "name": "APIGuru API Gateway RateLimit + JWT AuthN/AuthZ + redocly + WAF - YAML OpenAPI schema", + "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": {}, + "requests": {} + } + } + ], + "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 },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": true\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"APIGuru\",\n \"names\": [\n \"apigw.nginx.lab\"\n ],\n \"resolver\": \"Google\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/apiguru\",\n \"urimatch\": \"prefix\",\n \"apigateway\": {\n \"openapi_schema\": {\n \"content\": \"https://api.apis.guru/v2/openapi.yaml\"\n },\n \"api_gateway\": {\n \"enabled\": true,\n \"strip_uri\": true,\n \"server_url\": \"https://api.apis.guru/v2/\"\n },\n \"developer_portal\": {\n \"enabled\": true,\n \"type\": \"redocly\",\n \"redocly\": {\n \"uri\": \"/apiguru-devportal.html\"\n }\n },\n \"authentication\": {\n \"client\": [\n {\n \"profile\": \"JWT Authentication\"\n }\n ],\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/providers.json\"\n ]\n },\n \"authorization\": [\n {\n \"profile\": \"JWT role based authorization\",\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/providers.json\"\n ]\n }\n ],\n \"rate_limit\": [\n {\n \"profile\": \"apigw_ratelimit\",\n \"httpcode\": 429,\n \"burst\": 0,\n \"delay\": 0,\n \"enforceOnPaths\": true,\n \"paths\": [\n \"/metrics.json\"\n ]\n }\n ]\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/apigw-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/apigw-error.log\"\n }\n },\n \"app_protect\": {\n \"enabled\": true,\n \"policy\": \"owasp-top10\",\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\": \"apigw_ratelimit\",\n \"key\": \"$binary_remote_addr\",\n \"size\": \"10m\",\n \"rate\": \"2r/s\"\n }\n ],\n \"authentication\": {\n \"client\": [\n {\n \"name\": \"JWT Authentication\",\n \"type\": \"jwt\",\n \"jwt\": {\n \"realm\": \"API 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 \"policies\": [\n {\n \"type\": \"app_protect\",\n \"name\": \"owasp-top10\",\n \"active_tag\": \"default\",\n \"versions\": [\n {\n \"tag\": \"default\",\n \"displayName\": \"Production Policy - OWASP top 10 protection\",\n \"description\": \"This is a production-ready policy - OWASP top 10 protection\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/waf-policy-owasp-top10.json\"\n }\n }\n ]\n }\n ],\n \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ],\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\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": "APIGuru API Gateway RateLimit + JWT AuthN/AuthZ + redocly - local OpenAPI schema", "event": [ @@ -7188,10 +7234,10 @@ ] }, { - "name": "GitOps autosync", + "name": "F5 WAF for NGINX", "item": [ { - "name": "NGINX Plus and GitOps", + "name": "Create initial NGINX configuration with F5 WAF for NGINX", "event": [ { "listen": "test", @@ -7214,7 +7260,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\": 5\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\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 },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\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}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -7237,7 +7283,7 @@ "response": [] }, { - "name": "F5 WAF for NGINX and GitOps", + "name": "Change active F5 WAF for NGINX policy", "event": [ { "listen": "test", @@ -7256,11 +7302,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\": 5,\n \"modules\": [\n \"ngx_http_app_protect_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\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}}/{{ngc_api_version}}/nap-policy-gitops.json\"\n }\n }\n ]\n }\n ]\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\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 },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\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}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n }\n }\n}", "options": { "raw": { "language": "json" @@ -7268,7 +7314,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}}" @@ -7276,34 +7322,38 @@ "port": "{{ncg_port}}", "path": [ "{{ngc_api_version}}", - "config" + "config", + "{{configUid}}" ] } }, "response": [] }, { - "name": "Get declaration status", + "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": {}, + "requests": {} } } ], - "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 },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert2.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert2.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -7311,7 +7361,7 @@ } }, "url": { - "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}/status", + "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}", "protocol": "http", "host": [ "{{ncg_host}}" @@ -7320,35 +7370,36 @@ "path": [ "{{ngc_api_version}}", "config", - "{{configUid}}", - "status" + "{{configUid}}" ] } }, "response": [] }, { - "name": "Get declaration", + "name": "Disable F5 WAF for NGINX", "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 },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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" @@ -7370,26 +7421,37 @@ } }, "response": [] - }, + } + ] + }, + { + "name": "GitOps autosync", + "item": [ { - "name": "Delete declaration", + "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" + "type": "text/javascript", + "packages": {}, + "requests": {} } } ], "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\": 5\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -7397,7 +7459,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}}" @@ -7405,20 +7467,14 @@ "port": "{{ncg_port}}", "path": [ "{{ngc_api_version}}", - "config", - "{{configUid}}" + "config" ] } }, "response": [] - } - ] - }, - { - "name": "Housekeeping - common endpoints", - "item": [ + }, { - "name": "Clean NGINX configuration", + "name": "F5 WAF for NGINX and GitOps", "event": [ { "listen": "test", @@ -7431,7 +7487,8 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], @@ -7440,7 +7497,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 },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": 5,\n \"modules\": [\n \"ngx_http_app_protect_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\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}}/{{ngc_api_version}}/nap-policy-gitops.json\"\n }\n }\n ]\n }\n ]\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -7508,7 +7565,7 @@ "response": [] }, { - "name": "Delete declaration", + "name": "Get declaration", "event": [ { "listen": "test", @@ -7520,8 +7577,11 @@ } } ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, "request": { - "method": "DELETE", + "method": "GET", "header": [], "body": { "mode": "raw", @@ -7549,7 +7609,7 @@ "response": [] }, { - "name": "Get declaration", + "name": "Delete declaration", "event": [ { "listen": "test", @@ -7561,11 +7621,8 @@ } } ], - "protocolProfileBehavior": { - "disableBodyPruning": true - }, "request": { - "method": "GET", + "method": "DELETE", "header": [], "body": { "mode": "raw", @@ -7595,10 +7652,10 @@ ] }, { - "name": "HTTP Headers Manipulation", + "name": "Housekeeping - common endpoints", "item": [ { - "name": "Create test echo service", + "name": "Clean NGINX configuration", "event": [ { "listen": "test", @@ -7620,7 +7677,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 },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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 \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\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 \"resolver\": \"Google\"\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\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 },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n }\n}", "options": { "raw": { "language": "json" @@ -7643,29 +7700,27 @@ "response": [] }, { - "name": "Manipulate headers - server level", + "name": "Get declaration status", "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": {} + "type": "text/javascript" } } ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, "request": { - "method": "PATCH", + "method": "GET", "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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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 \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\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-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 \"resolver\": \"Google\"\n }\n ]\n }\n }\n}", + "raw": "", "options": { "raw": { "language": "json" @@ -7673,7 +7728,7 @@ } }, "url": { - "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}", + "raw": "http://{{ncg_host}}:{{ncg_port}}/{{ngc_api_version}}/config/{{configUid}}/status", "protocol": "http", "host": [ "{{ncg_host}}" @@ -7682,36 +7737,32 @@ "path": [ "{{ngc_api_version}}", "config", - "{{configUid}}" + "{{configUid}}", + "status" ] } }, "response": [] }, { - "name": "Manipulate headers - location level", + "name": "Delete declaration", "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": {} + "type": "text/javascript" } } ], "request": { - "method": "PATCH", + "method": "DELETE", "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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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 \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test-echo-upstream\",\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 }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test-echo-upstream\",\n \"origin\": [\n {\n \"server\": \"echo.free.beeceptor.com\"\n }\n ],\n \"resolver\": \"Google\"\n }\n ]\n }\n }\n}", + "raw": "", "options": { "raw": { "language": "json" @@ -7733,38 +7784,29 @@ } }, "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", + "name": "Get declaration", "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": {}, - "requests": {} + "type": "text/javascript" } } ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, "request": { - "method": "POST", + "method": "GET", "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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n}", + "raw": "", "options": { "raw": { "language": "json" @@ -7772,7 +7814,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}}" @@ -7780,14 +7822,20 @@ "port": "{{ncg_port}}", "path": [ "{{ngc_api_version}}", - "config" + "config", + "{{configUid}}" ] } }, "response": [] - }, + } + ] + }, + { + "name": "HTTP Headers Manipulation", + "item": [ { - "name": "TLS Offload and F5 WAF for NGINX", + "name": "Create test echo service", "event": [ { "listen": "test", @@ -7800,8 +7848,7 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {}, - "requests": {} + "packages": {} } } ], @@ -7810,7 +7857,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 ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\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}}/{{ngc_api_version}}/nap-policy-xss-blocked.json\"\n }\n }\n ]\n }\n ]\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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 \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\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 \"resolver\": \"Google\"\n }\n ]\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -7831,14 +7878,9 @@ } }, "response": [] - } - ] - }, - { - "name": "JWT Client Authentication", - "item": [ + }, { - "name": "JWT Client Authentication - local JWT key and Bearer token", + "name": "Manipulate headers - server level", "event": [ { "listen": "test", @@ -7856,11 +7898,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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test service\",\n \"resolver\": \"Google\",\n \"names\": [\n \"test.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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 \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\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-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 \"resolver\": \"Google\"\n }\n ]\n }\n }\n}", "options": { "raw": { "language": "json" @@ -7868,7 +7910,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}}" @@ -7876,14 +7918,15 @@ "port": "{{ncg_port}}", "path": [ "{{ngc_api_version}}", - "config" + "config", + "{{configUid}}" ] } }, "response": [] }, { - "name": "JWT secret fetched from URL", + "name": "Manipulate headers - location level", "event": [ { "listen": "test", @@ -7905,7 +7948,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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test service\",\n \"resolver\": \"Google\",\n \"names\": [\n \"test.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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}", + "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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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 \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\n },\n \"locations\": [\n {\n \"uri\": \"/\",\n \"urimatch\": \"prefix\",\n \"upstream\": \"http://test-echo-upstream\",\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 }\n ]\n }\n ],\n \"upstreams\": [\n {\n \"name\": \"test-echo-upstream\",\n \"origin\": [\n {\n \"server\": \"echo.free.beeceptor.com\"\n }\n ],\n \"resolver\": \"Google\"\n }\n ]\n }\n }\n}", "options": { "raw": { "language": "json" @@ -7927,9 +7970,15 @@ } }, "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": "JWT token in auth_token query string parameter", + "name": "TLS Offload", "event": [ { "listen": "test", @@ -7942,16 +7991,17 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], "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 },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test service\",\n \"resolver\": \"Google\",\n \"names\": [\n \"test.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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}", + "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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -7959,7 +8009,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}}" @@ -7967,15 +8017,14 @@ "port": "{{ncg_port}}", "path": [ "{{ngc_api_version}}", - "config", - "{{configUid}}" + "config" ] } }, "response": [] }, { - "name": "JWT token in HTTP X-Auth-Token header", + "name": "TLS Offload and F5 WAF for NGINX", "event": [ { "listen": "test", @@ -7988,16 +8037,17 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], "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 },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test service\",\n \"resolver\": \"Google\",\n \"names\": [\n \"test.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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}", + "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 },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\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}}/{{ngc_api_version}}/nap-policy-xss-blocked.json\"\n }\n }\n ]\n }\n ]\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\n }\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -8005,7 +8055,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}}" @@ -8013,8 +8063,7 @@ "port": "{{ncg_port}}", "path": [ "{{ngc_api_version}}", - "config", - "{{configUid}}" + "config" ] } }, @@ -8023,10 +8072,10 @@ ] }, { - "name": "JWT Client Authentication and Authorization", + "name": "JWT Client Authentication", "item": [ { - "name": "JWT Client Authentication and Authorization", + "name": "JWT Client Authentication - local JWT key and Bearer token", "event": [ { "listen": "test", @@ -8048,7 +8097,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 },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"JWT AuthN and AuthZ test server\",\n \"resolver\": \"Google\",\n \"names\": [\n \"test.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:80\"\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test service\",\n \"resolver\": \"Google\",\n \"names\": [\n \"test.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -8069,14 +8118,9 @@ } }, "response": [] - } - ] - }, - { - "name": "mTLS Client Authentication", - "item": [ + }, { - "name": "HTTPS server with mTLS, OCSP, SSL Stapling", + "name": "JWT secret fetched from URL", "event": [ { "listen": "test", @@ -8089,17 +8133,16 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {}, - "requests": {} + "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 },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"vm-blank.ff.lan\"\n ],\n \"resolver\": \"internal_lan\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"internal_lan\",\n \"address\": \"192.168.2.13\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\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}", + "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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test service\",\n \"resolver\": \"Google\",\n \"names\": [\n \"test.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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" @@ -8107,7 +8150,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}}" @@ -8115,19 +8158,15 @@ "port": "{{ncg_port}}", "path": [ "{{ngc_api_version}}", - "config" + "config", + "{{configUid}}" ] } }, "response": [] - } - ] - }, - { - "name": "F5 WAF for NGINX", - "item": [ + }, { - "name": "Create initial NGINX configuration with F5 WAF for NGINX", + "name": "JWT token in auth_token query string parameter", "event": [ { "listen": "test", @@ -8140,17 +8179,16 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {}, - "requests": {} + "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_app_protect_module\"\n ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\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}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/nap-policy-xss-allowed.json\"\n }\n }\n ]\n }\n ]\n },\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert.key\"\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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test service\",\n \"resolver\": \"Google\",\n \"names\": [\n \"test.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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" @@ -8158,7 +8196,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}}" @@ -8166,14 +8204,15 @@ "port": "{{ncg_port}}", "path": [ "{{ngc_api_version}}", - "config" + "config", + "{{configUid}}" ] } }, "response": [] }, { - "name": "Change active F5 WAF for NGINX policy", + "name": "JWT token in HTTP X-Auth-Token header", "event": [ { "listen": "test", @@ -8186,8 +8225,7 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {}, - "requests": {} + "packages": {} } } ], @@ -8196,7 +8234,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 ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\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}}/{{ngc_api_version}}/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}}/{{ngc_api_version}}/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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Test service\",\n \"resolver\": \"Google\",\n \"names\": [\n \"test.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"80\"\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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" @@ -8218,9 +8256,14 @@ } }, "response": [] - }, + } + ] + }, + { + "name": "JWT Client Authentication and Authorization", + "item": [ { - "name": "Update TLS certificates", + "name": "JWT Client Authentication and Authorization", "event": [ { "listen": "test", @@ -8233,17 +8276,16 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {}, - "requests": {} + "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 ]\n },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"certificates\": [\n {\n \"type\": \"certificate\",\n \"name\": \"test_cert\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert2.crt\"\n }\n },\n {\n \"type\": \"key\",\n \"name\": \"test_key\",\n \"contents\": {\n \"content\": \"{{github_gitops_root}}/{{ngc_api_version}}/testcert2.key\"\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 \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"JWT AuthN and AuthZ test server\",\n \"resolver\": \"Google\",\n \"names\": [\n \"test.nginx.lab\"\n ],\n \"listen\": {\n \"address\": \"0.0.0.0:80\"\n },\n \"log\": {\n \"access\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"Google\",\n \"address\": \"8.8.8.8\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\n ]\n }\n}", "options": { "raw": { "language": "json" @@ -8251,7 +8293,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}}" @@ -8259,15 +8301,19 @@ "port": "{{ncg_port}}", "path": [ "{{ngc_api_version}}", - "config", - "{{configUid}}" + "config" ] } }, "response": [] - }, + } + ] + }, + { + "name": "mTLS Client Authentication", + "item": [ { - "name": "Disable F5 WAF for NGINX", + "name": "HTTPS server with mTLS, OCSP, SSL Stapling", "event": [ { "listen": "test", @@ -8280,16 +8326,17 @@ "pm.collectionVariables.set('configUid',respData.configUid);" ], "type": "text/javascript", - "packages": {} + "packages": {}, + "requests": {} } } ], "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 },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 },\n \"license\": {\n \"endpoint\": \"{{nginx_reporting_server}}\",\n \"token\": \"{{nginx_license_token}}\",\n \"ssl_verify\": false,\n \"grace_period\": false\n }\n },\n \"declaration\": {\n \"http\": {\n \"servers\": [\n {\n \"name\": \"Online boutique HTTPS\",\n \"names\": [\n \"vm-blank.ff.lan\"\n ],\n \"resolver\": \"internal_lan\",\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\": {\n \"destination\": \"/var/log/nginx/server-access.log\"\n },\n \"error\": {\n \"destination\": \"/var/log/nginx/server-error.log\"\n }\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 \"nginx_plus_api\": {\n \"write\": false,\n \"listen\": \"127.0.0.1:8080\",\n \"allow_acl\": \"0.0.0.0/0\"\n }\n },\n \"resolvers\": [\n {\n \"name\": \"internal_lan\",\n \"address\": \"192.168.2.13\",\n \"ipv4\": true,\n \"ipv6\": false,\n \"timeout\": \"30s\"\n }\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}", "options": { "raw": { "language": "json" @@ -8297,7 +8344,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}}" @@ -8305,8 +8352,7 @@ "port": "{{ncg_port}}", "path": [ "{{ngc_api_version}}", - "config", - "{{configUid}}" + "config" ] } }, diff --git a/contrib/postman/README.md b/contrib/postman/README.md index 518bf304..624c97cc 100644 --- a/contrib/postman/README.md +++ b/contrib/postman/README.md @@ -2,5 +2,5 @@ This collection contains several declaration examples for the following NGINX Declarative API releases: -* v5.5 - latest -* v5.4 - stable +* v5.6 - latest +* v5.5 - stable From 1f96d5b616488f5d5808eec7afe91bfd97ea47f0 Mon Sep 17 00:00:00 2001 From: Fabrizio Fiorucci Date: Thu, 7 May 2026 15:34:12 +0100 Subject: [PATCH 11/12] Added control plane config file Revamped configuration from toml to yaml --- .../templates/service.yaml | 2 +- etc/config.toml | 90 ------------------ etc/config.yaml | 92 +++++++++++++++++++ etc/controlplane.yaml | 57 ++++++++++++ src/NcgConfig.py | 12 +-- src/main.py | 2 +- 6 files changed, 157 insertions(+), 98 deletions(-) delete mode 100644 etc/config.toml create mode 100644 etc/config.yaml create mode 100644 etc/controlplane.yaml diff --git a/contrib/helm/nginx-declarative-api/templates/service.yaml b/contrib/helm/nginx-declarative-api/templates/service.yaml index a597ade8..fe1c16c3 100644 --- a/contrib/helm/nginx-declarative-api/templates/service.yaml +++ b/contrib/helm/nginx-declarative-api/templates/service.yaml @@ -29,7 +29,7 @@ spec: apiVersion: v1 kind: Service metadata: - # Fixed name "redis" — the app reads config.toml which hardcodes this hostname. + # Fixed name "redis" — the app reads config.yaml which hardcodes this hostname. name: {{ include "nginx-declarative-api.redis.serviceName" . }} namespace: {{ include "nginx-declarative-api.namespace" . }} labels: diff --git a/etc/config.toml b/etc/config.toml deleted file mode 100644 index c7515fc0..00000000 --- a/etc/config.toml +++ /dev/null @@ -1,90 +0,0 @@ -# NGINX Declarative API - https://github.com/f5devcentral/NGINX-Declarative-API/ - -# Main variables -[main] -banner = "NGINX Declarative API" -version = "5.6.0" -url = "https://github.com/f5devcentral/NGINX-Declarative-API" - -# Templates -[templates] -root_dir = "../templates" -nginxmain = "nginx-conf/nginx.conf" -mimetypes = "nginx-conf/mime.types" -license = "nginx-conf/license-key.tmpl" - -httpconf = "http.tmpl" -apigwconf = "apigateway.tmpl" -apigwmapsconf = "apigateway-maps.tmpl" -visibility_root = "visibility" -streamconf = "stream.tmpl" -configmap = "configmap.tmpl" -resolver = "misc/resolver.tmpl" - -server_http = "misc/server-http.tmpl" -server_stream = "misc/server-stream.tmpl" - -upstream_http = "misc/upstream-http.tmpl" -upstream_stream = "misc/upstream-stream.tmpl" - -auth_client_root = "authn/client" -auth_server_root = "authn/server" - -authz_client_root = "authz/client" - -acme_issuer = "misc/acme.tmpl" - -devportal_root = "devportal" -misc_root = "misc" - -# NGINX Declarative API Server -[apiserver] -host = "0.0.0.0" -port = 5000 - -# Redis backend -[redis] -host = "redis" -port = 6379 - -# Redocly devportal helper -[devportal] -host = "devportal" -port = 5000 -uri = "/v1/devportal" - -# Staged configuration directories -[nms] -config_dir = '/etc/nginx' -certs_dir = '/etc/nginx/ssl' -acme_dir = '/etc/nginx/acme' -apigw_dir = '/etc/nginx/apigateway' -apigw_maps_dir = '/etc/nginx/apigateway/maps' -visibility_dir = '/etc/nginx/visibility' -devportal_dir = '/etc/nginx/devportal' -auth_client_dir = '/etc/nginx/authn/client' -auth_server_dir = '/etc/nginx/authn/server' -authz_client_dir = '/etc/nginx/authz/client' -njs_dir = '/etc/nginx/njs' -resolver_dir = '/etc/nginx/resolvers' -server_http_dir = '/etc/nginx/servers/http' -upstream_http_dir = '/etc/nginx/upstreams/http' -server_stream_dir = '/etc/nginx/servers/stream' -upstream_stream_dir = '/etc/nginx/upstreams/stream' - -# Time (in seconds) to wait to get status after committing a staged config -staged_config_publish_waittime = 2 - -# Time (in seconds) to wait between two subsequent asynchronous submissions publish requests through PATCH -asynchronous_publish_waittime = 30 - -# NGINX App Protect support -nap_policies_dir = '/etc/nginx/waf/policies' -nap_logformats_dir = '/etc/nginx/waf/logformats' -nap_logformats_template = "logformat.tmpl" -nap_policies_dir_pum = '/etc/nms' -nap_logformats_dir_pum = '/etc/nms' - -# Staged configuration filenames -staged_config_http_filename = 'conf.d/services.conf' -staged_config_stream_filename = 'stream-conf.d/services.conf' diff --git a/etc/config.yaml b/etc/config.yaml new file mode 100644 index 00000000..afeee90f --- /dev/null +++ b/etc/config.yaml @@ -0,0 +1,92 @@ +# +# NGINX Declarative API - https://github.com/f5devcentral/NGINX-Declarative-API/ +# Main configuration file +# + +# Main variables +main: + banner: "NGINX Declarative API" + version: "5.6.0" + url: "https://github.com/f5devcentral/NGINX-Declarative-API" + +# Templates +templates: + root_dir: "../templates" + nginxmain: "nginx-conf/nginx.conf" + mimetypes: "nginx-conf/mime.types" + license: "nginx-conf/license-key.tmpl" + + httpconf: "http.tmpl" + apigwconf: "apigateway.tmpl" + apigwmapsconf: "apigateway-maps.tmpl" + visibility_root: "visibility" + streamconf: "stream.tmpl" + configmap: "configmap.tmpl" + resolver: "misc/resolver.tmpl" + + server_http: "misc/server-http.tmpl" + server_stream: "misc/server-stream.tmpl" + + upstream_http: "misc/upstream-http.tmpl" + upstream_stream: "misc/upstream-stream.tmpl" + + auth_client_root: "authn/client" + auth_server_root: "authn/server" + authz_client_root: "authz/client" + + acme_issuer: "misc/acme.tmpl" + + devportal_root: "devportal" + misc_root: "misc" + +# NGINX Declarative API Server +apiserver: + host: "0.0.0.0" + port: 5000 + +# Redis backend +redis: + host: "redis" + port: 6379 + +# Redocly devportal helper +devportal: + host: "devportal" + port: 5000 + uri: "/v1/devportal" + +# Staged configuration directories +nms: + config_dir: "/etc/nginx" + certs_dir: "/etc/nginx/ssl" + acme_dir: "/etc/nginx/acme" + apigw_dir: "/etc/nginx/apigateway" + apigw_maps_dir: "/etc/nginx/apigateway/maps" + visibility_dir: "/etc/nginx/visibility" + devportal_dir: "/etc/nginx/devportal" + auth_client_dir: "/etc/nginx/authn/client" + auth_server_dir: "/etc/nginx/authn/server" + authz_client_dir: "/etc/nginx/authz/client" + njs_dir: "/etc/nginx/njs" + resolver_dir: "/etc/nginx/resolvers" + server_http_dir: "/etc/nginx/servers/http" + upstream_http_dir: "/etc/nginx/upstreams/http" + server_stream_dir: "/etc/nginx/servers/stream" + upstream_stream_dir: "/etc/nginx/upstreams/stream" + + # Time (in seconds) to wait to get status after committing a staged config + staged_config_publish_waittime: 2 + + # Time (in seconds) to wait between two subsequent asynchronous submissions publish requests through PATCH + asynchronous_publish_waittime: 30 + + # NGINX App Protect support + nap_policies_dir: "/etc/nginx/waf/policies" + nap_logformats_dir: "/etc/nginx/waf/logformats" + nap_logformats_template: "logformat.tmpl" + nap_policies_dir_pum: "/etc/nms" + nap_logformats_dir_pum: "/etc/nms" + + # Staged configuration filenames + staged_config_http_filename: "conf.d/services.conf" + staged_config_stream_filename: "stream-conf.d/services.conf" \ No newline at end of file diff --git a/etc/controlplane.yaml b/etc/controlplane.yaml new file mode 100644 index 00000000..42c89dac --- /dev/null +++ b/etc/controlplane.yaml @@ -0,0 +1,57 @@ +# +# NGINX Declarative API +# Control plane and licensing configuration +# + +spec: + + # + # Available control planes. NGINX Instance Manager and NGINX One Console currently supported + # + control_planes: + - name: NGINX_Instance_Manager + type: nms + url: https:// + username: + password: + - name: NGINX_One_Console + type: nginxone + url: https://.volterra.us + token: + + # + # NGINX One licenses + # + licenses: + - name: + token: + + # + # Usage reporting endpoints + # + reporting_endpoints: + - name: Report_to_NGINX_Instance_Manager + endpoint: + ssl_verify: false + proxy: + proxy_username: + proxy_password: + - name: Report_to_F5 + endpoint: product.connect.nginx.com + ssl_verify: false + proxy: + proxy_username: + proxy_password: + + # + # Instance groups (NGINX Instance Manager) / config sync groups (NGINX One Console) + # + instance_groups: + - name: + license: + reporting_endpoint: Report_to_F5 + grace_period: true + control_plane: NGINX_One_Console + synctime: 0 + modules: + - ngx_http_app_protect_module \ No newline at end of file diff --git a/src/NcgConfig.py b/src/NcgConfig.py index da170ac7..644ae689 100644 --- a/src/NcgConfig.py +++ b/src/NcgConfig.py @@ -2,19 +2,19 @@ Configuration singleton """ -import toml +import yaml class NcgConfig(object): _instance = None config = {} - def __new__(cls,configFile): + def __new__(cls, configFile): if cls._instance is None: - print(f'Reading configuration from {configFile}') + print(f"Reading configuration from {configFile}") cls._instance = super(cls, NcgConfig).__new__(cls) - with open(configFile) as cfgFile: - cls.config = toml.load(cfgFile) + with open(configFile, "r") as cfgFile: + cls.config = yaml.safe_load(cfgFile) - return cls._instance + return cls._instance \ No newline at end of file diff --git a/src/main.py b/src/main.py index f1a6fc9b..28b05cb5 100644 --- a/src/main.py +++ b/src/main.py @@ -24,7 +24,7 @@ import V5_6_NginxConfigDeclaration import v5_6.Asynchronous -cfg = NcgConfig.NcgConfig(configFile="../etc/config.toml") +cfg = NcgConfig.NcgConfig(configFile="../etc/config.yaml") redis = NcgRedis(host=cfg.config['redis']['host'], port=cfg.config['redis']['port']) app = FastAPI( From ffdeaef80a02a537f1abb32827c93aec25a7aefa Mon Sep 17 00:00:00 2001 From: Fabrizio Fiorucci Date: Wed, 20 May 2026 16:57:27 +0100 Subject: [PATCH 12/12] Config files updates --- etc/controlplane.yaml | 57 ------------------------------------------- 1 file changed, 57 deletions(-) delete mode 100644 etc/controlplane.yaml diff --git a/etc/controlplane.yaml b/etc/controlplane.yaml deleted file mode 100644 index 42c89dac..00000000 --- a/etc/controlplane.yaml +++ /dev/null @@ -1,57 +0,0 @@ -# -# NGINX Declarative API -# Control plane and licensing configuration -# - -spec: - - # - # Available control planes. NGINX Instance Manager and NGINX One Console currently supported - # - control_planes: - - name: NGINX_Instance_Manager - type: nms - url: https:// - username: - password: - - name: NGINX_One_Console - type: nginxone - url: https://.volterra.us - token: - - # - # NGINX One licenses - # - licenses: - - name: - token: - - # - # Usage reporting endpoints - # - reporting_endpoints: - - name: Report_to_NGINX_Instance_Manager - endpoint: - ssl_verify: false - proxy: - proxy_username: - proxy_password: - - name: Report_to_F5 - endpoint: product.connect.nginx.com - ssl_verify: false - proxy: - proxy_username: - proxy_password: - - # - # Instance groups (NGINX Instance Manager) / config sync groups (NGINX One Console) - # - instance_groups: - - name: - license: - reporting_endpoint: Report_to_F5 - grace_period: true - control_plane: NGINX_One_Console - synctime: 0 - modules: - - ngx_http_app_protect_module \ No newline at end of file