├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── CONTRIBUTING.md ├── Dockerfile ├── FEATURES.md ├── LICENSE.md ├── README.md ├── USAGE-v5.1.md ├── USAGE-v5.2.md ├── USAGE-v5.3.md ├── code_of_conduct.md ├── contrib ├── README.md ├── app-protect │ ├── Dockerfile │ ├── README.md │ └── src │ │ ├── requirements.txt │ │ ├── server.py │ │ └── start.sh ├── devportal │ └── redocly │ │ ├── Dockerfile │ │ ├── README.md │ │ └── src │ │ ├── requirements.txt │ │ ├── server.py │ │ └── start.sh ├── docker-compose │ ├── README.md │ ├── docker-compose.yaml │ └── nginx-dapi.sh ├── gitops-examples │ ├── jkws.json │ ├── v5.1 │ │ ├── apigw.nginx.lab.crt │ │ ├── apigw.nginx.lab.key │ │ ├── client.cert.pem │ │ ├── client.key.pem │ │ ├── nap-policy-xss-allowed.json │ │ ├── nap-policy-xss-blocked-bot-allowed.json │ │ ├── nap-policy-xss-blocked.json │ │ ├── testcert.chain │ │ ├── testcert.crt │ │ ├── testcert.key │ │ ├── testcert2.chain │ │ ├── testcert2.crt │ │ └── testcert2.key │ ├── v5.2 │ │ ├── apigw.nginx.lab.crt │ │ ├── apigw.nginx.lab.key │ │ ├── client.cert.pem │ │ ├── client.key.pem │ │ ├── nap-policy-xss-allowed.json │ │ ├── nap-policy-xss-blocked-bot-allowed.json │ │ ├── nap-policy-xss-blocked.json │ │ ├── testcert.chain │ │ ├── testcert.crt │ │ ├── testcert.key │ │ ├── testcert2.chain │ │ ├── testcert2.crt │ │ └── testcert2.key │ └── v5.3 │ │ ├── apigw.nginx.lab.crt │ │ ├── apigw.nginx.lab.key │ │ ├── client.cert.pem │ │ ├── client.key.pem │ │ ├── nap-policy-xss-allowed.json │ │ ├── nap-policy-xss-blocked-bot-allowed.json │ │ ├── nap-policy-xss-blocked.json │ │ ├── testcert.chain │ │ ├── testcert.crt │ │ ├── testcert.key │ │ ├── testcert2.chain │ │ ├── testcert2.crt │ │ └── testcert2.key ├── kubernetes │ ├── README.md │ └── nginx-declarative-api.yaml └── postman │ ├── NGINX Declarative API.postman_collection.json │ └── README.md ├── etc └── config.toml ├── src ├── NcgConfig.py ├── NcgRedis.py ├── V5_1_CreateConfig.py ├── V5_1_NginxConfigDeclaration.py ├── V5_2_CreateConfig.py ├── V5_2_NginxConfigDeclaration.py ├── V5_3_CreateConfig.py ├── V5_3_NginxConfigDeclaration.py ├── main.py ├── requirements.txt ├── v5_1 │ ├── APIGateway.py │ ├── DeclarationPatcher.py │ ├── DevPortal.py │ ├── GitOps.py │ ├── MiscUtils.py │ ├── NAPUtils.py │ ├── NGINXOneOutput.py │ ├── NGINXOneUtils.py │ ├── NIMUtils.py │ ├── NMSOutput.py │ └── OpenAPIParser.py ├── v5_2 │ ├── APIGateway.py │ ├── DeclarationPatcher.py │ ├── DevPortal.py │ ├── GitOps.py │ ├── MiscUtils.py │ ├── NAPUtils.py │ ├── NGINXOneOutput.py │ ├── NGINXOneUtils.py │ ├── NIMOutput.py │ ├── NIMUtils.py │ └── OpenAPIParser.py └── v5_3 │ ├── APIGateway.py │ ├── Asynchronous.py │ ├── DeclarationPatcher.py │ ├── DevPortal.py │ ├── GitOps.py │ ├── MiscUtils.py │ ├── NAPUtils.py │ ├── NGINXOneOutput.py │ ├── NGINXOneUtils.py │ ├── NIMOutput.py │ ├── NIMUtils.py │ └── OpenAPIParser.py └── templates ├── v5.1 ├── apigateway.tmpl ├── authn │ ├── client │ │ ├── jwks.tmpl │ │ ├── jwt.tmpl │ │ └── mtls.tmpl │ └── server │ │ ├── mtls.tmpl │ │ └── token.tmpl ├── authz │ └── client │ │ ├── jwt-authz-map.tmpl │ │ └── jwt.tmpl ├── configmap.tmpl ├── devportal │ └── backstage.tmpl ├── http.tmpl ├── logformat.tmpl ├── misc │ ├── resolver.tmpl │ ├── upstream-http.tmpl │ └── upstream-stream.tmpl ├── nginx-conf │ ├── mime.types │ └── nginx.conf ├── stream.tmpl └── visibility │ └── moesif │ ├── http.tmpl │ └── server.tmpl ├── v5.2 ├── apigateway.tmpl ├── authn │ ├── client │ │ ├── jwks.tmpl │ │ ├── jwt.tmpl │ │ └── mtls.tmpl │ └── server │ │ ├── mtls.tmpl │ │ └── token.tmpl ├── authz │ └── client │ │ ├── jwt-authz-map.tmpl │ │ └── jwt.tmpl ├── devportal │ └── backstage.tmpl ├── http.tmpl ├── logformat.tmpl ├── misc │ ├── resolver.tmpl │ ├── upstream-http.tmpl │ └── upstream-stream.tmpl ├── nginx-conf │ ├── license-key.tmpl │ ├── mime.types │ └── nginx.conf ├── stream.tmpl └── visibility │ └── moesif │ ├── http.tmpl │ └── server.tmpl └── v5.3 ├── apigateway.tmpl ├── authn ├── client │ ├── jwks.tmpl │ ├── jwt.tmpl │ └── mtls.tmpl └── server │ ├── mtls.tmpl │ └── token.tmpl ├── authz └── client │ ├── jwt-authz-map.tmpl │ └── jwt.tmpl ├── devportal └── backstage.tmpl ├── http.tmpl ├── logformat.tmpl ├── misc ├── resolver.tmpl ├── upstream-http.tmpl └── upstream-stream.tmpl ├── nginx-conf ├── license-key.tmpl ├── mime.types └── nginx.conf ├── stream.tmpl └── visibility └── moesif ├── http.tmpl └── server.tmpl /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Any private crt and keys # 2 | ############################ 3 | #*.crt 4 | #*.key 5 | *~ 6 | \#* 7 | 8 | # OS Specific # 9 | ############### 10 | Thumbs.db 11 | .DS_Store 12 | .vscode 13 | 14 | # Logs # 15 | ######## 16 | *.log 17 | 18 | # Additional dirs # 19 | ################### 20 | ======= 21 | /.idea/ 22 | /src/__pycache__/ 23 | /src/v5_1/__pycache__/ 24 | /src/v5_2/__pycache__/ 25 | /src/v5_3/__pycache__/ 26 | /contrib/devportal/redocly/src/__pycache__/ 27 | /contrib/app-protect/src/__pycache__/ 28 | /venv/ 29 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | The following is a set of guidelines for contributing to NGINX Declarative API. We really appreciate that you are considering contributing! 4 | 5 | ## Getting Started 6 | 7 | Follow our [Getting Started Guide](README.md) to get NGINX Declarative API up and running. 8 | 9 | ## Contributing 10 | 11 | ### Report a Bug 12 | 13 | To report a bug, open an issue on GitHub with the label `bug` using the available bug report issue template. Please ensure the bug has not already been reported. 14 | 15 | ### Suggest a Feature or Enhancement 16 | 17 | To suggest a feature or enhancement, please create an issue on GitHub with the label `enhancement`. Please ensure the feature or enhancement has not already been suggested. 18 | 19 | ### Open a Pull Request 20 | 21 | - Fork the repo, create a branch, implement your changes, add any relevant tests, submit a PR when your changes are **tested** and ready for review. 22 | 23 | ## Code Guidelines 24 | 25 | ### Git Guidelines 26 | 27 | - Keep a clean, concise and meaningful git commit history on your branch (within reason), rebasing locally and squashing before submitting a PR. 28 | - If possible and/or relevant, use the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) format when writing a commit message, so that changelogs can be automatically generated 29 | - Follow the guidelines of writing a good commit message as described here and summarised in the next few points: 30 | - In the subject line, use the present tense ("Add feature" not "Added feature"). 31 | - In the subject line, use the imperative mood ("Move cursor to..." not "Moves cursor to..."). 32 | - Limit the subject line to 72 characters or less. 33 | - Reference issues and pull requests liberally after the subject line. 34 | - Add more detailed description in the body of the git message (`git commit -a` to give you more space and time in your text editor to write a good message instead of `git commit -am`). 35 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | 3 | RUN apk update && apk upgrade && \ 4 | apk add --update --no-cache python3 5 | 6 | WORKDIR /deployment 7 | 8 | COPY etc/ etc/ 9 | COPY src/ src/ 10 | COPY templates/ templates/ 11 | 12 | RUN python3 -m venv /deployment/env/ && \ 13 | source /deployment/env/bin/activate && \ 14 | # python3 -m pip install --upgrade pip && \ 15 | pip3 install --no-cache --upgrade pip setuptools virtualenv && \ 16 | pip3 install -r src/requirements.txt 17 | 18 | WORKDIR /deployment/src 19 | CMD ["/deployment/env/bin/python3", "./main.py"] 20 | -------------------------------------------------------------------------------- /USAGE-v5.1.md: -------------------------------------------------------------------------------- 1 | # Usage for NGINX Declarative API v5.1 2 | 3 | Version 5.1 supports: 4 | 5 | - [NGINX Instance Manager](https://docs.nginx.com/nginx-management-suite/nim/) 2.14+ 6 | - [NGINX One Cloud Console](https://docs.nginx.com/nginx-one/) 7 | - [NGINX Plus](https://docs.nginx.com/nginx/) R30, R31, R32 8 | - [NGINX App Protect WAF](https://docs.nginx.com/nginx-app-protect-waf/) 4 with precompiled [policy bundles](https://docs.nginx.com/nginx-app-protect-waf/v5/admin-guide/compiler/) 9 | 10 | The JSON schema is self explanatory. See also the [sample Postman collection](/contrib/postman) for usage examples 11 | 12 | - `.output.type` defines how NGINX configuration will be returned: 13 | - *nms* - NGINX configuration is published as a Staged Config to NGINX Instance Manager 14 | - `.output.nms.url` the NGINX Instance Manager URL 15 | - `.output.nms.username` the NGINX Instance Manager authentication username 16 | - `.output.nms.password` the NGINX Instance Manager authentication password 17 | - `.output.nms.instancegroup` the NGINX Instance Manager instance group to publish the configuration to 18 | - `.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 19 | - `.output.nms.modules` an optional array of NGINX module names (ie. 'ngx_http_app_protect_module', 'ngx_http_js_module','ngx_stream_js_module') 20 | - `.output.nms.certificates` an optional array of TLS certificates/keys/chains to be published 21 | - `.output.nms.certificates[].type` the item type ('certificate', 'key', 'chain') 22 | - `.output.nms.certificates[].name` the certificate/key/chain name with no path/extension (ie. 'test-application') 23 | - `.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 24 | - `.output.nms.policies[]` an optional array of NGINX App Protect security policies 25 | - `.output.nms.policies[].type` the policy type ('app_protect') 26 | - `.output.nms.policies[].name` the policy name (ie. 'prod-policy') 27 | - `.output.nms.policies[].active_tag` the policy tag to enable among all available versions (ie. 'v1') 28 | - `.output.nms.policies[].versions[]` array with all available policy versions 29 | - `.output.nms.policies[].versions[].tag` the policy version's tag name 30 | - `.output.nms.policies[].versions[].displayName` the policy version's display name 31 | - `.output.nms.policies[].versions[].description` the policy version's description 32 | - `.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 33 | - *nginxone* - NGINX configuration is published to a NGINX One Cloud Console config sync group 34 | - `.output.nginxone.url` the NGINX One Cloud Console URL 35 | - `.output.nginxone.namespace` the NGINX One Cloud Console namespace 36 | - `.output.nginxone.token` the authentication token 37 | - `.output.nginxone.configsyncgroup` the NGINX One Cloud Console config sync group name 38 | - `.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 39 | - `.output.nginxone.modules` an optional array of NGINX module names (ie. 'ngx_http_app_protect_module', 'ngx_http_js_module','ngx_stream_js_module') 40 | - `.output.nginxone.certificates` an optional array of TLS certificates/keys/chains to be published 41 | - `.output.nginxone.certificates[].type` the item type ('certificate', 'key', 'chain') 42 | - `.output.nginxone.certificates[].name` the certificate/key/chain name with no path/extension (ie. 'test-application') 43 | - `.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 44 | - `.declaration` describes the NGINX configuration to be created 45 | - `.declaration.http[]` NGINX HTTP definitions 46 | - `.declaration.layer4[]` NGINX TCP/UDP definitions 47 | - `.declaration.resolvers[]` DNS resolvers definitions 48 | 49 | ### API endpoints 50 | 51 | - `POST /v5.1/config/` - Publish a new declaration 52 | - `PATCH /v5.1/config/{config_uid}` - Update an existing declaration 53 | - Per-HTTP server CRUD 54 | - Per-HTTP upstream CRUD 55 | - Per-Stream server CRUD 56 | - Per-Stream upstream CRUD 57 | - Per-NGINX App Protect WAF policy CRUD 58 | - `GET /v5.1/config/{config_uid}` - Retrieve an existing declaration 59 | - `DELETE /v5.1/config/{config_uid}` - Delete an existing declaration -------------------------------------------------------------------------------- /code_of_conduct.md: -------------------------------------------------------------------------------- 1 | 2 | # Contributor Covenant Code of Conduct 3 | 4 | ## Our Pledge 5 | 6 | We as members, contributors, and leaders pledge to make participation in our 7 | community a harassment-free experience for everyone, regardless of age, body 8 | size, visible or invisible disability, ethnicity, sex characteristics, gender 9 | identity and expression, level of experience, education, socio-economic status, 10 | nationality, personal appearance, race, religion, or sexual identity 11 | and orientation. 12 | 13 | We pledge to act and interact in ways that contribute to an open, welcoming, 14 | diverse, inclusive, and healthy community. 15 | 16 | ## Our Standards 17 | 18 | Examples of behavior that contributes to a positive environment for our 19 | community include: 20 | 21 | * Demonstrating empathy and kindness toward other people 22 | * Being respectful of differing opinions, viewpoints, and experiences 23 | * Giving and gracefully accepting constructive feedback 24 | * Accepting responsibility and apologizing to those affected by our mistakes, 25 | and learning from the experience 26 | * Focusing on what is best not just for us as individuals, but for the 27 | overall community 28 | 29 | Examples of unacceptable behavior include: 30 | 31 | * The use of sexualized language or imagery, and sexual attention or 32 | advances of any kind 33 | * Trolling, insulting or derogatory comments, and personal or political attacks 34 | * Public or private harassment 35 | * Publishing others' private information, such as a physical or email 36 | address, without their explicit permission 37 | * Other conduct which could reasonably be considered inappropriate in a 38 | professional setting 39 | 40 | ## Enforcement Responsibilities 41 | 42 | Community leaders are responsible for clarifying and enforcing our standards of 43 | acceptable behavior and will take appropriate and fair corrective action in 44 | response to any behavior that they deem inappropriate, threatening, offensive, 45 | or harmful. 46 | 47 | Community leaders have the right and responsibility to remove, edit, or reject 48 | comments, commits, code, wiki edits, issues, and other contributions that are 49 | not aligned to this Code of Conduct, and will communicate reasons for moderation 50 | decisions when appropriate. 51 | 52 | ## Scope 53 | 54 | This Code of Conduct applies within all community spaces, and also applies when 55 | an individual is officially representing the community in public spaces. 56 | Examples of representing our community include using an official e-mail address, 57 | posting via an official social media account, or acting as an appointed 58 | representative at an online or offline event. 59 | 60 | ## Enforcement 61 | 62 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 63 | reported to the community leaders responsible for enforcement. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /contrib/README.md: -------------------------------------------------------------------------------- 1 | # NGINX-Declarative-API contribs 2 | 3 | - [Devportal](devportal) - Redocly CLI wrapper 4 | - [Docker compose](docker-compose) - to run NGINX Declarative API using docker compose 5 | - [GitOps examples](gitops-examples) - sample source of truth objects 6 | - [Kubernetes](kubernetes) - to run NGINX Declarative API on Kubernetes 7 | - [Postman](postman) - Sample Postman collection to test and run NGINX Declarative API 8 | -------------------------------------------------------------------------------- /contrib/app-protect/Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | ARG VERSION_TAG 3 | ARG BASE_IMAGE=private-registry.nginx.com/nap/waf-compiler:${VERSION_TAG} 4 | FROM ${BASE_IMAGE} 5 | 6 | # Installing packages as root 7 | USER root 8 | 9 | ENV DEBIAN_FRONTEND="noninteractive" 10 | 11 | # REST API wrapper 12 | WORKDIR /compiler 13 | COPY src src/ 14 | # REST API wrapper 15 | 16 | RUN --mount=type=secret,id=nginx-crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode=0644 \ 17 | --mount=type=secret,id=nginx-key,dst=/etc/ssl/nginx/nginx-repo.key,mode=0644 \ 18 | apt-get update \ 19 | && apt-get install -y \ 20 | apt-transport-https \ 21 | lsb-release \ 22 | ca-certificates \ 23 | wget \ 24 | gnupg2 \ 25 | ubuntu-keyring \ 26 | && wget -qO - https://cs.nginx.com/static/keys/app-protect-security-updates.key | gpg --dearmor | \ 27 | tee /usr/share/keyrings/app-protect-security-updates.gpg >/dev/null \ 28 | && printf "deb [signed-by=/usr/share/keyrings/app-protect-security-updates.gpg] \ 29 | https://pkgs.nginx.com/app-protect-security-updates/ubuntu `lsb_release -cs` nginx-plus\n" | \ 30 | tee /etc/apt/sources.list.d/nginx-app-protect.list \ 31 | && wget -P /etc/apt/apt.conf.d https://cs.nginx.com/static/files/90pkgs-nginx \ 32 | && apt-get update \ 33 | && apt-get install -y \ 34 | app-protect-attack-signatures \ 35 | app-protect-bot-signatures \ 36 | app-protect-threat-campaigns \ 37 | # REST API wrapper 38 | && apt-get -y install python3 python3-venv \ 39 | && python3 -m venv /compiler/env/ \ 40 | && . /compiler/env/bin/activate \ 41 | && pip3 install --no-cache --upgrade pip setuptools virtualenv \ 42 | && python3 -m pip install --upgrade pip \ 43 | && pip3 install -r /compiler/src/requirements.txt \ 44 | # REST API wrapper 45 | && apt-get clean \ 46 | && rm -rf /var/lib/apt/lists/* 47 | 48 | # non-root default user (UID 101) 49 | USER nginx 50 | 51 | # REST API wrapper 52 | ENTRYPOINT [ "/compiler/src/start.sh" ] 53 | # REST API wrapper 54 | -------------------------------------------------------------------------------- /contrib/app-protect/README.md: -------------------------------------------------------------------------------- 1 | # REST API for NGINX App Protect WAF Compiler 2 | 3 | This contrib provides a set of REST API to use the NGINX App Protect 5 policy compiler 4 | 5 | ## REST API Endpoints 6 | 7 | - `/v1/compile/policy` - compiles a JSON policy into a bundle 8 | - Method: `POST` 9 | - Payload: `{"global-settings": "", "policy": "", "cookie-protection-seed": ""}` 10 | - `/v1/compile/logprofile` - compiles a log profile JSON into a bundle 11 | - Method: `POST` 12 | - Payload: `{"logprofile": ""}` 13 | - `/v1/bundle/info` - returns details on a compiled bundle 14 | - Method: `POST` 15 | - Payload: `{"bundle": ""}` 16 | 17 | Headers required for all endpoints: 18 | 19 | ``` 20 | Content-Type: application/json 21 | ``` -------------------------------------------------------------------------------- /contrib/app-protect/src/requirements.txt: -------------------------------------------------------------------------------- 1 | typing 2 | uvicorn 3 | fastapi 4 | uuid 5 | pyyaml 6 | -------------------------------------------------------------------------------- /contrib/app-protect/src/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | /compiler/env/bin/python /compiler/src/server.py 4 | -------------------------------------------------------------------------------- /contrib/devportal/redocly/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM redocly/cli 2 | 3 | WORKDIR /deployment 4 | 5 | COPY src src/ 6 | 7 | RUN apk update && \ 8 | apk add --update --no-cache bash python3 && \ 9 | python3 -m venv /deployment/env/ && \ 10 | . /deployment/env/bin/activate && \ 11 | pip3 install --no-cache --upgrade pip setuptools virtualenv && \ 12 | python3 -m pip install --upgrade pip && \ 13 | pip3 install -r /deployment/src/requirements.txt 14 | 15 | ENTRYPOINT [ "/deployment/src/start.sh" ] 16 | -------------------------------------------------------------------------------- /contrib/devportal/redocly/README.md: -------------------------------------------------------------------------------- 1 | # Developer portal add-on 2 | 3 | This is a wrapper for [Redocly CLI](https://redocly.com/docs/cli/) used by the NGINX declarative API to create and publish developer portals 4 | 5 | To build: 6 | 7 | docker build --no-cache -t . 8 | 9 | To run the pre-built image: 10 | 11 | docker run --rm -d -p 5001:5000 --name devportal fiorucci/nginx-declarative-api-devportal 12 | 13 | To test: 14 | 15 | curl -i -w '\n' 127.0.0.1:5001/v1/devportal -X POST -H "Content-Type: application/json" -d @ 16 | -------------------------------------------------------------------------------- /contrib/devportal/redocly/src/requirements.txt: -------------------------------------------------------------------------------- 1 | typing 2 | uvicorn 3 | fastapi 4 | uuid 5 | -------------------------------------------------------------------------------- /contrib/devportal/redocly/src/server.py: -------------------------------------------------------------------------------- 1 | import pathlib 2 | import uvicorn 3 | import subprocess 4 | import json 5 | import uuid 6 | 7 | from typing import Any, Dict, AnyStr, List, Union 8 | 9 | from fastapi import FastAPI, Request 10 | from fastapi.responses import PlainTextResponse, Response, JSONResponse 11 | 12 | app = FastAPI( 13 | title="Redocly connector", 14 | version="1.0.0", 15 | contact={"name": "GitHub", "url": "https://github.com/f5devcentral/NGINX-Declarative-API"} 16 | ) 17 | 18 | JSONObject = Dict[AnyStr, Any] 19 | JSONArray = List[Any] 20 | JSONStructure = Union[JSONArray, JSONObject] 21 | 22 | @app.post("/v1/devportal", status_code=200, response_class=JSONResponse) 23 | def post_devportal(response: Response, request: JSONStructure = None): 24 | if request: 25 | try: 26 | sessionUUID = uuid.uuid4() 27 | apiSchema = json.dumps(request) 28 | tmpFileBase = f"/tmp/{sessionUUID}" 29 | tmpFileSchema = f"{tmpFileBase}.json" 30 | tmpFileDocs = f"{tmpFileBase}.html" 31 | tmpFile = open(tmpFileSchema,"w") 32 | tmpFile.write(apiSchema) 33 | tmpFile.close() 34 | 35 | output = subprocess.check_output(f"redocly build-docs '{tmpFileSchema}' --output={tmpFileDocs}", shell=True) 36 | 37 | with open(tmpFileDocs, 'r') as file: 38 | devPortal = file.read().replace('\n','') 39 | 40 | return JSONResponse (content={'status': 'success','apischema': f'{apiSchema}','devportal': f'{devPortal}'}, status_code=200) 41 | except subprocess.CalledProcessError as e: 42 | return JSONResponse (content={'status': str(e)}, status_code=400) 43 | finally: 44 | schemaFile = pathlib.Path(tmpFileSchema) 45 | if schemaFile.is_file(): 46 | schemaFile.unlink() 47 | 48 | docsFile = pathlib.Path(tmpFileDocs) 49 | if docsFile.is_file(): 50 | docsFile.unlink() 51 | else: 52 | return JSONResponse (content={'status': 'invalid body'}, status_code=400) 53 | 54 | if __name__ == '__main__': 55 | uvicorn.run("server:app", host='0.0.0.0', port=5000) 56 | -------------------------------------------------------------------------------- /contrib/devportal/redocly/src/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # https://redocly.com/docs/cli/commands/build-docs/ 4 | 5 | # Disable telemetry collection 6 | # https://github.com/Redocly/redocly-cli/#data-collection 7 | export REDOCLY_TELEMETRY=off 8 | 9 | /deployment/env/bin/python /deployment/src/server.py 10 | -------------------------------------------------------------------------------- /contrib/docker-compose/README.md: -------------------------------------------------------------------------------- 1 | # Docker compose 2 | 3 | NGINX Declarative API can be deployed using docker compose on a Linux virtual machine. 4 | 5 | Software prerequisites are: 6 | 7 | - [docker-compose v2.20+](https://github.com/docker/compose) 8 | - [jq](https://github.com/jqlang/jq) 9 | 10 | Usage: 11 | 12 | ``` 13 | $ git clone https://github.com/f5devcentral/NGINX-Declarative-API 14 | $ cd NGINX-Declarative-API/contrib/docker-compose 15 | $ ./nginx-dapi.sh 16 | NGINX Declarative API - https://github.com/f5devcentral/NGINX-Declarative-API/ 17 | 18 | This script is used to deploy/undeploy NGINX Declarative API using docker-compose 19 | 20 | === Usage: 21 | 22 | ./nginx-dapi.sh [options] 23 | 24 | === Options: 25 | 26 | -h - This help 27 | -w - Enable NGINX App Protect WAF compiler 28 | -c [start|stop|build] - Deployment command 29 | -C [file.crt] - Certificate to pull packages from the official NGINX repository (mandatory with -w) 30 | -K [file.key] - Key to pull packages from the official NGINX repository (mandatory with -w) 31 | 32 | === Examples: 33 | 34 | Deploy NGINX Declarative API: 35 | no NGINX App Protect compiler: ./nginx-dapi.sh -c start 36 | with NGINX App Protect compiler: ./nginx-dapi.sh -c start -w 37 | 38 | Remove NGINX Declarative API: 39 | ./nginx-dapi.sh -c stop 40 | 41 | Build docker images: 42 | no NGINX App Protect compiler: ./nginx-dapi.sh -c build 43 | with NGINX App Protect compiler: ./nginx-dapi.sh -c build -w -C /etc/ssl/nginx/nginx-repo.crt -K /etc/ssl/nginx/nginx-repo.key 44 | 45 | ``` 46 | 47 | ## Building docker images 48 | 49 | Without NGINX App Protect compiler 50 | 51 | ``` 52 | $ ./nginx-dapi.sh -c build 53 | -> Building NGINX Declarative API Docker images 54 | [+] Building 3.6s (24/24) FINISHED 55 | [...] 56 | => => exporting layers 57 | [...] 58 | 59 | $ docker images 60 | REPOSITORY TAG IMAGE ID CREATED SIZE 61 | nginx-declarative-api-devportal latest e1bd3cf9965a 1 minutes ago 669MB 62 | nginx-declarative-api latest 0d76c5a4338b 1 minutes ago 168MB 63 | ``` 64 | 65 | With NGINX App Protect compiler 66 | 67 | ``` 68 | $ ./nginx-dapi.sh -c build -w -C /etc/ssl/nginx/nginx-repo.crt -K /etc/ssl/nginx/nginx-repo.key 69 | -> Building NGINX Declarative API Docker images 70 | -> Including NGINX App Protect WAF compiler tag 5.2.0 71 | [+] Building 118.6s (36/36) FINISHED 72 | [...] 73 | => => exporting layers 74 | [...] 75 | 76 | $ docker images 77 | REPOSITORY TAG IMAGE ID CREATED SIZE 78 | nginx-declarative-api-nap-compiler latest cbdaa70bba4b 33 seconds ago 691MB 79 | nginx-declarative-api-devportal latest ad136e8dc5fd About a minute ago 669MB 80 | nginx-declarative-api latest 4c9f89903b6d About a minute ago 174MB 81 | ``` 82 | 83 | ## How to run 84 | 85 | 1. Start NGINX Declarative API using the provided `nginx-dapi.sh` script 86 | 2. Start Postman using the collection provided [here](/contrib/postman) 87 | 88 | ### Without NGINX App Protect compiler 89 | 90 | Starting: 91 | 92 | ```commandline 93 | $ ./nginx-dapi.sh -c start 94 | -> Deploying NGINX Declarative API 95 | [+] Building 0.0s (0/0) 96 | [+] Running 4/4 97 | ✔ Network nginx-dapi_dapi-network Created 98 | ✔ Container redis Started 99 | ✔ Container devportal Started 100 | ✔ Container nginx-dapi Started 101 | ``` 102 | 103 | Stopping: 104 | 105 | ```commandline 106 | $ ./nginx-dapi.sh -c stop 107 | -> Undeploying NGINX Declarative API 108 | [+] Running 4/4 109 | ✔ Container nginx-dapi Removed 110 | ✔ Container devportal Removed 111 | ✔ Container redis Removed 112 | ✔ Network nginx-dapi_dapi-network Removed 113 | ``` 114 | 115 | 116 | #### With NGINX App Protect compiler: 117 | 118 | Starting: 119 | 120 | ```commandline 121 | $ ./nginx-dapi.sh -c start -w 122 | -> Deploying NGINX Declarative API 123 | [+] Building 0.0s (0/0) 124 | [+] Running 5/5 125 | ✔ Network nginx-dapi_dapi-network Created 126 | ✔ Container redis Started 127 | ✔ Container nap-compiler Started 128 | ✔ Container devportal Started 129 | ✔ Container nginx-dapi Started 130 | ``` 131 | 132 | Stopping: 133 | 134 | ```commandline 135 | $ ./nginx-dapi.sh -c stop -w 136 | -> Undeploying NGINX Declarative API 137 | [+] Running 5/5 138 | ✔ Container nginx-dapi Removed 139 | ✔ Container devportal Removed 140 | ✔ Container nap-compiler Removed 141 | ✔ Container redis Removed 142 | ✔ Network nginx-dapi_dapi-network Removed 143 | ``` 144 | -------------------------------------------------------------------------------- /contrib/docker-compose/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | 3 | volumes: 4 | redis_data: 5 | 6 | services: 7 | redis: 8 | image: redis 9 | container_name: "redis" 10 | restart: always 11 | ports: 12 | - "6379:6379" 13 | networks: 14 | - dapi-network 15 | volumes: 16 | - redis_data:/data:rw 17 | 18 | devportal: 19 | image: nginx-declarative-api-devportal 20 | build: 21 | context: ../devportal/redocly 22 | dockerfile: Dockerfile 23 | user: "${USERID}:${USERGROUP}" 24 | container_name: "devportal" 25 | restart: always 26 | ports: 27 | - "5001:5000" 28 | networks: 29 | - dapi-network 30 | 31 | nap-compiler: 32 | profiles: 33 | - nap 34 | image: nginx-declarative-api-nap-compiler 35 | build: 36 | context: ../app-protect 37 | dockerfile: Dockerfile 38 | secrets: 39 | - nginx-crt 40 | - nginx-key 41 | args: 42 | VERSION_TAG: "${NAP_COMPILER_TAG}" 43 | container_name: "nap-compiler" 44 | restart: always 45 | ports: 46 | - "5002:5000" 47 | networks: 48 | - dapi-network 49 | 50 | nginx-dapi: 51 | image: nginx-declarative-api 52 | build: 53 | context: ../../ 54 | dockerfile: Dockerfile 55 | user: "${USERID}:${USERGROUP}" 56 | container_name: "nginx-dapi" 57 | restart: always 58 | depends_on: 59 | - redis 60 | ports: 61 | - "5000:5000" 62 | networks: 63 | - dapi-network 64 | 65 | networks: 66 | dapi-network: 67 | 68 | secrets: 69 | nginx-crt: 70 | file: ${NGINX_CERT} 71 | nginx-key: 72 | file: ${NGINX_KEY} 73 | -------------------------------------------------------------------------------- /contrib/docker-compose/nginx-dapi.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Usage 5 | # 6 | usage() { 7 | BANNER="NGINX Declarative API - https://github.com/f5devcentral/NGINX-Declarative-API/\n\n 8 | This script is used to deploy/undeploy NGINX Declarative API using docker-compose\n\n 9 | === Usage:\n\n 10 | $0 [options]\n\n 11 | === Options:\n\n 12 | -h\t\t\t- This help\n 13 | -w \t\t\t- Enable NGINX App Protect WAF compiler\n 14 | -c [start|stop|build]\t- Deployment command\n 15 | -C [file.crt]\t\t- Certificate to pull packages from the official NGINX repository (mandatory with -w)\n 16 | -K [file.key]\t\t- Key to pull packages from the official NGINX repository (mandatory with -w)\n\n 17 | === Examples:\n\n 18 | Deploy NGINX Declarative API:\n 19 | \tno NGINX App Protect compiler:\t\t$0 -c start\n 20 | \twith NGINX App Protect compiler:\t$0 -c start -w\n\n 21 | Remove NGINX Declarative API:\n 22 | \t$0 -c stop\n\n 23 | Build docker images:\n 24 | \tno NGINX App Protect compiler:\t\t$0 -c build\n 25 | \twith NGINX App Protect compiler:\t$0 -c build -w -C /etc/ssl/nginx/nginx-repo.crt -K /etc/ssl/nginx/nginx-repo.key 26 | \n" 27 | 28 | echo -e $BANNER 2>&1 29 | exit 1 30 | } 31 | 32 | # 33 | # NGINX Declarative API deployment 34 | # 35 | nginx_dapi_start() { 36 | 37 | # Docker compose variables 38 | USERNAME=`whoami` 39 | export USERID=`id -u $USERNAME` 40 | export USERGROUP=`id -g $USERNAME` 41 | 42 | echo "-> Deploying NGINX Declarative API" 43 | COMPOSE_HTTP_TIMEOUT=240 docker-compose -p $PROJECT_NAME -f $DOCKER_COMPOSE_YAML $DOCKER_COMPOSE_PROFILE up -d --remove-orphans 44 | } 45 | 46 | # 47 | # NGINX Declarative API removal 48 | # 49 | nginx_dapi_stop() { 50 | 51 | # Docker compose variables 52 | USERNAME=`whoami` 53 | export USERID=`id -u $USERNAME` 54 | export USERGROUP=`id -g $USERNAME` 55 | 56 | echo "-> Undeploying NGINX Declarative API" 57 | #COMPOSE_HTTP_TIMEOUT=240 docker-compose -p $PROJECT_NAME -f $DOCKER_COMPOSE_YAML $DOCKER_COMPOSE_PROFILE down 58 | COMPOSE_HTTP_TIMEOUT=240 docker-compose -p $PROJECT_NAME -f $DOCKER_COMPOSE_YAML --profile nap down 59 | } 60 | 61 | # 62 | # NGINX Declarative API removal 63 | # 64 | nginx_dapi_build() { 65 | 66 | # Docker compose variables 67 | USERNAME=`whoami` 68 | export USERID=`id -u $USERNAME` 69 | export USERGROUP=`id -g $USERNAME` 70 | 71 | echo "-> Building NGINX Declarative API Docker images" 72 | if ([ ! "${NGINX_CERT}" = "unused" ] && [ ! "${NGINX_KEY}" = "unused" ]) 73 | then 74 | export NAP_COMPILER_TAG=`curl -s https://private-registry.nginx.com/v2/nap/waf-compiler/tags/list --key $NGINX_KEY --cert $NGINX_CERT | jq -r '.tags|max'` 75 | echo "-> Including NGINX App Protect WAF compiler tag $NAP_COMPILER_TAG" 76 | fi 77 | 78 | COMPOSE_HTTP_TIMEOUT=240 docker-compose -p $PROJECT_NAME -f $DOCKER_COMPOSE_YAML $DOCKER_COMPOSE_PROFILE build 79 | } 80 | 81 | # 82 | # Main 83 | # 84 | 85 | DOCKER_COMPOSE_YAML="docker-compose.yaml" 86 | PROJECT_NAME="nginx-dapi" 87 | export NGINX_CERT="unused" 88 | export NGINX_KEY="unused" 89 | export PROFILE="basic" 90 | export NAP_COMPILER_TAG="unused" 91 | export DOCKER_COMPOSE_PROFILE="" 92 | 93 | while getopts 'hc:C:K:w' OPTION 94 | do 95 | case "$OPTION" in 96 | h) 97 | usage 98 | ;; 99 | c) 100 | ACTION=$OPTARG 101 | ;; 102 | w) 103 | NAP_ENABLED=true 104 | export DOCKER_COMPOSE_PROFILE="--profile nap" 105 | ;; 106 | C) 107 | export NGINX_CERT=$OPTARG 108 | ;; 109 | K) 110 | export NGINX_KEY=$OPTARG 111 | ;; 112 | esac 113 | done 114 | 115 | if [ -z "${ACTION}" ] || [[ ! "${ACTION}" == +(start|stop|build) ]] 116 | then 117 | usage 118 | fi 119 | 120 | if [ "${ACTION}" == "build" ] && [ "${NAP_ENABLED}" == "true" ] 121 | then 122 | if [ "${NGINX_CERT}" == "unused" ] || [ "${NGINX_KEY}" == "unused" ] 123 | then 124 | echo "NGINX certificate and key missing" 125 | exit 126 | fi 127 | fi 128 | 129 | case "$ACTION" in 130 | start) 131 | nginx_dapi_start 132 | ;; 133 | stop) 134 | nginx_dapi_stop 135 | ;; 136 | build) 137 | nginx_dapi_build 138 | ;; 139 | esac 140 | -------------------------------------------------------------------------------- /contrib/gitops-examples/jkws.json: -------------------------------------------------------------------------------- 1 | {"keys": [{ "k":"ZmFudGFzdGljand0", "kty":"oct", "kid":"0001" }]} -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.1/apigw.nginx.lab.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | 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 32 | O6C6PJA6ITkdA+LLliWy4eU= 33 | -----END CERTIFICATE----- 34 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.1/apigw.nginx.lab.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | 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 51 | abUSsTGHO/UEOSdj+I8g1bIFrBdg 52 | -----END PRIVATE KEY----- 53 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.1/client.cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFAjCCA+qgAwIBAgIUavuhXA9aKTRebfvcPESft20TAxswDQYJKoZIhvcNAQEL 3 | BQAwVjELMAkGA1UEBhMCSUUxDTALBgNVBAgMBENvcmsxDTALBgNVBAcMBENvcmsx 4 | ETAPBgNVBAoMCEFjbWUgTHRkMRYwFAYDVQQDDA10ZXN0LmFjbWQubGFuMB4XDTI0 5 | MDQxNTE3MDg1M1oXDTI1MDQxNTE3MDg1M1owWDELMAkGA1UEBhMCSUUxDTALBgNV 6 | BAgMBENvcmsxDTALBgNVBAcMBENvcmsxETAPBgNVBAoMCEFjbWUgTHRkMRgwFgYD 7 | VQQDDA9jbGllbnQuYWNtZS5sYWIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK 8 | AoICAQDTCi2v/+sO+u2SpQyePK3xgotrEICdbX2cx7LdrtClO6kLS3r2mjqWZmZD 9 | Qi//GHexXKsZzPTD527FLfTDpLHohu2WfyA+C/G7brqyMOGPgyUpB65cvLu8WPM8 10 | OkyqTWfkLdFqvjAFrU9s31RycOpPJPtpYhEiaAvQX9pFxcjS65BlqAB265bygpk6 11 | jlWQ955VS9ffSKSxiA4BAp30uwFnXEkLpdBzr5NAJyrjuxslrFTK8HloFd62wsAC 12 | F6+DffCaM/5hrIcFK0IQaxpiie2ZYJiQf5rLyWzTmq1XuBk2hHAX3oAF6moaruM8 13 | 9RXqBiZ6qVtaOAqD+JQTcibeszD6glhJ+F3EELBNYXDNaKljkAtqUapa+WdGURE8 14 | vos08M+/9IaY7PxkP5pzl8fi/Qi/DIoV/8tQIrtPHc2jI1RFFh/pix1lGirNTA+D 15 | m9TD2JOHSSufvDdFuub1p2qyMnMwqE6IG8jfLH6LcqDaRng/yZUQ0jkMKHV+wX0z 16 | dgTl05UZ6m0ZE5Ge+QQhngcATzgkIjwZRhwRK8Lu6kpoegoGLRHdMSjqEt6CVsnA 17 | aKgHSm2Q8OLKYIvXU7Ti0OC6nNuN4D9JvLFAwO1EESkBQqPy8Fo/3ESYYMEk2zG4 18 | sr4QrxClncjpmC+vDftrnGNyIRov+Ny/swaRvG/rmyfxDaWM/wIDAQABo4HFMIHC 19 | MAkGA1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgWgMDMGCWCGSAGG+EIBDQQmFiRP 20 | cGVuU1NMIEdlbmVyYXRlZCBDbGllbnQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFFBb 21 | vimd61zLKvP4SdYDTVnwXtUpMB8GA1UdIwQYMBaAFKcoFDzLVw5Apb30yQ34snLe 22 | GCQVMA4GA1UdDwEB/wQEAwIF4DAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH 23 | AwQwDQYJKoZIhvcNAQELBQADggEBAJh4roddEFzbpZNdInsRgnmegYR1IisQLQSB 24 | rcrtFqVkKotlsODQpE18HF0lmP8XOHSHjc+XQQybQMwUbgdMnxAdMVhaZ1ziXIgi 25 | bPx08F4aty0IIcXr9ZEVvSwZayDAdq+ok9DjhF40aNbBaAMpv54B/e79CLIfzDJ8 26 | sYil7+OZmiNQ2meCkyPXuwawxSyTg5XVKt8TKJARyi1IydGZFQ12FXRGLMAJ7Zbx 27 | G9OwVok11zzV6DPdqneNDGpPENVgefV24eMIUu+c8gI8XMMF1OUUdw2iDBe8CMSA 28 | ishvh1VaVO4/zs9fkgKWaWz3pAjk7zdmgZRzWEEGGBLzBhBNEA8= 29 | -----END CERTIFICATE----- 30 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.1/client.key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | 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 51 | B/KL9Bv3fuI/BRKyOVeU5Vvy35/yAqU= 52 | -----END PRIVATE KEY----- 53 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.1/nap-policy-xss-allowed.json: -------------------------------------------------------------------------------- 1 | { 2 | "policy": { 3 | "name": "prod-policy", 4 | "template": { 5 | "name": "POLICY_TEMPLATE_NGINX_BASE" 6 | }, 7 | "applicationLanguage": "utf-8", 8 | "enforcementMode": "blocking", 9 | "signature-sets": [ 10 | { 11 | "name": "All Signatures", 12 | "block": true, 13 | "alarm": true 14 | } 15 | ], 16 | "signatures": [ 17 | { 18 | "signatureId": 200001834, 19 | "enabled": false 20 | }, 21 | { 22 | "signatureId": 200001475, 23 | "enabled": false 24 | }, 25 | { 26 | "signatureId": 200000098, 27 | "enabled": false 28 | }, 29 | { 30 | "signatureId": 200001088, 31 | "enabled": false 32 | }, 33 | { 34 | "signatureId": 200101609, 35 | "enabled": false 36 | } 37 | ] 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.1/nap-policy-xss-blocked-bot-allowed.json: -------------------------------------------------------------------------------- 1 | { 2 | "policy": { 3 | "name": "prod-policy", 4 | "template": { 5 | "name": "POLICY_TEMPLATE_NGINX_BASE" 6 | }, 7 | "applicationLanguage": "utf-8", 8 | "enforcementMode": "blocking", 9 | "signature-sets": [ 10 | { 11 | "name": "All Signatures", 12 | "block": true, 13 | "alarm": true 14 | } 15 | ], 16 | "signatures": [ 17 | { 18 | "signatureId": 200001834, 19 | "enabled": false 20 | } 21 | ], 22 | "bot-defense": { 23 | "settings": { 24 | "isEnabled": false 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.1/nap-policy-xss-blocked.json: -------------------------------------------------------------------------------- 1 | { 2 | "policy": { 3 | "name": "prod-policy", 4 | "template": { 5 | "name": "POLICY_TEMPLATE_NGINX_BASE" 6 | }, 7 | "applicationLanguage": "utf-8", 8 | "enforcementMode": "blocking", 9 | "signature-sets": [ 10 | { 11 | "name": "All Signatures", 12 | "block": true, 13 | "alarm": true 14 | } 15 | ], 16 | "signatures": [ 17 | { 18 | "signatureId": 200001834, 19 | "enabled": false 20 | } 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.1/testcert.chain: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDRjCCAi6gAwIBAgIUccT8pYiNoy0AQnkrUZrVCXhnm70wDQYJKoZIhvcNAQEL 3 | BQAwSDEiMCAGCSqGSIb3DQEJARYTbXlAZW1haWxhZGRyZXNzLmNvbTEiMCAGA1UE 4 | AwwZd3d3Lm9ubGluZS1ib3V0aXF1ZS5sb2NhbDAeFw0yMzAyMTQxNTA2NDRaFw0z 5 | MzAyMTExNTA2NDRaMEgxIjAgBgkqhkiG9w0BCQEWE215QGVtYWlsYWRkcmVzcy5j 6 | b20xIjAgBgNVBAMMGXd3dy5vbmxpbmUtYm91dGlxdWUubG9jYWwwggEiMA0GCSqG 7 | SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDasqlTnb5WlPHkjiLnjFX27QBm2BgDcA+x 8 | Y37biaMp+I1bTUd57hDM1X+kBeLZc98xe7hc/HaO5+3ywanBRTMVaBUCKBduET/o 9 | N+DdBAj8c64vov9a064sjXwYSeeh8lPqX52R5DYWxpHh2tvSg+a/3wwmIPoScXIu 10 | R1Wq7RY//dsshIHQkxVa9VAPYjLnusQjH9zOzJGZOxQ/OlCdaUrShbraKg6oVHK1 11 | +2h3M2S7RFjXFr8mbpxSgez1w9oN1YI+RM/kLPgI+Kq+YN6MfMhYvQei537569N9 12 | wJ9bl/i34EbM5gDf8BxhJJbo+ypEC9h0H8FmSXbqXcb8gt/dQMfZAgMBAAGjKDAm 13 | MCQGA1UdEQQdMBuCGXd3dy5vbmxpbmUtYm91dGlxdWUubG9jYWwwDQYJKoZIhvcN 14 | AQELBQADggEBAKLCxBakmK43tbf+2pwgbRLYuOvz4A8GCh/EK2F1OKeuw0oIat7M 15 | Nn5SxSgNFj45XswaRsR3/ObLovrYmXzZnV9IPNHIsB0/sBsyqEYMA55hJsb/8HEd 16 | +bWv2UJdcAimhbLMi1bpgSlSCNMn/CWkX09e3IjRrYkZxT50/ahOBBfBshoY+jwe 17 | sA1VDwZ4neXfrTUXJ4ixiTOfna2TpADLNxk6pncr6uiIpJSmLAq9jQwPBNlrpRN3 18 | TCyKKcadGdUPkALXm0+dMn1OHphy7ZQADMxPwxLySuoCK8kcslpGLg18zPXYQkoD 19 | C1KAguWu/VU4EBT39aC5/9askw+zV4XE9hw= 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.1/testcert.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDRjCCAi6gAwIBAgIUccT8pYiNoy0AQnkrUZrVCXhnm70wDQYJKoZIhvcNAQEL 3 | BQAwSDEiMCAGCSqGSIb3DQEJARYTbXlAZW1haWxhZGRyZXNzLmNvbTEiMCAGA1UE 4 | AwwZd3d3Lm9ubGluZS1ib3V0aXF1ZS5sb2NhbDAeFw0yMzAyMTQxNTA2NDRaFw0z 5 | MzAyMTExNTA2NDRaMEgxIjAgBgkqhkiG9w0BCQEWE215QGVtYWlsYWRkcmVzcy5j 6 | b20xIjAgBgNVBAMMGXd3dy5vbmxpbmUtYm91dGlxdWUubG9jYWwwggEiMA0GCSqG 7 | SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDasqlTnb5WlPHkjiLnjFX27QBm2BgDcA+x 8 | Y37biaMp+I1bTUd57hDM1X+kBeLZc98xe7hc/HaO5+3ywanBRTMVaBUCKBduET/o 9 | N+DdBAj8c64vov9a064sjXwYSeeh8lPqX52R5DYWxpHh2tvSg+a/3wwmIPoScXIu 10 | R1Wq7RY//dsshIHQkxVa9VAPYjLnusQjH9zOzJGZOxQ/OlCdaUrShbraKg6oVHK1 11 | +2h3M2S7RFjXFr8mbpxSgez1w9oN1YI+RM/kLPgI+Kq+YN6MfMhYvQei537569N9 12 | wJ9bl/i34EbM5gDf8BxhJJbo+ypEC9h0H8FmSXbqXcb8gt/dQMfZAgMBAAGjKDAm 13 | MCQGA1UdEQQdMBuCGXd3dy5vbmxpbmUtYm91dGlxdWUubG9jYWwwDQYJKoZIhvcN 14 | AQELBQADggEBAKLCxBakmK43tbf+2pwgbRLYuOvz4A8GCh/EK2F1OKeuw0oIat7M 15 | Nn5SxSgNFj45XswaRsR3/ObLovrYmXzZnV9IPNHIsB0/sBsyqEYMA55hJsb/8HEd 16 | +bWv2UJdcAimhbLMi1bpgSlSCNMn/CWkX09e3IjRrYkZxT50/ahOBBfBshoY+jwe 17 | sA1VDwZ4neXfrTUXJ4ixiTOfna2TpADLNxk6pncr6uiIpJSmLAq9jQwPBNlrpRN3 18 | TCyKKcadGdUPkALXm0+dMn1OHphy7ZQADMxPwxLySuoCK8kcslpGLg18zPXYQkoD 19 | C1KAguWu/VU4EBT39aC5/9askw+zV4XE9hw= 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.1/testcert.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDasqlTnb5WlPHk 3 | jiLnjFX27QBm2BgDcA+xY37biaMp+I1bTUd57hDM1X+kBeLZc98xe7hc/HaO5+3y 4 | wanBRTMVaBUCKBduET/oN+DdBAj8c64vov9a064sjXwYSeeh8lPqX52R5DYWxpHh 5 | 2tvSg+a/3wwmIPoScXIuR1Wq7RY//dsshIHQkxVa9VAPYjLnusQjH9zOzJGZOxQ/ 6 | OlCdaUrShbraKg6oVHK1+2h3M2S7RFjXFr8mbpxSgez1w9oN1YI+RM/kLPgI+Kq+ 7 | YN6MfMhYvQei537569N9wJ9bl/i34EbM5gDf8BxhJJbo+ypEC9h0H8FmSXbqXcb8 8 | gt/dQMfZAgMBAAECggEBAIcP85baQqSCE+mNBm1ts+FteOQK7LmiyW5J/hxjIktX 9 | XyVV0qCwr9twtwV7RR/6eYq7155FpIqZHdDgXZAoxmWgA+lzDRVCve8SI2MbjNks 10 | MBTnW0CinlyRfGQbsFvJpp2GM2/YOrdSJuIPIdce8rDodT5O+2HMgjGmiHepOCaH 11 | 4XS42Av9KDbcbo2rSfAhSulsXJetd9G7luD3dY3Lsp2TC6ihzwZOtGSHJjoY29uS 12 | D+MJvAq2MzZxRnyE6vP88NY45rZug1YS7EHs0v6NAnI6/Ew6M3sAjss+qhBL/k6j 13 | AMWAibn1oTgbN6ifXapXpynQOSU1IvEJqXNHA+YQMEkCgYEA/t7TihpRoJRcMzx6 14 | 4XtKMMDS/ixv7QUmOnJ1AO1Je3hjJK+2U1wARYLHoVdlZYTb9GRRlH6UHPL3lh2m 15 | ZWfDHRjKzQ+E4jlYFvQMAmAhbSqCAPtyFadQf7qLDKZAT/1WUj+Ynh0vjUUigqKj 16 | VsukDJkwqSt3jCk2ECtddcTicCcCgYEA26rLSaDx/+bDYVlJW9nXt8/N2ZYqtBev 17 | I+AV1qgVYjlskbcMch3apIVELiOEVfBaIGJDoq1N3e25cTvNNO/mA2rDSYLQuz7L 18 | bwlVs6ix02/tFd1R0N5nGKMhziue1l3BOjADHzf/UkOc4UIJGkmUQHrVxpby6FMY 19 | cT+HJ3+OB/8CgYAHtDqWuRbwkKt8zP415KEoehumnTdA5d/y8lTBE2seNVRh3oHX 20 | YTeM4lggc2DYQbzYVVP19iGKAnojaoAGHq3SKlau/iIZKHyWLQhT5g38m8VUPEWF 21 | jAot4jijyD63bEP4tn1pgh5W2dkiM8JWNE+gJd1Hr82sSe6dbIIlti7WDwKBgA3n 22 | PX6nhSmhPXSH5jC+FP05VdoTuxgy947ZvAgeE1xoLgr6/vqqERCgrrQM429dCxdJ 23 | oOZG+cq2JSqZkl9rX6+PrlSUxwlS7CVW/emlH7w2NVdQ7sC9kuDoUlduQ1tmC7jX 24 | GRt8u9hFF0TanSDgz1VVcPpky3MQ71cboj5JwH+ZAoGAAcDSlHuOu2xnbdnaTdE1 25 | MK0q/Yt3EOCGp0FRBkResPhhoV/TXadk0sJJbWFnleRFDkmgsw2QAwVhKQHCRWOu 26 | b4G8EnEXY/91IoRSevWtZTNf+/9+y5w4iOWI3rGJNpXCEgzN7Yc60z1sIsC/fu+Q 27 | YxXNiLIYUB4Pk4pDNRNLMZo= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.1/testcert2.chain: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDSTCCAjGgAwIBAgIUbzaZNPdYel80IQ81PCNfMllLnYgwDQYJKoZIhvcNAQEL 3 | BQAwSTEiMCAGCSqGSIb3DQEJARYTbXlAZW1haWxhZGRyZXNzLmNvbTEjMCEGA1UE 4 | Awwad3d3Mi5vbmxpbmUtYm91dGlxdWUubG9jYWwwHhcNMjMwMjE0MTUwNzMxWhcN 5 | MzMwMjExMTUwNzMxWjBJMSIwIAYJKoZIhvcNAQkBFhNteUBlbWFpbGFkZHJlc3Mu 6 | Y29tMSMwIQYDVQQDDBp3d3cyLm9ubGluZS1ib3V0aXF1ZS5sb2NhbDCCASIwDQYJ 7 | KoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2OHfrfxO6hhg4dGMi0Q4+iwuuNGv2J 8 | eh+t8g9A+dGB4zUkU0SEa2EFLjyAw2P7F1XAtiClHmS9nA0uTuj9nuw9Xk+wFUlm 9 | ahMkdkLBRNNsH3O1gTYUQSOK7xm8FOMBnOYQqJOHILXsXgM2z8QHpX//wl15aGXf 10 | 9vPm4CQUqqsEGNWDfpOQ8jfhrA4T8W1WuAXzJAQmZfhW1qMWxoj1iTCk+Q6nH/8a 11 | MWLWPjTes0bTSRXRTpuQCyeHCaqS8oPPshcd52/FXChnYbNAG1s9Q+35MrgDztL6 12 | dPkNiA9UaUY7pumNip93ZnsYwDmOPnDBPqfvy9Dk1zQuaAsJ1FXwRNsCAwEAAaMp 13 | MCcwJQYDVR0RBB4wHIIad3d3Mi5vbmxpbmUtYm91dGlxdWUubG9jYWwwDQYJKoZI 14 | hvcNAQELBQADggEBADT2SchC4VhWqCYRsw/3nqrVh0JQmD+/x9JjiNsY6fLnG6uW 15 | 8bs8/714qoghJff67H60B6NbrS3lpTZ3bmyotcGtwNNsY4QSFHRu/x4OyIrTfjKb 16 | VIdhRM2Atwc1s1YA6c+2JBquBDhniqABKG9u+j1aa2ElXSalCj+Kozm8ma0yduVw 17 | TX8zS6XZl57vSk/Qo/PZvbmbs8EMOwTUCLn6WQldAARCLughjd9LI9prNpBlYon6 18 | jmZ8oi59arK16cKe6i6tQ3QExT2kQsLlrK/jFw0xqrFnveKgUTeevViT4WZnqsCm 19 | awrPhrbDn0F7HmFSrgenrW8BIuJ2crBHy0230Lc= 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.1/testcert2.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDSTCCAjGgAwIBAgIUbzaZNPdYel80IQ81PCNfMllLnYgwDQYJKoZIhvcNAQEL 3 | BQAwSTEiMCAGCSqGSIb3DQEJARYTbXlAZW1haWxhZGRyZXNzLmNvbTEjMCEGA1UE 4 | Awwad3d3Mi5vbmxpbmUtYm91dGlxdWUubG9jYWwwHhcNMjMwMjE0MTUwNzMxWhcN 5 | MzMwMjExMTUwNzMxWjBJMSIwIAYJKoZIhvcNAQkBFhNteUBlbWFpbGFkZHJlc3Mu 6 | Y29tMSMwIQYDVQQDDBp3d3cyLm9ubGluZS1ib3V0aXF1ZS5sb2NhbDCCASIwDQYJ 7 | KoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2OHfrfxO6hhg4dGMi0Q4+iwuuNGv2J 8 | eh+t8g9A+dGB4zUkU0SEa2EFLjyAw2P7F1XAtiClHmS9nA0uTuj9nuw9Xk+wFUlm 9 | ahMkdkLBRNNsH3O1gTYUQSOK7xm8FOMBnOYQqJOHILXsXgM2z8QHpX//wl15aGXf 10 | 9vPm4CQUqqsEGNWDfpOQ8jfhrA4T8W1WuAXzJAQmZfhW1qMWxoj1iTCk+Q6nH/8a 11 | MWLWPjTes0bTSRXRTpuQCyeHCaqS8oPPshcd52/FXChnYbNAG1s9Q+35MrgDztL6 12 | dPkNiA9UaUY7pumNip93ZnsYwDmOPnDBPqfvy9Dk1zQuaAsJ1FXwRNsCAwEAAaMp 13 | MCcwJQYDVR0RBB4wHIIad3d3Mi5vbmxpbmUtYm91dGlxdWUubG9jYWwwDQYJKoZI 14 | hvcNAQELBQADggEBADT2SchC4VhWqCYRsw/3nqrVh0JQmD+/x9JjiNsY6fLnG6uW 15 | 8bs8/714qoghJff67H60B6NbrS3lpTZ3bmyotcGtwNNsY4QSFHRu/x4OyIrTfjKb 16 | VIdhRM2Atwc1s1YA6c+2JBquBDhniqABKG9u+j1aa2ElXSalCj+Kozm8ma0yduVw 17 | TX8zS6XZl57vSk/Qo/PZvbmbs8EMOwTUCLn6WQldAARCLughjd9LI9prNpBlYon6 18 | jmZ8oi59arK16cKe6i6tQ3QExT2kQsLlrK/jFw0xqrFnveKgUTeevViT4WZnqsCm 19 | awrPhrbDn0F7HmFSrgenrW8BIuJ2crBHy0230Lc= 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.1/testcert2.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDdjh3638TuoYYO 3 | HRjItEOPosLrjRr9iXofrfIPQPnRgeM1JFNEhGthBS48gMNj+xdVwLYgpR5kvZwN 4 | Lk7o/Z7sPV5PsBVJZmoTJHZCwUTTbB9ztYE2FEEjiu8ZvBTjAZzmEKiThyC17F4D 5 | Ns/EB6V//8JdeWhl3/bz5uAkFKqrBBjVg36TkPI34awOE/FtVrgF8yQEJmX4Vtaj 6 | FsaI9YkwpPkOpx//GjFi1j403rNG00kV0U6bkAsnhwmqkvKDz7IXHedvxVwoZ2Gz 7 | QBtbPUPt+TK4A87S+nT5DYgPVGlGO6bpjYqfd2Z7GMA5jj5wwT6n78vQ5Nc0LmgL 8 | CdRV8ETbAgMBAAECggEBAJkAy010eWC+5YAbsgDxFHM+WNQo90m+RjtYegD0w1Ff 9 | HNSXSHXZ6PnwhPS9i7IhNgU/d8dloG67zuf/YflfJQBKhTYNCTZOZtTfalhBdlF3 10 | quTSpO/+3tk32lVwYRBADeWH/ZMcT4ezO12G3can7TBPJSA+ds1b9QSNHZ9tMku0 11 | 2J2pzT8C8V0vHn49oKO9D4Q+QwRvisT6FKNaOW/xKZjtUIvyjVvjENnBW7MQ5y5z 12 | IHsUNkwGgZ2V2IbDouM4+A42J9iDsseM2euSsaDfum3vj9MPTqXE8zUUdX+/miMq 13 | RJTXLxDdkPaCbQftQ7y/cIAFLDZS8Fvvsa5pX69jl1ECgYEA8sQ6S7kcyYgBLX4T 14 | KVYPg1sFTgCofW5nTgCND4kiVvIDz/uk9vsfuMj7FMS3fcCfZorPdYEKa+Zwi4wZ 15 | NMCSArtezbwFBeaOiZTpjh2k8CBrtumdcU/EfzQOvrVcSzVc27ditwRAmONeBXVw 16 | GSvqSfjQKLDh/4Y191qOmgyIBDMCgYEA6aHjQr43XM811VQhTPBtLlBccD8hCS23 17 | NcujPMa85Vz+RES3OqHt2nH9NGuYrexGbrSt3ckjxnO+TdsS4f94bKhquXvv7AkX 18 | 7qr8KZEwHncyjcL3uTChbjWr2xJR4lSnS5PAbnWfyR48HXkHO9IVPe/IcYnvuGDN 19 | AeMJkCgp1LkCgYEArvD/PXAxMX1js9/FeSU+Wp8t7G8G/BSiNxColkhxSYxveOJT 20 | l3OSAXw7i1TTEbjMZX2kUH3j/6t48ObNhzk6PuO9Rq62Q/FISBbaU4JDSJNka9Rf 21 | k7cy16Ow+HcDAmN6/g5iAZb74fD+4Rom5MzDsfiuMJR+179khlJortRW9AcCgYAD 22 | 4AKD9eG3MVykOCwBOa+l6AFQf0uN+msigkkn1egGKd+xxC4B0/O8/s0DVJGIuPWG 23 | GosTtaVZQkwywGJ0yyb1Lmnuv6aAFLqH4+Ag1F6m8rUs8sHnGW5kBJHgJVKkXWEU 24 | +NNlQaAv1seKeZpsHJTrnRGHCJGoTjq4QErFUFU5SQKBgEYMGdnPP4ZDAeezPCML 25 | 42RVHOAG9IsMl4mV7+fwcEHcmuvb8nNgKNfayjG/NbiQWtT4v7iQH4GHYzUobaqr 26 | 3xnQlec3jBrLEsWR8ItRWKxKO2GGLlbmQ99Kn3UGh+6FtXbxwB0hhkFfKXJzM10N 27 | Y9ruUdyYpjGO/j9ROjoBepUH 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.2/apigw.nginx.lab.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | 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 32 | O6C6PJA6ITkdA+LLliWy4eU= 33 | -----END CERTIFICATE----- 34 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.2/apigw.nginx.lab.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | 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 51 | abUSsTGHO/UEOSdj+I8g1bIFrBdg 52 | -----END PRIVATE KEY----- 53 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.2/client.cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFAjCCA+qgAwIBAgIUavuhXA9aKTRebfvcPESft20TAxswDQYJKoZIhvcNAQEL 3 | BQAwVjELMAkGA1UEBhMCSUUxDTALBgNVBAgMBENvcmsxDTALBgNVBAcMBENvcmsx 4 | ETAPBgNVBAoMCEFjbWUgTHRkMRYwFAYDVQQDDA10ZXN0LmFjbWQubGFuMB4XDTI0 5 | MDQxNTE3MDg1M1oXDTI1MDQxNTE3MDg1M1owWDELMAkGA1UEBhMCSUUxDTALBgNV 6 | BAgMBENvcmsxDTALBgNVBAcMBENvcmsxETAPBgNVBAoMCEFjbWUgTHRkMRgwFgYD 7 | VQQDDA9jbGllbnQuYWNtZS5sYWIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK 8 | AoICAQDTCi2v/+sO+u2SpQyePK3xgotrEICdbX2cx7LdrtClO6kLS3r2mjqWZmZD 9 | Qi//GHexXKsZzPTD527FLfTDpLHohu2WfyA+C/G7brqyMOGPgyUpB65cvLu8WPM8 10 | OkyqTWfkLdFqvjAFrU9s31RycOpPJPtpYhEiaAvQX9pFxcjS65BlqAB265bygpk6 11 | jlWQ955VS9ffSKSxiA4BAp30uwFnXEkLpdBzr5NAJyrjuxslrFTK8HloFd62wsAC 12 | F6+DffCaM/5hrIcFK0IQaxpiie2ZYJiQf5rLyWzTmq1XuBk2hHAX3oAF6moaruM8 13 | 9RXqBiZ6qVtaOAqD+JQTcibeszD6glhJ+F3EELBNYXDNaKljkAtqUapa+WdGURE8 14 | vos08M+/9IaY7PxkP5pzl8fi/Qi/DIoV/8tQIrtPHc2jI1RFFh/pix1lGirNTA+D 15 | m9TD2JOHSSufvDdFuub1p2qyMnMwqE6IG8jfLH6LcqDaRng/yZUQ0jkMKHV+wX0z 16 | dgTl05UZ6m0ZE5Ge+QQhngcATzgkIjwZRhwRK8Lu6kpoegoGLRHdMSjqEt6CVsnA 17 | aKgHSm2Q8OLKYIvXU7Ti0OC6nNuN4D9JvLFAwO1EESkBQqPy8Fo/3ESYYMEk2zG4 18 | sr4QrxClncjpmC+vDftrnGNyIRov+Ny/swaRvG/rmyfxDaWM/wIDAQABo4HFMIHC 19 | MAkGA1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgWgMDMGCWCGSAGG+EIBDQQmFiRP 20 | cGVuU1NMIEdlbmVyYXRlZCBDbGllbnQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFFBb 21 | vimd61zLKvP4SdYDTVnwXtUpMB8GA1UdIwQYMBaAFKcoFDzLVw5Apb30yQ34snLe 22 | GCQVMA4GA1UdDwEB/wQEAwIF4DAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH 23 | AwQwDQYJKoZIhvcNAQELBQADggEBAJh4roddEFzbpZNdInsRgnmegYR1IisQLQSB 24 | rcrtFqVkKotlsODQpE18HF0lmP8XOHSHjc+XQQybQMwUbgdMnxAdMVhaZ1ziXIgi 25 | bPx08F4aty0IIcXr9ZEVvSwZayDAdq+ok9DjhF40aNbBaAMpv54B/e79CLIfzDJ8 26 | sYil7+OZmiNQ2meCkyPXuwawxSyTg5XVKt8TKJARyi1IydGZFQ12FXRGLMAJ7Zbx 27 | G9OwVok11zzV6DPdqneNDGpPENVgefV24eMIUu+c8gI8XMMF1OUUdw2iDBe8CMSA 28 | ishvh1VaVO4/zs9fkgKWaWz3pAjk7zdmgZRzWEEGGBLzBhBNEA8= 29 | -----END CERTIFICATE----- 30 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.2/client.key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | 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 51 | B/KL9Bv3fuI/BRKyOVeU5Vvy35/yAqU= 52 | -----END PRIVATE KEY----- 53 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.2/nap-policy-xss-allowed.json: -------------------------------------------------------------------------------- 1 | { 2 | "policy": { 3 | "name": "prod-policy", 4 | "template": { 5 | "name": "POLICY_TEMPLATE_NGINX_BASE" 6 | }, 7 | "applicationLanguage": "utf-8", 8 | "enforcementMode": "blocking", 9 | "signature-sets": [ 10 | { 11 | "name": "All Signatures", 12 | "block": true, 13 | "alarm": true 14 | } 15 | ], 16 | "signatures": [ 17 | { 18 | "signatureId": 200001834, 19 | "enabled": false 20 | }, 21 | { 22 | "signatureId": 200001475, 23 | "enabled": false 24 | }, 25 | { 26 | "signatureId": 200000098, 27 | "enabled": false 28 | }, 29 | { 30 | "signatureId": 200001088, 31 | "enabled": false 32 | }, 33 | { 34 | "signatureId": 200101609, 35 | "enabled": false 36 | } 37 | ] 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.2/nap-policy-xss-blocked-bot-allowed.json: -------------------------------------------------------------------------------- 1 | { 2 | "policy": { 3 | "name": "prod-policy", 4 | "template": { 5 | "name": "POLICY_TEMPLATE_NGINX_BASE" 6 | }, 7 | "applicationLanguage": "utf-8", 8 | "enforcementMode": "blocking", 9 | "signature-sets": [ 10 | { 11 | "name": "All Signatures", 12 | "block": true, 13 | "alarm": true 14 | } 15 | ], 16 | "signatures": [ 17 | { 18 | "signatureId": 200001834, 19 | "enabled": false 20 | } 21 | ], 22 | "bot-defense": { 23 | "settings": { 24 | "isEnabled": false 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.2/nap-policy-xss-blocked.json: -------------------------------------------------------------------------------- 1 | { 2 | "policy": { 3 | "name": "prod-policy", 4 | "template": { 5 | "name": "POLICY_TEMPLATE_NGINX_BASE" 6 | }, 7 | "applicationLanguage": "utf-8", 8 | "enforcementMode": "blocking", 9 | "signature-sets": [ 10 | { 11 | "name": "All Signatures", 12 | "block": true, 13 | "alarm": true 14 | } 15 | ], 16 | "signatures": [ 17 | { 18 | "signatureId": 200001834, 19 | "enabled": false 20 | } 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.2/testcert.chain: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDRjCCAi6gAwIBAgIUccT8pYiNoy0AQnkrUZrVCXhnm70wDQYJKoZIhvcNAQEL 3 | BQAwSDEiMCAGCSqGSIb3DQEJARYTbXlAZW1haWxhZGRyZXNzLmNvbTEiMCAGA1UE 4 | AwwZd3d3Lm9ubGluZS1ib3V0aXF1ZS5sb2NhbDAeFw0yMzAyMTQxNTA2NDRaFw0z 5 | MzAyMTExNTA2NDRaMEgxIjAgBgkqhkiG9w0BCQEWE215QGVtYWlsYWRkcmVzcy5j 6 | b20xIjAgBgNVBAMMGXd3dy5vbmxpbmUtYm91dGlxdWUubG9jYWwwggEiMA0GCSqG 7 | SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDasqlTnb5WlPHkjiLnjFX27QBm2BgDcA+x 8 | Y37biaMp+I1bTUd57hDM1X+kBeLZc98xe7hc/HaO5+3ywanBRTMVaBUCKBduET/o 9 | N+DdBAj8c64vov9a064sjXwYSeeh8lPqX52R5DYWxpHh2tvSg+a/3wwmIPoScXIu 10 | R1Wq7RY//dsshIHQkxVa9VAPYjLnusQjH9zOzJGZOxQ/OlCdaUrShbraKg6oVHK1 11 | +2h3M2S7RFjXFr8mbpxSgez1w9oN1YI+RM/kLPgI+Kq+YN6MfMhYvQei537569N9 12 | wJ9bl/i34EbM5gDf8BxhJJbo+ypEC9h0H8FmSXbqXcb8gt/dQMfZAgMBAAGjKDAm 13 | MCQGA1UdEQQdMBuCGXd3dy5vbmxpbmUtYm91dGlxdWUubG9jYWwwDQYJKoZIhvcN 14 | AQELBQADggEBAKLCxBakmK43tbf+2pwgbRLYuOvz4A8GCh/EK2F1OKeuw0oIat7M 15 | Nn5SxSgNFj45XswaRsR3/ObLovrYmXzZnV9IPNHIsB0/sBsyqEYMA55hJsb/8HEd 16 | +bWv2UJdcAimhbLMi1bpgSlSCNMn/CWkX09e3IjRrYkZxT50/ahOBBfBshoY+jwe 17 | sA1VDwZ4neXfrTUXJ4ixiTOfna2TpADLNxk6pncr6uiIpJSmLAq9jQwPBNlrpRN3 18 | TCyKKcadGdUPkALXm0+dMn1OHphy7ZQADMxPwxLySuoCK8kcslpGLg18zPXYQkoD 19 | C1KAguWu/VU4EBT39aC5/9askw+zV4XE9hw= 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.2/testcert.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDRjCCAi6gAwIBAgIUccT8pYiNoy0AQnkrUZrVCXhnm70wDQYJKoZIhvcNAQEL 3 | BQAwSDEiMCAGCSqGSIb3DQEJARYTbXlAZW1haWxhZGRyZXNzLmNvbTEiMCAGA1UE 4 | AwwZd3d3Lm9ubGluZS1ib3V0aXF1ZS5sb2NhbDAeFw0yMzAyMTQxNTA2NDRaFw0z 5 | MzAyMTExNTA2NDRaMEgxIjAgBgkqhkiG9w0BCQEWE215QGVtYWlsYWRkcmVzcy5j 6 | b20xIjAgBgNVBAMMGXd3dy5vbmxpbmUtYm91dGlxdWUubG9jYWwwggEiMA0GCSqG 7 | SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDasqlTnb5WlPHkjiLnjFX27QBm2BgDcA+x 8 | Y37biaMp+I1bTUd57hDM1X+kBeLZc98xe7hc/HaO5+3ywanBRTMVaBUCKBduET/o 9 | N+DdBAj8c64vov9a064sjXwYSeeh8lPqX52R5DYWxpHh2tvSg+a/3wwmIPoScXIu 10 | R1Wq7RY//dsshIHQkxVa9VAPYjLnusQjH9zOzJGZOxQ/OlCdaUrShbraKg6oVHK1 11 | +2h3M2S7RFjXFr8mbpxSgez1w9oN1YI+RM/kLPgI+Kq+YN6MfMhYvQei537569N9 12 | wJ9bl/i34EbM5gDf8BxhJJbo+ypEC9h0H8FmSXbqXcb8gt/dQMfZAgMBAAGjKDAm 13 | MCQGA1UdEQQdMBuCGXd3dy5vbmxpbmUtYm91dGlxdWUubG9jYWwwDQYJKoZIhvcN 14 | AQELBQADggEBAKLCxBakmK43tbf+2pwgbRLYuOvz4A8GCh/EK2F1OKeuw0oIat7M 15 | Nn5SxSgNFj45XswaRsR3/ObLovrYmXzZnV9IPNHIsB0/sBsyqEYMA55hJsb/8HEd 16 | +bWv2UJdcAimhbLMi1bpgSlSCNMn/CWkX09e3IjRrYkZxT50/ahOBBfBshoY+jwe 17 | sA1VDwZ4neXfrTUXJ4ixiTOfna2TpADLNxk6pncr6uiIpJSmLAq9jQwPBNlrpRN3 18 | TCyKKcadGdUPkALXm0+dMn1OHphy7ZQADMxPwxLySuoCK8kcslpGLg18zPXYQkoD 19 | C1KAguWu/VU4EBT39aC5/9askw+zV4XE9hw= 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.2/testcert.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDasqlTnb5WlPHk 3 | jiLnjFX27QBm2BgDcA+xY37biaMp+I1bTUd57hDM1X+kBeLZc98xe7hc/HaO5+3y 4 | wanBRTMVaBUCKBduET/oN+DdBAj8c64vov9a064sjXwYSeeh8lPqX52R5DYWxpHh 5 | 2tvSg+a/3wwmIPoScXIuR1Wq7RY//dsshIHQkxVa9VAPYjLnusQjH9zOzJGZOxQ/ 6 | OlCdaUrShbraKg6oVHK1+2h3M2S7RFjXFr8mbpxSgez1w9oN1YI+RM/kLPgI+Kq+ 7 | YN6MfMhYvQei537569N9wJ9bl/i34EbM5gDf8BxhJJbo+ypEC9h0H8FmSXbqXcb8 8 | gt/dQMfZAgMBAAECggEBAIcP85baQqSCE+mNBm1ts+FteOQK7LmiyW5J/hxjIktX 9 | XyVV0qCwr9twtwV7RR/6eYq7155FpIqZHdDgXZAoxmWgA+lzDRVCve8SI2MbjNks 10 | MBTnW0CinlyRfGQbsFvJpp2GM2/YOrdSJuIPIdce8rDodT5O+2HMgjGmiHepOCaH 11 | 4XS42Av9KDbcbo2rSfAhSulsXJetd9G7luD3dY3Lsp2TC6ihzwZOtGSHJjoY29uS 12 | D+MJvAq2MzZxRnyE6vP88NY45rZug1YS7EHs0v6NAnI6/Ew6M3sAjss+qhBL/k6j 13 | AMWAibn1oTgbN6ifXapXpynQOSU1IvEJqXNHA+YQMEkCgYEA/t7TihpRoJRcMzx6 14 | 4XtKMMDS/ixv7QUmOnJ1AO1Je3hjJK+2U1wARYLHoVdlZYTb9GRRlH6UHPL3lh2m 15 | ZWfDHRjKzQ+E4jlYFvQMAmAhbSqCAPtyFadQf7qLDKZAT/1WUj+Ynh0vjUUigqKj 16 | VsukDJkwqSt3jCk2ECtddcTicCcCgYEA26rLSaDx/+bDYVlJW9nXt8/N2ZYqtBev 17 | I+AV1qgVYjlskbcMch3apIVELiOEVfBaIGJDoq1N3e25cTvNNO/mA2rDSYLQuz7L 18 | bwlVs6ix02/tFd1R0N5nGKMhziue1l3BOjADHzf/UkOc4UIJGkmUQHrVxpby6FMY 19 | cT+HJ3+OB/8CgYAHtDqWuRbwkKt8zP415KEoehumnTdA5d/y8lTBE2seNVRh3oHX 20 | YTeM4lggc2DYQbzYVVP19iGKAnojaoAGHq3SKlau/iIZKHyWLQhT5g38m8VUPEWF 21 | jAot4jijyD63bEP4tn1pgh5W2dkiM8JWNE+gJd1Hr82sSe6dbIIlti7WDwKBgA3n 22 | PX6nhSmhPXSH5jC+FP05VdoTuxgy947ZvAgeE1xoLgr6/vqqERCgrrQM429dCxdJ 23 | oOZG+cq2JSqZkl9rX6+PrlSUxwlS7CVW/emlH7w2NVdQ7sC9kuDoUlduQ1tmC7jX 24 | GRt8u9hFF0TanSDgz1VVcPpky3MQ71cboj5JwH+ZAoGAAcDSlHuOu2xnbdnaTdE1 25 | MK0q/Yt3EOCGp0FRBkResPhhoV/TXadk0sJJbWFnleRFDkmgsw2QAwVhKQHCRWOu 26 | b4G8EnEXY/91IoRSevWtZTNf+/9+y5w4iOWI3rGJNpXCEgzN7Yc60z1sIsC/fu+Q 27 | YxXNiLIYUB4Pk4pDNRNLMZo= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.2/testcert2.chain: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDSTCCAjGgAwIBAgIUbzaZNPdYel80IQ81PCNfMllLnYgwDQYJKoZIhvcNAQEL 3 | BQAwSTEiMCAGCSqGSIb3DQEJARYTbXlAZW1haWxhZGRyZXNzLmNvbTEjMCEGA1UE 4 | Awwad3d3Mi5vbmxpbmUtYm91dGlxdWUubG9jYWwwHhcNMjMwMjE0MTUwNzMxWhcN 5 | MzMwMjExMTUwNzMxWjBJMSIwIAYJKoZIhvcNAQkBFhNteUBlbWFpbGFkZHJlc3Mu 6 | Y29tMSMwIQYDVQQDDBp3d3cyLm9ubGluZS1ib3V0aXF1ZS5sb2NhbDCCASIwDQYJ 7 | KoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2OHfrfxO6hhg4dGMi0Q4+iwuuNGv2J 8 | eh+t8g9A+dGB4zUkU0SEa2EFLjyAw2P7F1XAtiClHmS9nA0uTuj9nuw9Xk+wFUlm 9 | ahMkdkLBRNNsH3O1gTYUQSOK7xm8FOMBnOYQqJOHILXsXgM2z8QHpX//wl15aGXf 10 | 9vPm4CQUqqsEGNWDfpOQ8jfhrA4T8W1WuAXzJAQmZfhW1qMWxoj1iTCk+Q6nH/8a 11 | MWLWPjTes0bTSRXRTpuQCyeHCaqS8oPPshcd52/FXChnYbNAG1s9Q+35MrgDztL6 12 | dPkNiA9UaUY7pumNip93ZnsYwDmOPnDBPqfvy9Dk1zQuaAsJ1FXwRNsCAwEAAaMp 13 | MCcwJQYDVR0RBB4wHIIad3d3Mi5vbmxpbmUtYm91dGlxdWUubG9jYWwwDQYJKoZI 14 | hvcNAQELBQADggEBADT2SchC4VhWqCYRsw/3nqrVh0JQmD+/x9JjiNsY6fLnG6uW 15 | 8bs8/714qoghJff67H60B6NbrS3lpTZ3bmyotcGtwNNsY4QSFHRu/x4OyIrTfjKb 16 | VIdhRM2Atwc1s1YA6c+2JBquBDhniqABKG9u+j1aa2ElXSalCj+Kozm8ma0yduVw 17 | TX8zS6XZl57vSk/Qo/PZvbmbs8EMOwTUCLn6WQldAARCLughjd9LI9prNpBlYon6 18 | jmZ8oi59arK16cKe6i6tQ3QExT2kQsLlrK/jFw0xqrFnveKgUTeevViT4WZnqsCm 19 | awrPhrbDn0F7HmFSrgenrW8BIuJ2crBHy0230Lc= 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.2/testcert2.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDSTCCAjGgAwIBAgIUbzaZNPdYel80IQ81PCNfMllLnYgwDQYJKoZIhvcNAQEL 3 | BQAwSTEiMCAGCSqGSIb3DQEJARYTbXlAZW1haWxhZGRyZXNzLmNvbTEjMCEGA1UE 4 | Awwad3d3Mi5vbmxpbmUtYm91dGlxdWUubG9jYWwwHhcNMjMwMjE0MTUwNzMxWhcN 5 | MzMwMjExMTUwNzMxWjBJMSIwIAYJKoZIhvcNAQkBFhNteUBlbWFpbGFkZHJlc3Mu 6 | Y29tMSMwIQYDVQQDDBp3d3cyLm9ubGluZS1ib3V0aXF1ZS5sb2NhbDCCASIwDQYJ 7 | KoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2OHfrfxO6hhg4dGMi0Q4+iwuuNGv2J 8 | eh+t8g9A+dGB4zUkU0SEa2EFLjyAw2P7F1XAtiClHmS9nA0uTuj9nuw9Xk+wFUlm 9 | ahMkdkLBRNNsH3O1gTYUQSOK7xm8FOMBnOYQqJOHILXsXgM2z8QHpX//wl15aGXf 10 | 9vPm4CQUqqsEGNWDfpOQ8jfhrA4T8W1WuAXzJAQmZfhW1qMWxoj1iTCk+Q6nH/8a 11 | MWLWPjTes0bTSRXRTpuQCyeHCaqS8oPPshcd52/FXChnYbNAG1s9Q+35MrgDztL6 12 | dPkNiA9UaUY7pumNip93ZnsYwDmOPnDBPqfvy9Dk1zQuaAsJ1FXwRNsCAwEAAaMp 13 | MCcwJQYDVR0RBB4wHIIad3d3Mi5vbmxpbmUtYm91dGlxdWUubG9jYWwwDQYJKoZI 14 | hvcNAQELBQADggEBADT2SchC4VhWqCYRsw/3nqrVh0JQmD+/x9JjiNsY6fLnG6uW 15 | 8bs8/714qoghJff67H60B6NbrS3lpTZ3bmyotcGtwNNsY4QSFHRu/x4OyIrTfjKb 16 | VIdhRM2Atwc1s1YA6c+2JBquBDhniqABKG9u+j1aa2ElXSalCj+Kozm8ma0yduVw 17 | TX8zS6XZl57vSk/Qo/PZvbmbs8EMOwTUCLn6WQldAARCLughjd9LI9prNpBlYon6 18 | jmZ8oi59arK16cKe6i6tQ3QExT2kQsLlrK/jFw0xqrFnveKgUTeevViT4WZnqsCm 19 | awrPhrbDn0F7HmFSrgenrW8BIuJ2crBHy0230Lc= 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.2/testcert2.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDdjh3638TuoYYO 3 | HRjItEOPosLrjRr9iXofrfIPQPnRgeM1JFNEhGthBS48gMNj+xdVwLYgpR5kvZwN 4 | Lk7o/Z7sPV5PsBVJZmoTJHZCwUTTbB9ztYE2FEEjiu8ZvBTjAZzmEKiThyC17F4D 5 | Ns/EB6V//8JdeWhl3/bz5uAkFKqrBBjVg36TkPI34awOE/FtVrgF8yQEJmX4Vtaj 6 | FsaI9YkwpPkOpx//GjFi1j403rNG00kV0U6bkAsnhwmqkvKDz7IXHedvxVwoZ2Gz 7 | QBtbPUPt+TK4A87S+nT5DYgPVGlGO6bpjYqfd2Z7GMA5jj5wwT6n78vQ5Nc0LmgL 8 | CdRV8ETbAgMBAAECggEBAJkAy010eWC+5YAbsgDxFHM+WNQo90m+RjtYegD0w1Ff 9 | HNSXSHXZ6PnwhPS9i7IhNgU/d8dloG67zuf/YflfJQBKhTYNCTZOZtTfalhBdlF3 10 | quTSpO/+3tk32lVwYRBADeWH/ZMcT4ezO12G3can7TBPJSA+ds1b9QSNHZ9tMku0 11 | 2J2pzT8C8V0vHn49oKO9D4Q+QwRvisT6FKNaOW/xKZjtUIvyjVvjENnBW7MQ5y5z 12 | IHsUNkwGgZ2V2IbDouM4+A42J9iDsseM2euSsaDfum3vj9MPTqXE8zUUdX+/miMq 13 | RJTXLxDdkPaCbQftQ7y/cIAFLDZS8Fvvsa5pX69jl1ECgYEA8sQ6S7kcyYgBLX4T 14 | KVYPg1sFTgCofW5nTgCND4kiVvIDz/uk9vsfuMj7FMS3fcCfZorPdYEKa+Zwi4wZ 15 | NMCSArtezbwFBeaOiZTpjh2k8CBrtumdcU/EfzQOvrVcSzVc27ditwRAmONeBXVw 16 | GSvqSfjQKLDh/4Y191qOmgyIBDMCgYEA6aHjQr43XM811VQhTPBtLlBccD8hCS23 17 | NcujPMa85Vz+RES3OqHt2nH9NGuYrexGbrSt3ckjxnO+TdsS4f94bKhquXvv7AkX 18 | 7qr8KZEwHncyjcL3uTChbjWr2xJR4lSnS5PAbnWfyR48HXkHO9IVPe/IcYnvuGDN 19 | AeMJkCgp1LkCgYEArvD/PXAxMX1js9/FeSU+Wp8t7G8G/BSiNxColkhxSYxveOJT 20 | l3OSAXw7i1TTEbjMZX2kUH3j/6t48ObNhzk6PuO9Rq62Q/FISBbaU4JDSJNka9Rf 21 | k7cy16Ow+HcDAmN6/g5iAZb74fD+4Rom5MzDsfiuMJR+179khlJortRW9AcCgYAD 22 | 4AKD9eG3MVykOCwBOa+l6AFQf0uN+msigkkn1egGKd+xxC4B0/O8/s0DVJGIuPWG 23 | GosTtaVZQkwywGJ0yyb1Lmnuv6aAFLqH4+Ag1F6m8rUs8sHnGW5kBJHgJVKkXWEU 24 | +NNlQaAv1seKeZpsHJTrnRGHCJGoTjq4QErFUFU5SQKBgEYMGdnPP4ZDAeezPCML 25 | 42RVHOAG9IsMl4mV7+fwcEHcmuvb8nNgKNfayjG/NbiQWtT4v7iQH4GHYzUobaqr 26 | 3xnQlec3jBrLEsWR8ItRWKxKO2GGLlbmQ99Kn3UGh+6FtXbxwB0hhkFfKXJzM10N 27 | Y9ruUdyYpjGO/j9ROjoBepUH 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.3/apigw.nginx.lab.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | 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 32 | O6C6PJA6ITkdA+LLliWy4eU= 33 | -----END CERTIFICATE----- 34 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.3/apigw.nginx.lab.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | 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 51 | abUSsTGHO/UEOSdj+I8g1bIFrBdg 52 | -----END PRIVATE KEY----- 53 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.3/client.cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFAjCCA+qgAwIBAgIUavuhXA9aKTRebfvcPESft20TAxswDQYJKoZIhvcNAQEL 3 | BQAwVjELMAkGA1UEBhMCSUUxDTALBgNVBAgMBENvcmsxDTALBgNVBAcMBENvcmsx 4 | ETAPBgNVBAoMCEFjbWUgTHRkMRYwFAYDVQQDDA10ZXN0LmFjbWQubGFuMB4XDTI0 5 | MDQxNTE3MDg1M1oXDTI1MDQxNTE3MDg1M1owWDELMAkGA1UEBhMCSUUxDTALBgNV 6 | BAgMBENvcmsxDTALBgNVBAcMBENvcmsxETAPBgNVBAoMCEFjbWUgTHRkMRgwFgYD 7 | VQQDDA9jbGllbnQuYWNtZS5sYWIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK 8 | AoICAQDTCi2v/+sO+u2SpQyePK3xgotrEICdbX2cx7LdrtClO6kLS3r2mjqWZmZD 9 | Qi//GHexXKsZzPTD527FLfTDpLHohu2WfyA+C/G7brqyMOGPgyUpB65cvLu8WPM8 10 | OkyqTWfkLdFqvjAFrU9s31RycOpPJPtpYhEiaAvQX9pFxcjS65BlqAB265bygpk6 11 | jlWQ955VS9ffSKSxiA4BAp30uwFnXEkLpdBzr5NAJyrjuxslrFTK8HloFd62wsAC 12 | F6+DffCaM/5hrIcFK0IQaxpiie2ZYJiQf5rLyWzTmq1XuBk2hHAX3oAF6moaruM8 13 | 9RXqBiZ6qVtaOAqD+JQTcibeszD6glhJ+F3EELBNYXDNaKljkAtqUapa+WdGURE8 14 | vos08M+/9IaY7PxkP5pzl8fi/Qi/DIoV/8tQIrtPHc2jI1RFFh/pix1lGirNTA+D 15 | m9TD2JOHSSufvDdFuub1p2qyMnMwqE6IG8jfLH6LcqDaRng/yZUQ0jkMKHV+wX0z 16 | dgTl05UZ6m0ZE5Ge+QQhngcATzgkIjwZRhwRK8Lu6kpoegoGLRHdMSjqEt6CVsnA 17 | aKgHSm2Q8OLKYIvXU7Ti0OC6nNuN4D9JvLFAwO1EESkBQqPy8Fo/3ESYYMEk2zG4 18 | sr4QrxClncjpmC+vDftrnGNyIRov+Ny/swaRvG/rmyfxDaWM/wIDAQABo4HFMIHC 19 | MAkGA1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgWgMDMGCWCGSAGG+EIBDQQmFiRP 20 | cGVuU1NMIEdlbmVyYXRlZCBDbGllbnQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFFBb 21 | vimd61zLKvP4SdYDTVnwXtUpMB8GA1UdIwQYMBaAFKcoFDzLVw5Apb30yQ34snLe 22 | GCQVMA4GA1UdDwEB/wQEAwIF4DAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH 23 | AwQwDQYJKoZIhvcNAQELBQADggEBAJh4roddEFzbpZNdInsRgnmegYR1IisQLQSB 24 | rcrtFqVkKotlsODQpE18HF0lmP8XOHSHjc+XQQybQMwUbgdMnxAdMVhaZ1ziXIgi 25 | bPx08F4aty0IIcXr9ZEVvSwZayDAdq+ok9DjhF40aNbBaAMpv54B/e79CLIfzDJ8 26 | sYil7+OZmiNQ2meCkyPXuwawxSyTg5XVKt8TKJARyi1IydGZFQ12FXRGLMAJ7Zbx 27 | G9OwVok11zzV6DPdqneNDGpPENVgefV24eMIUu+c8gI8XMMF1OUUdw2iDBe8CMSA 28 | ishvh1VaVO4/zs9fkgKWaWz3pAjk7zdmgZRzWEEGGBLzBhBNEA8= 29 | -----END CERTIFICATE----- 30 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.3/client.key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | 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 51 | B/KL9Bv3fuI/BRKyOVeU5Vvy35/yAqU= 52 | -----END PRIVATE KEY----- 53 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.3/nap-policy-xss-allowed.json: -------------------------------------------------------------------------------- 1 | { 2 | "policy": { 3 | "name": "prod-policy", 4 | "template": { 5 | "name": "POLICY_TEMPLATE_NGINX_BASE" 6 | }, 7 | "applicationLanguage": "utf-8", 8 | "enforcementMode": "blocking", 9 | "signature-sets": [ 10 | { 11 | "name": "All Signatures", 12 | "block": true, 13 | "alarm": true 14 | } 15 | ], 16 | "signatures": [ 17 | { 18 | "signatureId": 200001834, 19 | "enabled": false 20 | }, 21 | { 22 | "signatureId": 200001475, 23 | "enabled": false 24 | }, 25 | { 26 | "signatureId": 200000098, 27 | "enabled": false 28 | }, 29 | { 30 | "signatureId": 200001088, 31 | "enabled": false 32 | }, 33 | { 34 | "signatureId": 200101609, 35 | "enabled": false 36 | } 37 | ] 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.3/nap-policy-xss-blocked-bot-allowed.json: -------------------------------------------------------------------------------- 1 | { 2 | "policy": { 3 | "name": "prod-policy", 4 | "template": { 5 | "name": "POLICY_TEMPLATE_NGINX_BASE" 6 | }, 7 | "applicationLanguage": "utf-8", 8 | "enforcementMode": "blocking", 9 | "signature-sets": [ 10 | { 11 | "name": "All Signatures", 12 | "block": true, 13 | "alarm": true 14 | } 15 | ], 16 | "signatures": [ 17 | { 18 | "signatureId": 200001834, 19 | "enabled": false 20 | } 21 | ], 22 | "bot-defense": { 23 | "settings": { 24 | "isEnabled": false 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.3/nap-policy-xss-blocked.json: -------------------------------------------------------------------------------- 1 | { 2 | "policy": { 3 | "name": "prod-policy", 4 | "template": { 5 | "name": "POLICY_TEMPLATE_NGINX_BASE" 6 | }, 7 | "applicationLanguage": "utf-8", 8 | "enforcementMode": "blocking", 9 | "signature-sets": [ 10 | { 11 | "name": "All Signatures", 12 | "block": true, 13 | "alarm": true 14 | } 15 | ], 16 | "signatures": [ 17 | { 18 | "signatureId": 200001834, 19 | "enabled": false 20 | } 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.3/testcert.chain: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDRjCCAi6gAwIBAgIUccT8pYiNoy0AQnkrUZrVCXhnm70wDQYJKoZIhvcNAQEL 3 | BQAwSDEiMCAGCSqGSIb3DQEJARYTbXlAZW1haWxhZGRyZXNzLmNvbTEiMCAGA1UE 4 | AwwZd3d3Lm9ubGluZS1ib3V0aXF1ZS5sb2NhbDAeFw0yMzAyMTQxNTA2NDRaFw0z 5 | MzAyMTExNTA2NDRaMEgxIjAgBgkqhkiG9w0BCQEWE215QGVtYWlsYWRkcmVzcy5j 6 | b20xIjAgBgNVBAMMGXd3dy5vbmxpbmUtYm91dGlxdWUubG9jYWwwggEiMA0GCSqG 7 | SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDasqlTnb5WlPHkjiLnjFX27QBm2BgDcA+x 8 | Y37biaMp+I1bTUd57hDM1X+kBeLZc98xe7hc/HaO5+3ywanBRTMVaBUCKBduET/o 9 | N+DdBAj8c64vov9a064sjXwYSeeh8lPqX52R5DYWxpHh2tvSg+a/3wwmIPoScXIu 10 | R1Wq7RY//dsshIHQkxVa9VAPYjLnusQjH9zOzJGZOxQ/OlCdaUrShbraKg6oVHK1 11 | +2h3M2S7RFjXFr8mbpxSgez1w9oN1YI+RM/kLPgI+Kq+YN6MfMhYvQei537569N9 12 | wJ9bl/i34EbM5gDf8BxhJJbo+ypEC9h0H8FmSXbqXcb8gt/dQMfZAgMBAAGjKDAm 13 | MCQGA1UdEQQdMBuCGXd3dy5vbmxpbmUtYm91dGlxdWUubG9jYWwwDQYJKoZIhvcN 14 | AQELBQADggEBAKLCxBakmK43tbf+2pwgbRLYuOvz4A8GCh/EK2F1OKeuw0oIat7M 15 | Nn5SxSgNFj45XswaRsR3/ObLovrYmXzZnV9IPNHIsB0/sBsyqEYMA55hJsb/8HEd 16 | +bWv2UJdcAimhbLMi1bpgSlSCNMn/CWkX09e3IjRrYkZxT50/ahOBBfBshoY+jwe 17 | sA1VDwZ4neXfrTUXJ4ixiTOfna2TpADLNxk6pncr6uiIpJSmLAq9jQwPBNlrpRN3 18 | TCyKKcadGdUPkALXm0+dMn1OHphy7ZQADMxPwxLySuoCK8kcslpGLg18zPXYQkoD 19 | C1KAguWu/VU4EBT39aC5/9askw+zV4XE9hw= 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.3/testcert.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDRjCCAi6gAwIBAgIUccT8pYiNoy0AQnkrUZrVCXhnm70wDQYJKoZIhvcNAQEL 3 | BQAwSDEiMCAGCSqGSIb3DQEJARYTbXlAZW1haWxhZGRyZXNzLmNvbTEiMCAGA1UE 4 | AwwZd3d3Lm9ubGluZS1ib3V0aXF1ZS5sb2NhbDAeFw0yMzAyMTQxNTA2NDRaFw0z 5 | MzAyMTExNTA2NDRaMEgxIjAgBgkqhkiG9w0BCQEWE215QGVtYWlsYWRkcmVzcy5j 6 | b20xIjAgBgNVBAMMGXd3dy5vbmxpbmUtYm91dGlxdWUubG9jYWwwggEiMA0GCSqG 7 | SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDasqlTnb5WlPHkjiLnjFX27QBm2BgDcA+x 8 | Y37biaMp+I1bTUd57hDM1X+kBeLZc98xe7hc/HaO5+3ywanBRTMVaBUCKBduET/o 9 | N+DdBAj8c64vov9a064sjXwYSeeh8lPqX52R5DYWxpHh2tvSg+a/3wwmIPoScXIu 10 | R1Wq7RY//dsshIHQkxVa9VAPYjLnusQjH9zOzJGZOxQ/OlCdaUrShbraKg6oVHK1 11 | +2h3M2S7RFjXFr8mbpxSgez1w9oN1YI+RM/kLPgI+Kq+YN6MfMhYvQei537569N9 12 | wJ9bl/i34EbM5gDf8BxhJJbo+ypEC9h0H8FmSXbqXcb8gt/dQMfZAgMBAAGjKDAm 13 | MCQGA1UdEQQdMBuCGXd3dy5vbmxpbmUtYm91dGlxdWUubG9jYWwwDQYJKoZIhvcN 14 | AQELBQADggEBAKLCxBakmK43tbf+2pwgbRLYuOvz4A8GCh/EK2F1OKeuw0oIat7M 15 | Nn5SxSgNFj45XswaRsR3/ObLovrYmXzZnV9IPNHIsB0/sBsyqEYMA55hJsb/8HEd 16 | +bWv2UJdcAimhbLMi1bpgSlSCNMn/CWkX09e3IjRrYkZxT50/ahOBBfBshoY+jwe 17 | sA1VDwZ4neXfrTUXJ4ixiTOfna2TpADLNxk6pncr6uiIpJSmLAq9jQwPBNlrpRN3 18 | TCyKKcadGdUPkALXm0+dMn1OHphy7ZQADMxPwxLySuoCK8kcslpGLg18zPXYQkoD 19 | C1KAguWu/VU4EBT39aC5/9askw+zV4XE9hw= 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.3/testcert.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDasqlTnb5WlPHk 3 | jiLnjFX27QBm2BgDcA+xY37biaMp+I1bTUd57hDM1X+kBeLZc98xe7hc/HaO5+3y 4 | wanBRTMVaBUCKBduET/oN+DdBAj8c64vov9a064sjXwYSeeh8lPqX52R5DYWxpHh 5 | 2tvSg+a/3wwmIPoScXIuR1Wq7RY//dsshIHQkxVa9VAPYjLnusQjH9zOzJGZOxQ/ 6 | OlCdaUrShbraKg6oVHK1+2h3M2S7RFjXFr8mbpxSgez1w9oN1YI+RM/kLPgI+Kq+ 7 | YN6MfMhYvQei537569N9wJ9bl/i34EbM5gDf8BxhJJbo+ypEC9h0H8FmSXbqXcb8 8 | gt/dQMfZAgMBAAECggEBAIcP85baQqSCE+mNBm1ts+FteOQK7LmiyW5J/hxjIktX 9 | XyVV0qCwr9twtwV7RR/6eYq7155FpIqZHdDgXZAoxmWgA+lzDRVCve8SI2MbjNks 10 | MBTnW0CinlyRfGQbsFvJpp2GM2/YOrdSJuIPIdce8rDodT5O+2HMgjGmiHepOCaH 11 | 4XS42Av9KDbcbo2rSfAhSulsXJetd9G7luD3dY3Lsp2TC6ihzwZOtGSHJjoY29uS 12 | D+MJvAq2MzZxRnyE6vP88NY45rZug1YS7EHs0v6NAnI6/Ew6M3sAjss+qhBL/k6j 13 | AMWAibn1oTgbN6ifXapXpynQOSU1IvEJqXNHA+YQMEkCgYEA/t7TihpRoJRcMzx6 14 | 4XtKMMDS/ixv7QUmOnJ1AO1Je3hjJK+2U1wARYLHoVdlZYTb9GRRlH6UHPL3lh2m 15 | ZWfDHRjKzQ+E4jlYFvQMAmAhbSqCAPtyFadQf7qLDKZAT/1WUj+Ynh0vjUUigqKj 16 | VsukDJkwqSt3jCk2ECtddcTicCcCgYEA26rLSaDx/+bDYVlJW9nXt8/N2ZYqtBev 17 | I+AV1qgVYjlskbcMch3apIVELiOEVfBaIGJDoq1N3e25cTvNNO/mA2rDSYLQuz7L 18 | bwlVs6ix02/tFd1R0N5nGKMhziue1l3BOjADHzf/UkOc4UIJGkmUQHrVxpby6FMY 19 | cT+HJ3+OB/8CgYAHtDqWuRbwkKt8zP415KEoehumnTdA5d/y8lTBE2seNVRh3oHX 20 | YTeM4lggc2DYQbzYVVP19iGKAnojaoAGHq3SKlau/iIZKHyWLQhT5g38m8VUPEWF 21 | jAot4jijyD63bEP4tn1pgh5W2dkiM8JWNE+gJd1Hr82sSe6dbIIlti7WDwKBgA3n 22 | PX6nhSmhPXSH5jC+FP05VdoTuxgy947ZvAgeE1xoLgr6/vqqERCgrrQM429dCxdJ 23 | oOZG+cq2JSqZkl9rX6+PrlSUxwlS7CVW/emlH7w2NVdQ7sC9kuDoUlduQ1tmC7jX 24 | GRt8u9hFF0TanSDgz1VVcPpky3MQ71cboj5JwH+ZAoGAAcDSlHuOu2xnbdnaTdE1 25 | MK0q/Yt3EOCGp0FRBkResPhhoV/TXadk0sJJbWFnleRFDkmgsw2QAwVhKQHCRWOu 26 | b4G8EnEXY/91IoRSevWtZTNf+/9+y5w4iOWI3rGJNpXCEgzN7Yc60z1sIsC/fu+Q 27 | YxXNiLIYUB4Pk4pDNRNLMZo= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.3/testcert2.chain: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDSTCCAjGgAwIBAgIUbzaZNPdYel80IQ81PCNfMllLnYgwDQYJKoZIhvcNAQEL 3 | BQAwSTEiMCAGCSqGSIb3DQEJARYTbXlAZW1haWxhZGRyZXNzLmNvbTEjMCEGA1UE 4 | Awwad3d3Mi5vbmxpbmUtYm91dGlxdWUubG9jYWwwHhcNMjMwMjE0MTUwNzMxWhcN 5 | MzMwMjExMTUwNzMxWjBJMSIwIAYJKoZIhvcNAQkBFhNteUBlbWFpbGFkZHJlc3Mu 6 | Y29tMSMwIQYDVQQDDBp3d3cyLm9ubGluZS1ib3V0aXF1ZS5sb2NhbDCCASIwDQYJ 7 | KoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2OHfrfxO6hhg4dGMi0Q4+iwuuNGv2J 8 | eh+t8g9A+dGB4zUkU0SEa2EFLjyAw2P7F1XAtiClHmS9nA0uTuj9nuw9Xk+wFUlm 9 | ahMkdkLBRNNsH3O1gTYUQSOK7xm8FOMBnOYQqJOHILXsXgM2z8QHpX//wl15aGXf 10 | 9vPm4CQUqqsEGNWDfpOQ8jfhrA4T8W1WuAXzJAQmZfhW1qMWxoj1iTCk+Q6nH/8a 11 | MWLWPjTes0bTSRXRTpuQCyeHCaqS8oPPshcd52/FXChnYbNAG1s9Q+35MrgDztL6 12 | dPkNiA9UaUY7pumNip93ZnsYwDmOPnDBPqfvy9Dk1zQuaAsJ1FXwRNsCAwEAAaMp 13 | MCcwJQYDVR0RBB4wHIIad3d3Mi5vbmxpbmUtYm91dGlxdWUubG9jYWwwDQYJKoZI 14 | hvcNAQELBQADggEBADT2SchC4VhWqCYRsw/3nqrVh0JQmD+/x9JjiNsY6fLnG6uW 15 | 8bs8/714qoghJff67H60B6NbrS3lpTZ3bmyotcGtwNNsY4QSFHRu/x4OyIrTfjKb 16 | VIdhRM2Atwc1s1YA6c+2JBquBDhniqABKG9u+j1aa2ElXSalCj+Kozm8ma0yduVw 17 | TX8zS6XZl57vSk/Qo/PZvbmbs8EMOwTUCLn6WQldAARCLughjd9LI9prNpBlYon6 18 | jmZ8oi59arK16cKe6i6tQ3QExT2kQsLlrK/jFw0xqrFnveKgUTeevViT4WZnqsCm 19 | awrPhrbDn0F7HmFSrgenrW8BIuJ2crBHy0230Lc= 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.3/testcert2.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDSTCCAjGgAwIBAgIUbzaZNPdYel80IQ81PCNfMllLnYgwDQYJKoZIhvcNAQEL 3 | BQAwSTEiMCAGCSqGSIb3DQEJARYTbXlAZW1haWxhZGRyZXNzLmNvbTEjMCEGA1UE 4 | Awwad3d3Mi5vbmxpbmUtYm91dGlxdWUubG9jYWwwHhcNMjMwMjE0MTUwNzMxWhcN 5 | MzMwMjExMTUwNzMxWjBJMSIwIAYJKoZIhvcNAQkBFhNteUBlbWFpbGFkZHJlc3Mu 6 | Y29tMSMwIQYDVQQDDBp3d3cyLm9ubGluZS1ib3V0aXF1ZS5sb2NhbDCCASIwDQYJ 7 | KoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2OHfrfxO6hhg4dGMi0Q4+iwuuNGv2J 8 | eh+t8g9A+dGB4zUkU0SEa2EFLjyAw2P7F1XAtiClHmS9nA0uTuj9nuw9Xk+wFUlm 9 | ahMkdkLBRNNsH3O1gTYUQSOK7xm8FOMBnOYQqJOHILXsXgM2z8QHpX//wl15aGXf 10 | 9vPm4CQUqqsEGNWDfpOQ8jfhrA4T8W1WuAXzJAQmZfhW1qMWxoj1iTCk+Q6nH/8a 11 | MWLWPjTes0bTSRXRTpuQCyeHCaqS8oPPshcd52/FXChnYbNAG1s9Q+35MrgDztL6 12 | dPkNiA9UaUY7pumNip93ZnsYwDmOPnDBPqfvy9Dk1zQuaAsJ1FXwRNsCAwEAAaMp 13 | MCcwJQYDVR0RBB4wHIIad3d3Mi5vbmxpbmUtYm91dGlxdWUubG9jYWwwDQYJKoZI 14 | hvcNAQELBQADggEBADT2SchC4VhWqCYRsw/3nqrVh0JQmD+/x9JjiNsY6fLnG6uW 15 | 8bs8/714qoghJff67H60B6NbrS3lpTZ3bmyotcGtwNNsY4QSFHRu/x4OyIrTfjKb 16 | VIdhRM2Atwc1s1YA6c+2JBquBDhniqABKG9u+j1aa2ElXSalCj+Kozm8ma0yduVw 17 | TX8zS6XZl57vSk/Qo/PZvbmbs8EMOwTUCLn6WQldAARCLughjd9LI9prNpBlYon6 18 | jmZ8oi59arK16cKe6i6tQ3QExT2kQsLlrK/jFw0xqrFnveKgUTeevViT4WZnqsCm 19 | awrPhrbDn0F7HmFSrgenrW8BIuJ2crBHy0230Lc= 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /contrib/gitops-examples/v5.3/testcert2.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDdjh3638TuoYYO 3 | HRjItEOPosLrjRr9iXofrfIPQPnRgeM1JFNEhGthBS48gMNj+xdVwLYgpR5kvZwN 4 | Lk7o/Z7sPV5PsBVJZmoTJHZCwUTTbB9ztYE2FEEjiu8ZvBTjAZzmEKiThyC17F4D 5 | Ns/EB6V//8JdeWhl3/bz5uAkFKqrBBjVg36TkPI34awOE/FtVrgF8yQEJmX4Vtaj 6 | FsaI9YkwpPkOpx//GjFi1j403rNG00kV0U6bkAsnhwmqkvKDz7IXHedvxVwoZ2Gz 7 | QBtbPUPt+TK4A87S+nT5DYgPVGlGO6bpjYqfd2Z7GMA5jj5wwT6n78vQ5Nc0LmgL 8 | CdRV8ETbAgMBAAECggEBAJkAy010eWC+5YAbsgDxFHM+WNQo90m+RjtYegD0w1Ff 9 | HNSXSHXZ6PnwhPS9i7IhNgU/d8dloG67zuf/YflfJQBKhTYNCTZOZtTfalhBdlF3 10 | quTSpO/+3tk32lVwYRBADeWH/ZMcT4ezO12G3can7TBPJSA+ds1b9QSNHZ9tMku0 11 | 2J2pzT8C8V0vHn49oKO9D4Q+QwRvisT6FKNaOW/xKZjtUIvyjVvjENnBW7MQ5y5z 12 | IHsUNkwGgZ2V2IbDouM4+A42J9iDsseM2euSsaDfum3vj9MPTqXE8zUUdX+/miMq 13 | RJTXLxDdkPaCbQftQ7y/cIAFLDZS8Fvvsa5pX69jl1ECgYEA8sQ6S7kcyYgBLX4T 14 | KVYPg1sFTgCofW5nTgCND4kiVvIDz/uk9vsfuMj7FMS3fcCfZorPdYEKa+Zwi4wZ 15 | NMCSArtezbwFBeaOiZTpjh2k8CBrtumdcU/EfzQOvrVcSzVc27ditwRAmONeBXVw 16 | GSvqSfjQKLDh/4Y191qOmgyIBDMCgYEA6aHjQr43XM811VQhTPBtLlBccD8hCS23 17 | NcujPMa85Vz+RES3OqHt2nH9NGuYrexGbrSt3ckjxnO+TdsS4f94bKhquXvv7AkX 18 | 7qr8KZEwHncyjcL3uTChbjWr2xJR4lSnS5PAbnWfyR48HXkHO9IVPe/IcYnvuGDN 19 | AeMJkCgp1LkCgYEArvD/PXAxMX1js9/FeSU+Wp8t7G8G/BSiNxColkhxSYxveOJT 20 | l3OSAXw7i1TTEbjMZX2kUH3j/6t48ObNhzk6PuO9Rq62Q/FISBbaU4JDSJNka9Rf 21 | k7cy16Ow+HcDAmN6/g5iAZb74fD+4Rom5MzDsfiuMJR+179khlJortRW9AcCgYAD 22 | 4AKD9eG3MVykOCwBOa+l6AFQf0uN+msigkkn1egGKd+xxC4B0/O8/s0DVJGIuPWG 23 | GosTtaVZQkwywGJ0yyb1Lmnuv6aAFLqH4+Ag1F6m8rUs8sHnGW5kBJHgJVKkXWEU 24 | +NNlQaAv1seKeZpsHJTrnRGHCJGoTjq4QErFUFU5SQKBgEYMGdnPP4ZDAeezPCML 25 | 42RVHOAG9IsMl4mV7+fwcEHcmuvb8nNgKNfayjG/NbiQWtT4v7iQH4GHYzUobaqr 26 | 3xnQlec3jBrLEsWR8ItRWKxKO2GGLlbmQ99Kn3UGh+6FtXbxwB0hhkFfKXJzM10N 27 | Y9ruUdyYpjGO/j9ROjoBepUH 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /contrib/kubernetes/README.md: -------------------------------------------------------------------------------- 1 | # Running NGINX Declarative API on Kubernetes 2 | 3 | NGINX Declarative API can be deployed on Kubernetes using the manifest provided 4 | 5 | ## How to deploy 6 | 7 | 1. Build the NGINX Declarative API docker images using the [Docker-compose script](/contrib/docker-compose) 8 | 9 | 2. Tag and push the docker images to a private registry 10 | 11 | ``` 12 | docker tag nginx-declarative-api:latest YOUR_REGISTRY_HERE/nginx-declarative-api:latest 13 | docker push YOUR_REGISTRY_HERE/nginx-declarative-api:latest 14 | 15 | docker tag nginx-declarative-api-devportal:latest YOUR_REGISTRY_HERE/nginx-declarative-api-devportal:latest 16 | docker push YOUR_REGISTRY_HERE/nginx-declarative-api-devportal:latest 17 | ``` 18 | 19 | 3. Edit `nginx-declarative-api.yaml` and update the following lines to match the docker images and to set the `Ingress` host DNS name 20 | 21 | ``` 22 | image: YOUR_REGISTRY_HERE/nginx-declarative-api:latest 23 | image: YOUR_REGISTRY_HERE/nginx-declarative-api-devportal:latest 24 | ``` 25 | 26 | ``` 27 | - host: nginx-dapi.k8s.f5.ff.lan 28 | ``` 29 | 30 | 4. Apply the manifest 31 | 32 | ``` 33 | $ kubectl apply -f nginx-declarative-api.yaml 34 | namespace/nginx-dapi created 35 | deployment.apps/redis created 36 | deployment.apps/nginx-dapi created 37 | deployment.apps/devportal created 38 | service/redis created 39 | service/nginx-dapi created 40 | service/devportal created 41 | ingress.networking.k8s.io/nginx-dapi created 42 | ``` 43 | 44 | 5. Make sure all pods are up and running 45 | 46 | ``` 47 | $ kubectl get all -n nginx-dapi 48 | NAME READY STATUS RESTARTS AGE 49 | pod/devportal-74fc5c9ccb-5wjpr 1/1 Running 0 25s 50 | pod/nginx-dapi-848599b79b-ll2kg 1/1 Running 0 25s 51 | pod/redis-5cdb78b899-hjz9x 1/1 Running 0 25s 52 | ``` 53 | 54 | 6. The NGINX Declarative API can be accessed through its `Ingress` resource 55 | 56 | ``` 57 | $ kubectl get ingress -n nginx-dapi 58 | NAME CLASS HOSTS ADDRESS PORTS AGE 59 | nginx-dapi nginx nginx-dapi.k8s.f5.ff.lan 80 34s 60 | ``` 61 | 62 | ## How to undeploy 63 | 64 | 1. Delete the `nginx-declarative-api.yaml` manifest 65 | 66 | ``` 67 | kubectl delete -f nginx-declarative-api.yaml 68 | ``` 69 | -------------------------------------------------------------------------------- /contrib/kubernetes/nginx-declarative-api.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: nginx-dapi 5 | 6 | --- 7 | apiVersion: apps/v1 8 | kind: Deployment 9 | metadata: 10 | name: redis 11 | namespace: nginx-dapi 12 | labels: 13 | app: redis 14 | spec: 15 | selector: 16 | matchLabels: 17 | app: redis 18 | replicas: 1 19 | template: 20 | metadata: 21 | labels: 22 | app: redis 23 | spec: 24 | containers: 25 | - name: redis 26 | image: redis 27 | ports: 28 | - name: redis 29 | containerPort: 6379 30 | 31 | --- 32 | apiVersion: apps/v1 33 | kind: Deployment 34 | metadata: 35 | name: nginx-dapi 36 | namespace: nginx-dapi 37 | labels: 38 | app: nginx-dapi 39 | spec: 40 | selector: 41 | matchLabels: 42 | app: nginx-dapi 43 | replicas: 1 44 | template: 45 | metadata: 46 | labels: 47 | app: nginx-dapi 48 | spec: 49 | containers: 50 | - name: nginx-dapi 51 | image: YOUR_REGISTRY_HERE/nginx-declarative-api:latest 52 | ports: 53 | - name: http 54 | containerPort: 5000 55 | 56 | --- 57 | apiVersion: apps/v1 58 | kind: Deployment 59 | metadata: 60 | name: devportal 61 | namespace: nginx-dapi 62 | labels: 63 | app: devportal 64 | spec: 65 | selector: 66 | matchLabels: 67 | app: devportal 68 | replicas: 1 69 | template: 70 | metadata: 71 | labels: 72 | app: devportal 73 | spec: 74 | containers: 75 | - name: devportal 76 | image: YOUR_REGISTRY_HERE/nginx-declarative-api-devportal:latest 77 | ports: 78 | - name: http 79 | containerPort: 5000 80 | 81 | --- 82 | apiVersion: apps/v1 83 | kind: Deployment 84 | metadata: 85 | name: devportal 86 | namespace: nginx-dapi 87 | labels: 88 | app: nap-compiler 89 | spec: 90 | selector: 91 | matchLabels: 92 | app: nap-compiler 93 | replicas: 1 94 | template: 95 | metadata: 96 | labels: 97 | app: nap-compiler 98 | spec: 99 | containers: 100 | - name: devportal 101 | image: YOUR_REGISTRY_HERE/nginx-declarative-api-nap-compiler:latest 102 | ports: 103 | - name: http 104 | containerPort: 5000 105 | 106 | --- 107 | apiVersion: v1 108 | kind: Service 109 | metadata: 110 | name: redis 111 | namespace: nginx-dapi 112 | labels: 113 | app: redis 114 | spec: 115 | ports: 116 | - name: redis 117 | port: 6379 118 | selector: 119 | app: redis 120 | type: ClusterIP 121 | 122 | --- 123 | apiVersion: v1 124 | kind: Service 125 | metadata: 126 | name: nginx-dapi 127 | namespace: nginx-dapi 128 | labels: 129 | app: nginx-dapi 130 | spec: 131 | ports: 132 | - name: http 133 | port: 5000 134 | selector: 135 | app: nginx-dapi 136 | type: ClusterIP 137 | 138 | --- 139 | apiVersion: v1 140 | kind: Service 141 | metadata: 142 | name: devportal 143 | namespace: nginx-dapi 144 | labels: 145 | app: devportal 146 | spec: 147 | ports: 148 | - name: http 149 | port: 5000 150 | selector: 151 | app: devportal 152 | type: ClusterIP 153 | 154 | --- 155 | apiVersion: v1 156 | kind: Service 157 | metadata: 158 | name: nap-compiler 159 | namespace: nginx-dapi 160 | labels: 161 | app: nap-compiler 162 | spec: 163 | ports: 164 | - name: http 165 | port: 5000 166 | selector: 167 | app: devportal 168 | type: ClusterIP 169 | 170 | --- 171 | apiVersion: networking.k8s.io/v1 172 | kind: Ingress 173 | metadata: 174 | name: nginx-dapi 175 | namespace: nginx-dapi 176 | labels: 177 | app: nginx-dapi 178 | spec: 179 | ingressClassName: nginx 180 | rules: 181 | - host: nginx-dapi.k8s.f5.ff.lan 182 | http: 183 | paths: 184 | - path: / 185 | pathType: Prefix 186 | backend: 187 | service: 188 | name: nginx-dapi 189 | port: 190 | number: 5000 191 | -------------------------------------------------------------------------------- /contrib/postman/README.md: -------------------------------------------------------------------------------- 1 | # Sample Postman Collection 2 | 3 | This collection contains several declaration examples for the following Declarative API releases: 4 | 5 | * API v5.2 - Required for NGINX Plus R33+ 6 | * API v5.1 7 | * API v5.0 8 | 9 | **Note**: 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.2.md) for further details. [Postman collection](/contrib/postman) examples are provided for R33. 10 | 11 | --- 12 | 13 | ## API Gateway ## 14 | 15 | Test requests for the `API Gateway` folder in the Postman collection require `apigw.nginx.lab` to resolve to the NGINX instance IP address. 16 | 17 | ### Petstore ### 18 | 19 | Successful request 20 | 21 | ``` 22 | curl -w '\n' -ik https://apigw.nginx.lab/petstore/store/inventory 23 | ``` 24 | 25 | Authentication failed: 26 | 27 | ``` 28 | curl -w '\n' -ik https://apigw.nginx.lab/petstore/user/login 29 | ``` 30 | 31 | Authentication successful: 32 | 33 | ``` 34 | curl -w '\n' -ik https://apigw.nginx.lab/petstore/user/login -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDI0ODEzNjcsImV4cCI6MTcwMjQ4MTM2OH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIl19.SKA_7MszAypMEtX5NDQ0TcUbVYx_Wt0hrtmuyTmrVKU" 35 | ``` 36 | 37 | Authorization failed (based on JWT `role` claim): 38 | 39 | ``` 40 | curl -w '\n' -ki https://apigw.nginx.lab/petstore/user/login -H "Authorization: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDk3NjQ3NTMsImV4cCI6MTcwOTc2NDc1NH0.eyJuYW1lIjoiQWxpY2UgR3Vlc3QiLCJzdWIiOiJKV1Qgc3ViIGNsYWltIiwiaXNzIjoiSldUIGlzcyBjbGFpbSIsInJvbGVzIjpbImd1ZXN0Il19.jFJDq-33irz7uFxdI8c8fIb5TwTAU5BlemmIFVALUAE" 41 | ``` 42 | ``` 43 | curl -w '\n' -ki https://apigw.nginx.lab/petstore/pet/1/uploadImage -X POST \ 44 | -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDk3NjQ3NTMsImV4cCI6MTcwOTc2NDc1NH0.eyJuYW1lIjoiQWxpY2UgR3Vlc3QiLCJzdWIiOiJKV1Qgc3ViIGNsYWltIiwiaXNzIjoiSldUIGlzcyBjbGFpbSIsInJvbGVzIjpbImd1ZXN0Il19.jFJDq-33irz7uFxdI8c8fIb5TwTAU5BlemmIFVALUAE" \ 45 | -H 'accept: application/json' \ 46 | -H 'Content-Type: multipart/form-data' \ 47 | -F 'file=iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TS0UqChYRcchQXbSLijjWKhShQqgVWnUwuX5Ck4YkxcVRcC04+LFYdXBx1tXBVRAEP0CcHZwUXaTE/yWFFjEeHPfj3b3H3TtAaFSYanbFAFWzjFQiLmayq2LwFQEI6Mc4BmVm6nOSlITn+LqHj693UZ7lfe7P0ZvLmwzwicQxphsW8QbxzKalc94nDrOSnCM+J54w6ILEj1xXXH7jXHRY4JlhI52aJw4Ti8UOVjqYlQyVeJo4klM1yhcyLuc4b3FWKzXWuid/YSivrSxzneYIEljEEiSIUFBDGRVYiNKqkWIiRftxD/+w45fIpZCrDEaOBVShQnb84H/wu1uzMDXpJoXiQODFtj9GgeAu0Kzb9vexbTdPAP8zcKW1/dUGMPtJer2tRY6Avm3g4rqtKXvA5Q4w9KTLhuxIfppCoQC8n9E3ZYGBW6Bnze2ttY/TByBNXSVvgINDYKxI2ese7+7u7O3fM63+fgB5bXKpzZcBIwAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAAd0SU1FB+gFAhArKAvJglcAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAADElEQVQI12P4//8/AAX+Av7czFnnAAAAAElFTkSuQmCC;type=image/png' 48 | ``` 49 | 50 | Authorization successful (based on JWT `role` claim): 51 | 52 | ``` 53 | curl -w '\n' -ki https://apigw.nginx.lab/petstore/user/login -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDI0ODEzNjcsImV4cCI6MTcwMjQ4MTM2OH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIl19.SKA_7MszAypMEtX5NDQ0TcUbVYx_Wt0hrtmuyTmrVKU" 54 | ``` 55 | 56 | ``` 57 | curl -w '\n' -ki https://apigw.nginx.lab/petstore/pet/1/uploadImage -X POST \ 58 | -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjAwMDEiLCJpc3MiOiJCYXNoIEpXVCBHZW5lcmF0b3IiLCJpYXQiOjE3MDI0ODEzNjcsImV4cCI6MTcwMjQ4MTM2OH0.eyJuYW1lIjoiQm9iIERldk9wcyIsInN1YiI6IkpXVCBzdWIgY2xhaW0iLCJpc3MiOiJKV1QgaXNzIGNsYWltIiwicm9sZXMiOlsiZGV2b3BzIl19.SKA_7MszAypMEtX5NDQ0TcUbVYx_Wt0hrtmuyTmrVKU" \ 59 | -H 'accept: application/json' \ 60 | -H 'Content-Type: multipart/form-data' \ 61 | -F 'file=iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TS0UqChYRcchQXbSLijjWKhShQqgVWnUwuX5Ck4YkxcVRcC04+LFYdXBx1tXBVRAEP0CcHZwUXaTE/yWFFjEeHPfj3b3H3TtAaFSYanbFAFWzjFQiLmayq2LwFQEI6Mc4BmVm6nOSlITn+LqHj693UZ7lfe7P0ZvLmwzwicQxphsW8QbxzKalc94nDrOSnCM+J54w6ILEj1xXXH7jXHRY4JlhI52aJw4Ti8UOVjqYlQyVeJo4klM1yhcyLuc4b3FWKzXWuid/YSivrSxzneYIEljEEiSIUFBDGRVYiNKqkWIiRftxD/+w45fIpZCrDEaOBVShQnb84H/wu1uzMDXpJoXiQODFtj9GgeAu0Kzb9vexbTdPAP8zcKW1/dUGMPtJer2tRY6Avm3g4rqtKXvA5Q4w9KTLhuxIfppCoQC8n9E3ZYGBW6Bnze2ttY/TByBNXSVvgINDYKxI2ese7+7u7O3fM63+fgB5bXKpzZcBIwAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAAd0SU1FB+gFAhArKAvJglcAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAADElEQVQI12P4//8/AAX+Av7czFnnAAAAAElFTkSuQmCC;type=image/png' 62 | ``` 63 | 64 | The API Developer portal can be accessed at: 65 | 66 | https://apigw.nginx.lab/petstore/petstore-devportal.html 67 | 68 | ### Ergast ### 69 | 70 | Valid request: 71 | 72 | curl -s http://apigw.nginx.lab/ergast/2023.json | jq 73 | 74 | Invalid request: 75 | 76 | curl -s http://apigw.nginx.lab/ergast/2023.json -X POST 77 | 78 | 79 | --- 80 | 81 | **Note**: The `GitOps autosync` folder requires either 82 | - an NGINX instance (OSS or Plus) reachable as `acme.gitlab.local` on port `80/TCP` using the sample configuration available here: [/contrib/sample-source-of-truth/ncg-nginx.conf](/contrib/sample-source-of-truth/ncg-nginx.conf) 83 | - access to the GitHub repository at https://github.com/f5devcentral/NGINX-Declarative-API/ to fetch files under https://github.com/f5devcentral/NGINX-Declarative-API/tree/main/contrib/gitops-examples/v4.0 84 | -------------------------------------------------------------------------------- /etc/config.toml: -------------------------------------------------------------------------------- 1 | # NGINX Declarative API - https://github.com/f5devcentral/NGINX-Declarative-API/ 2 | 3 | # Main variables 4 | [main] 5 | banner = "NGINX Declarative API" 6 | version = "5.3.0" 7 | url = "https://github.com/f5devcentral/NGINX-Declarative-API" 8 | 9 | # Templates 10 | [templates] 11 | root_dir = "../templates" 12 | nginxmain = "nginx-conf/nginx.conf" 13 | mimetypes = "nginx-conf/mime.types" 14 | license = "nginx-conf/license-key.tmpl" 15 | 16 | httpconf = "http.tmpl" 17 | apigwconf = "apigateway.tmpl" 18 | visibility_root = "visibility" 19 | streamconf = "stream.tmpl" 20 | configmap = "configmap.tmpl" 21 | 22 | auth_client_root = "authn/client" 23 | auth_server_root = "authn/server" 24 | 25 | authz_client_root = "authz/client" 26 | 27 | devportal_root = "devportal" 28 | misc_root = "misc" 29 | 30 | # NGINX Declarative API Server 31 | [apiserver] 32 | host = "0.0.0.0" 33 | port = 5000 34 | 35 | # Redis backend 36 | [redis] 37 | host = "redis" 38 | port = 6379 39 | 40 | # Redocly devportal helper 41 | [devportal] 42 | host = "devportal" 43 | port = 5000 44 | uri = "/v1/devportal" 45 | 46 | # NGINX App Protect 47 | [nap] 48 | cookie_protection_seed = "tBjtd3WXKqoKp27pfEBc" 49 | compiler_host = "nap-compiler" 50 | compiler_port = 5000 51 | compiler_uri = "/v1/compile/policy" 52 | 53 | # Staged configuration directories 54 | [nms] 55 | config_dir = '/etc/nginx' 56 | certs_dir = '/etc/nginx/ssl' 57 | apigw_dir = '/etc/nginx/apigateway' 58 | visibility_dir = '/etc/nginx/visibility' 59 | devportal_dir = '/etc/nginx/devportal' 60 | auth_client_dir = '/etc/nginx/authn/client' 61 | auth_server_dir = '/etc/nginx/authn/server' 62 | authz_client_dir = '/etc/nginx/authz/client' 63 | njs_dir = '/etc/nginx/njs' 64 | resolver_dir = '/etc/nginx/resolvers' 65 | upstream_http_dir = '/etc/nginx/upstreams/http' 66 | upstream_stream_dir = '/etc/nginx/upstreams/stream' 67 | 68 | # Time (in seconds) to wait to get status after committing a staged config 69 | staged_config_publish_waittime = 2 70 | 71 | # Time (in seconds) to wait between two subsequent asynchronous submissions publish requests through PATCH 72 | asynchronous_publish_waittime = 30 73 | 74 | # NGINX App Protect support 75 | nap_policies_dir = '/etc/nginx/waf/policies' 76 | nap_logformats_dir = '/etc/nginx/waf/logformats' 77 | nap_logformats_template = "logformat.tmpl" 78 | nap_policies_dir_pum = '/etc/nms' 79 | nap_logformats_dir_pum = '/etc/nms' 80 | 81 | # Staged configuration filenames 82 | staged_config_http_filename = 'conf.d/services.conf' 83 | staged_config_stream_filename = 'stream-conf.d/services.conf' -------------------------------------------------------------------------------- /src/NcgConfig.py: -------------------------------------------------------------------------------- 1 | """ 2 | Configuration singleton 3 | """ 4 | 5 | import toml 6 | 7 | 8 | class NcgConfig(object): 9 | _instance = None 10 | config = {} 11 | 12 | def __new__(cls,configFile): 13 | if cls._instance is None: 14 | print(f'Reading configuration from {configFile}') 15 | cls._instance = super(cls, NcgConfig).__new__(cls) 16 | 17 | with open(configFile) as cfgFile: 18 | cls.config = toml.load(cfgFile) 19 | 20 | return cls._instance 21 | -------------------------------------------------------------------------------- /src/NcgRedis.py: -------------------------------------------------------------------------------- 1 | """ 2 | Redis singleton 3 | """ 4 | 5 | import redis 6 | import sys 7 | import queue 8 | 9 | 10 | class NcgRedis(object): 11 | _instance = None 12 | redis 13 | asyncQueue = None 14 | 15 | # All submitted config declarations 16 | # For each entry key is the configUid 17 | # Value is: 18 | # - the threaded autosync job for autosync declarations 19 | # - "static" for declarations not in autosync mode 20 | declarationsList = {} 21 | 22 | def __new__(cls, host, port): 23 | if cls._instance is None: 24 | try: 25 | cls.redis = redis.Redis(host, port) 26 | print(f"Connecting to redis at {host}:{port}") 27 | 28 | cls.redis.set('NGINX_Declarative_API','test') 29 | cls.redis.delete('NGINX_Declarative_API') 30 | 31 | # Asynchronous queue 32 | cls.asyncQueue = queue.Queue() 33 | except Exception as e: 34 | print(f"Cannot connect to redis on {host}:{port} : {e}") 35 | sys.exit(1) 36 | 37 | cls._instance = super(cls, NcgRedis).__new__(cls) 38 | 39 | return cls._instance 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/requirements.txt: -------------------------------------------------------------------------------- 1 | fastapi 2 | uvicorn 3 | urllib3 4 | requests 5 | datetime 6 | pydantic 7 | jinja2 8 | jinja2-base64-filters 9 | toml 10 | requests 11 | redis 12 | uuid 13 | schedule 14 | future 15 | pyyaml -------------------------------------------------------------------------------- /src/v5_1/APIGateway.py: -------------------------------------------------------------------------------- 1 | """ 2 | API Gateway support functions 3 | """ 4 | 5 | import json 6 | 7 | import v5_1.GitOps 8 | import v5_1.MiscUtils 9 | from v5_1.OpenAPIParser import OpenAPIParser 10 | 11 | # pydantic models 12 | from V5_1_NginxConfigDeclaration import * 13 | 14 | 15 | # Builds the declarative JSON for the API Gateway configuration 16 | # Return a tuple: status, description. If status = 200 things were successful 17 | def createAPIGateway(locationDeclaration: dict, authProfiles: Authentication={}): 18 | apiGwDeclaration = {} 19 | 20 | if locationDeclaration['apigateway']['openapi_schema']: 21 | status, apiSchemaString = v5_1.GitOps.getObjectFromRepo(object=locationDeclaration['apigateway']['openapi_schema'], 22 | authProfiles = authProfiles['server'] if 'server' in authProfiles else {}, base64Encode=False) 23 | 24 | if v5_1.MiscUtils.yaml_or_json(apiSchemaString['content']) == 'yaml': 25 | # YAML to JSON conversion 26 | apiSchemaString['content'] = v5_1.MiscUtils.yaml_to_json(apiSchemaString['content']) 27 | 28 | apiSchema = OpenAPIParser(json.loads(apiSchemaString['content'])) 29 | 30 | apiGwDeclaration = {} 31 | apiGwDeclaration['location'] = locationDeclaration 32 | apiGwDeclaration['info'] = apiSchema.info() 33 | apiGwDeclaration['servers'] = apiSchema.servers() 34 | apiGwDeclaration['paths'] = apiSchema.paths() 35 | apiGwDeclaration['version'] = apiSchema.version() 36 | 37 | return 200, apiGwDeclaration, apiSchemaString['content'] -------------------------------------------------------------------------------- /src/v5_1/DevPortal.py: -------------------------------------------------------------------------------- 1 | """ 2 | API Gateway Developer Portal support functions 3 | """ 4 | 5 | import json 6 | import requests 7 | import base64 8 | 9 | # NGINX Declarative API modules 10 | from NcgConfig import NcgConfig 11 | import v5_1.GitOps 12 | import v5_1.MiscUtils 13 | 14 | # pydantic models 15 | from V5_1_NginxConfigDeclaration import * 16 | 17 | def buildDevPortal(openapischema): 18 | try: 19 | response = requests.post(f"http://{NcgConfig.config['devportal']['host']}:" 20 | f"{NcgConfig.config['devportal']['port']}{NcgConfig.config['devportal']['uri']}", 21 | headers={'Content-Type': 'application/json'}, data=openapischema) 22 | except Exception as e: 23 | return 400, "" 24 | 25 | return response.status_code, json.loads(response.text) 26 | 27 | 28 | # Builds the declarative JSON for the API Gateway configuration 29 | # Return a tuple: status, description. If status = 200 things were successful 30 | def createDevPortal(locationDeclaration: dict, authProfiles: Authentication={}): 31 | if locationDeclaration['apigateway']['openapi_schema']: 32 | status, apiSchemaString = v5_1.GitOps.getObjectFromRepo( 33 | object = locationDeclaration['apigateway']['openapi_schema'], authProfiles = authProfiles['server'] if 'server' in authProfiles else {}, base64Encode = False) 34 | 35 | if v5_1.MiscUtils.yaml_or_json(apiSchemaString['content']) == 'yaml': 36 | # YAML to JSON conversion 37 | status, devportalJSON = buildDevPortal(openapischema = v5_1.MiscUtils.yaml_to_json(apiSchemaString['content'])) 38 | else: 39 | status, devportalJSON = buildDevPortal(openapischema = apiSchemaString['content']) 40 | 41 | if status == 200: 42 | devportalHTML = base64.b64encode(bytes(devportalJSON['devportal'], 'utf-8')).decode('utf-8') 43 | else: 44 | devportalHTML = "" 45 | 46 | return status, devportalHTML -------------------------------------------------------------------------------- /src/v5_1/GitOps.py: -------------------------------------------------------------------------------- 1 | """ 2 | GitOps support functions 3 | """ 4 | 5 | import base64 6 | import requests 7 | 8 | from requests import ReadTimeout, HTTPError, Timeout, ConnectionError, ConnectTimeout 9 | 10 | # pydantic models 11 | from V5_1_NginxConfigDeclaration import * 12 | 13 | 14 | # Fetches a URL content 15 | def __fetchfromsourceoftruth__(url, headers = {} ): 16 | # Object is fetched from external repository 17 | try: 18 | reply = requests.get(url = url, headers = headers, verify=False) 19 | except (ConnectTimeout, HTTPError, ReadTimeout, Timeout, ConnectionError): 20 | return 408, "URL " + url + " unreachable" 21 | 22 | return reply.status_code, reply.text 23 | 24 | 25 | # If content starts with http(s):// fetches the object and return it b64-encoded by default. 26 | # base64Encode to be set to False to disable b64 encoding 27 | # Returns the status original content otherwise. 28 | # Return is a tuple: status_code, content 29 | def getObjectFromRepo(object: ObjectFromSourceOfTruth, authProfiles: Authentication={}, base64Encode: bool=True): 30 | status_code = 200 31 | response = object 32 | 33 | if object: 34 | if object['content'].lower().startswith(("http://","https://")): 35 | # Object is fetched from external repository 36 | headers = {} 37 | 38 | # Set server authentication if needed 39 | if authProfiles and 'server' in authProfiles and len(object['authentication'])>0: 40 | for authP in authProfiles['server']: 41 | if object['authentication'][0]['profile'] == authP['name']: 42 | # Sets up authentication 43 | if authP['type'].lower() == 'token': 44 | 45 | authToken = authP['token']['token'] 46 | authTokenType = authP['token']['type'] 47 | 48 | if authTokenType.lower() == 'bearer': 49 | headers['Authorization'] = f"Bearer {authToken}" 50 | elif authTokenType.lower() == 'basic': 51 | authTokenUsername = authP['token']['username'] 52 | authTokenPassword = base64.b64decode(authP['token']['password']).decode('utf-8') 53 | 54 | headers['Authorization'] = f"Basic {base64.b64encode(str.encode(authTokenUsername + ':' + authTokenPassword)).decode('utf-8')}" 55 | elif authTokenType.lower() == 'header': 56 | authTokenLocation = authP['token']['location'] 57 | 58 | headers[authTokenLocation] = authToken 59 | 60 | status_code, fetchedContent = __fetchfromsourceoftruth__(url = object['content'], headers = headers) 61 | 62 | if status_code == 200: 63 | if base64Encode == True: 64 | fetchedContent = base64.b64encode(bytes(fetchedContent, 'utf-8')).decode('utf-8') 65 | else: 66 | fetchedContent = bytes(fetchedContent, 'utf-8').decode("utf-8") 67 | 68 | response['content'] = fetchedContent 69 | 70 | return status_code, response -------------------------------------------------------------------------------- /src/v5_1/MiscUtils.py: -------------------------------------------------------------------------------- 1 | """ 2 | Support functions 3 | """ 4 | 5 | import re 6 | import json 7 | import yaml 8 | import uuid 9 | 10 | 11 | def getDictKey(_dict: dict, key_lookup: str, separator='.'): 12 | """ 13 | Searches for a nested key in a dictionary and returns its value, or None if nothing was found. 14 | key_lookup must be a string where each key is deparated by a given "separator" character, which by default is a dot 15 | """ 16 | keys = key_lookup.split(separator) 17 | subdict = _dict 18 | 19 | for k in keys: 20 | subdict = subdict[k] if k in subdict else None 21 | if subdict is None: 22 | return None 23 | 24 | return subdict 25 | 26 | """ 27 | Jinja2 regexp filter 28 | """ 29 | def regex_replace(s, find, replace): 30 | return re.sub(find, replace, s) 31 | 32 | """ 33 | JSON/YAML detection 34 | """ 35 | def yaml_or_json(document: str): 36 | try: 37 | json.load(document) 38 | return 'json' 39 | except Exception: 40 | return 'yaml' 41 | 42 | """ 43 | YAML to JSON conversion 44 | """ 45 | def yaml_to_json(document: str): 46 | return json.dumps(yaml.safe_load(document)) 47 | 48 | 49 | """ 50 | JSON TO YAML conversion 51 | """ 52 | def json_to_yaml(document: str): 53 | return yaml.dump(json.loads(document)) 54 | 55 | 56 | """ 57 | Returns a unique ID 58 | """ 59 | def getuniqueid(): 60 | return uuid.uuid4() -------------------------------------------------------------------------------- /src/v5_1/NGINXOneUtils.py: -------------------------------------------------------------------------------- 1 | """ 2 | NGINX One support functions 3 | """ 4 | 5 | import requests 6 | import json 7 | 8 | 9 | # Fetch a cluster ID from NGINX One 10 | # Return None if not found 11 | def getConfigSyncGroupId(nOneUrl: str, nOneToken: str, nameSpace: str, configSyncGroupName: str): 12 | # Retrieve config sync group uid 13 | cSyncGroup = requests.get(url=f'{nOneUrl}/api/nginx/one/namespaces/{nameSpace}/config-sync-groups', 14 | verify=False, headers = {"Authorization": f"Bearer APIToken {nOneToken}"}) 15 | 16 | if cSyncGroup.status_code != 200: 17 | if cSyncGroup.status_code == 401: 18 | return cSyncGroup.status_code, "NGINX One authentication failed" 19 | else: 20 | return cSyncGroup.status_code, f"Error fetching config sync group uid: {cSyncGroup.text}" 21 | 22 | # Get the instance group id 23 | igUid = None 24 | igJson = json.loads(cSyncGroup.text) 25 | for i in igJson['items']: 26 | if i['name'] == configSyncGroupName: 27 | igUid = i['object_id'] 28 | 29 | if igUid is None: 30 | return 404, f"config sync group [{configSyncGroupName}] not found" 31 | 32 | return 200, igUid 33 | -------------------------------------------------------------------------------- /src/v5_1/NIMUtils.py: -------------------------------------------------------------------------------- 1 | """ 2 | NGINX Instance Manager support functions 3 | """ 4 | 5 | import requests 6 | import json 7 | 8 | 9 | # Fetch an instance group UID from NGINX Instance Manager 10 | # Return None if not found 11 | def getNIMInstanceGroupUid(nmsUrl: str, nmsUsername: str, nmsPassword: str, instanceGroupName: str): 12 | # Retrieve instance group uid 13 | ig = requests.get(url=f'{nmsUrl}/api/platform/v1/instance-groups', auth=(nmsUsername, nmsPassword), 14 | verify=False) 15 | 16 | if ig.status_code != 200: 17 | return None 18 | 19 | # Get the instance group id 20 | igUid = None 21 | igJson = json.loads(ig.text) 22 | for i in igJson['items']: 23 | if i['name'] == instanceGroupName: 24 | igUid = i['uid'] 25 | 26 | return igUid 27 | -------------------------------------------------------------------------------- /src/v5_1/OpenAPIParser.py: -------------------------------------------------------------------------------- 1 | """ 2 | OpenAPI schema parser support functions 3 | """ 4 | 5 | import json 6 | 7 | class OpenAPIParser: 8 | httpMethods = ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'CONNECT', 'OPTIONS', 'TRACE', 'PATCH'] 9 | 10 | def __init__(self, openAPISchema): 11 | self.openAPISchema = openAPISchema 12 | 13 | def version(self): 14 | if 'openapi' in self.openAPISchema: 15 | return self.openAPISchema['openapi'] 16 | elif 'swagger' in self.openAPISchema: 17 | return self.openAPISchema['swagger'] 18 | 19 | return None 20 | 21 | def info(self): 22 | return self.openAPISchema['info'] 23 | 24 | def servers(self): 25 | self.allServers = [] 26 | 27 | # Loop over OpenAPI schema servers 28 | if 'servers' in self.openAPISchema: 29 | for server in self.openAPISchema['servers']: 30 | urlName = server['url'] 31 | self.s = {} 32 | self.s['url'] = urlName 33 | 34 | if 'description' in server: 35 | self.s['description'] = server['description'] 36 | 37 | self.allServers.append(self.s) 38 | 39 | return self.allServers 40 | 41 | def paths(self): 42 | self.allPaths = [] 43 | 44 | # Loop over OpenAPI schema paths 45 | if 'paths' in self.openAPISchema: 46 | for path in self.openAPISchema['paths'].keys(): 47 | #print(f"- {path}") 48 | self.p = {} 49 | self.p['path'] = path 50 | self.p['methods'] = [] 51 | 52 | # Loop over path HTTP methods found in schema 53 | for method in self.openAPISchema['paths'][path].keys(): 54 | methodInfo = self.openAPISchema['paths'][path][method] 55 | 56 | if method.upper() in self.httpMethods: 57 | self.m = {} 58 | self.m['method'] = method 59 | self.m['details'] = {} 60 | 61 | if 'description' in methodInfo and methodInfo['description']: 62 | self.m['details']['description'] = methodInfo['description'] 63 | if 'operationId' in methodInfo and methodInfo['operationId']: 64 | self.m['details']['operationId'] = methodInfo['operationId'] 65 | 66 | self.p['methods'].append(self.m) 67 | 68 | self.allPaths.append(self.p) 69 | 70 | return self.allPaths -------------------------------------------------------------------------------- /src/v5_2/APIGateway.py: -------------------------------------------------------------------------------- 1 | """ 2 | API Gateway support functions 3 | """ 4 | 5 | import json 6 | 7 | import v5_2.GitOps 8 | import v5_2.MiscUtils 9 | from v5_2.OpenAPIParser import OpenAPIParser 10 | 11 | # pydantic models 12 | # pydantic models 13 | from V5_2_NginxConfigDeclaration import * 14 | 15 | 16 | # Builds the declarative JSON for the API Gateway configuration 17 | # Return a tuple: status, description. If status = 200 things were successful 18 | def createAPIGateway(locationDeclaration: dict, authProfiles: Authentication={}): 19 | apiGwDeclaration = {} 20 | 21 | if locationDeclaration['apigateway']['openapi_schema']: 22 | status, apiSchemaString = v5_2.GitOps.getObjectFromRepo(object=locationDeclaration['apigateway']['openapi_schema'], 23 | authProfiles = authProfiles['server'] if 'server' in authProfiles else {}, base64Encode=False) 24 | 25 | if v5_2.MiscUtils.yaml_or_json(apiSchemaString['content']) == 'yaml': 26 | # YAML to JSON conversion 27 | apiSchemaString['content'] = v5_2.MiscUtils.yaml_to_json(apiSchemaString['content']) 28 | 29 | apiSchema = OpenAPIParser(json.loads(apiSchemaString['content'])) 30 | 31 | apiGwDeclaration = {} 32 | apiGwDeclaration['location'] = locationDeclaration 33 | apiGwDeclaration['info'] = apiSchema.info() 34 | apiGwDeclaration['servers'] = apiSchema.servers() 35 | apiGwDeclaration['paths'] = apiSchema.paths() 36 | apiGwDeclaration['version'] = apiSchema.version() 37 | 38 | return 200, apiGwDeclaration, apiSchemaString['content'] -------------------------------------------------------------------------------- /src/v5_2/DevPortal.py: -------------------------------------------------------------------------------- 1 | """ 2 | API Gateway Developer Portal support functions 3 | """ 4 | 5 | import json 6 | import requests 7 | import base64 8 | 9 | # NGINX Declarative API modules 10 | from NcgConfig import NcgConfig 11 | import v5_2.GitOps 12 | import v5_2.MiscUtils 13 | 14 | # pydantic models 15 | from V5_2_NginxConfigDeclaration import * 16 | 17 | def buildDevPortal(openapischema): 18 | try: 19 | response = requests.post(f"http://{NcgConfig.config['devportal']['host']}:" 20 | f"{NcgConfig.config['devportal']['port']}{NcgConfig.config['devportal']['uri']}", 21 | headers={'Content-Type': 'application/json'}, data=openapischema) 22 | except Exception as e: 23 | return 400, "" 24 | 25 | return response.status_code, json.loads(response.text) 26 | 27 | 28 | # Builds the declarative JSON for the API Gateway configuration 29 | # Return a tuple: status, description. If status = 200 things were successful 30 | def createDevPortal(locationDeclaration: dict, authProfiles: Authentication={}): 31 | if locationDeclaration['apigateway']['openapi_schema']: 32 | status, apiSchemaString = v5_2.GitOps.getObjectFromRepo( 33 | object = locationDeclaration['apigateway']['openapi_schema'], authProfiles = authProfiles['server'] if 'server' in authProfiles else {}, base64Encode = False) 34 | 35 | if v5_2.MiscUtils.yaml_or_json(apiSchemaString['content']) == 'yaml': 36 | # YAML to JSON conversion 37 | status, devportalJSON = buildDevPortal(openapischema = v5_2.MiscUtils.yaml_to_json(apiSchemaString['content'])) 38 | else: 39 | status, devportalJSON = buildDevPortal(openapischema = apiSchemaString['content']) 40 | 41 | if status == 200: 42 | devportalHTML = base64.b64encode(bytes(devportalJSON['devportal'], 'utf-8')).decode('utf-8') 43 | else: 44 | devportalHTML = "" 45 | 46 | return status, devportalHTML -------------------------------------------------------------------------------- /src/v5_2/GitOps.py: -------------------------------------------------------------------------------- 1 | """ 2 | GitOps support functions 3 | """ 4 | 5 | import base64 6 | import requests 7 | 8 | from requests import ReadTimeout, HTTPError, Timeout, ConnectionError, ConnectTimeout 9 | 10 | # pydantic models 11 | from V5_2_NginxConfigDeclaration import * 12 | 13 | 14 | # Fetches a URL content 15 | def __fetchfromsourceoftruth__(url, headers = {} ): 16 | # Object is fetched from external repository 17 | 18 | try: 19 | reply = requests.get(url = url, headers = headers, verify=False) 20 | except (ConnectTimeout, HTTPError, ReadTimeout, Timeout, ConnectionError): 21 | return 408, "URL " + url + " unreachable" 22 | 23 | return reply.status_code, reply.text 24 | 25 | 26 | # If content starts with http(s):// fetches the object and return it b64-encoded by default. 27 | # base64Encode to be set to False to disable b64 encoding 28 | # Returns the status original content otherwise. 29 | # Return is a tuple: status_code, content 30 | def getObjectFromRepo(object: ObjectFromSourceOfTruth, authProfiles: Authentication={}, base64Encode: bool=True): 31 | status_code = 200 32 | response = object 33 | 34 | if object: 35 | if object['content'].lower().startswith(("http://","https://")): 36 | # Object is fetched from external repository 37 | headers = {} 38 | 39 | # Set server authentication if needed 40 | if authProfiles and 'server' in authProfiles and len(object['authentication'])>0: 41 | for authP in authProfiles['server']: 42 | if object['authentication'][0]['profile'] == authP['name']: 43 | # Sets up authentication 44 | if authP['type'].lower() == 'token': 45 | 46 | authToken = authP['token']['token'] 47 | authTokenType = authP['token']['type'] 48 | 49 | if authTokenType.lower() == 'bearer': 50 | headers['Authorization'] = f"Bearer {authToken}" 51 | elif authTokenType.lower() == 'basic': 52 | authTokenUsername = authP['token']['username'] 53 | authTokenPassword = base64.b64decode(authP['token']['password']).decode('utf-8') 54 | 55 | headers['Authorization'] = f"Basic {base64.b64encode(str.encode(authTokenUsername + ':' + authTokenPassword)).decode('utf-8')}" 56 | elif authTokenType.lower() == 'header': 57 | authTokenLocation = authP['token']['location'] 58 | 59 | headers[authTokenLocation] = authToken 60 | 61 | status_code, fetchedContent = __fetchfromsourceoftruth__(url = object['content'], headers = headers) 62 | 63 | if status_code == 200: 64 | if base64Encode == True: 65 | fetchedContent = base64.b64encode(bytes(fetchedContent, 'utf-8')).decode('utf-8') 66 | else: 67 | fetchedContent = bytes(fetchedContent, 'utf-8').decode("utf-8") 68 | 69 | response['content'] = fetchedContent 70 | 71 | return status_code, response -------------------------------------------------------------------------------- /src/v5_2/MiscUtils.py: -------------------------------------------------------------------------------- 1 | """ 2 | Support functions 3 | """ 4 | 5 | import re 6 | import json 7 | import yaml 8 | import uuid 9 | import socket 10 | 11 | 12 | # Searches for a nested key in a dictionary and returns its value, or None if nothing was found. 13 | # key_lookup must be a string where each key is deparated by a given "separator" character, which by default is a dot 14 | def getDictKey(_dict: dict, key_lookup: str, separator='.'): 15 | keys = key_lookup.split(separator) 16 | subdict = _dict 17 | 18 | for k in keys: 19 | subdict = subdict[k] if k in subdict else None 20 | if subdict is None: 21 | return None 22 | 23 | return subdict 24 | 25 | # Jinja2 regexp filter 26 | def regex_replace(s, find, replace): 27 | return re.sub(find, replace, s) 28 | 29 | # JSON/YAML detection 30 | def yaml_or_json(document: str): 31 | try: 32 | json.load(document) 33 | return 'json' 34 | except Exception: 35 | return 'yaml' 36 | 37 | # YAML to JSON conversion 38 | def yaml_to_json(document: str): 39 | return json.dumps(yaml.safe_load(document)) 40 | 41 | 42 | # JSON TO YAML conversion 43 | def json_to_yaml(document: str): 44 | return yaml.dump(json.loads(document)) 45 | 46 | 47 | # Returns a unique ID 48 | def getuniqueid(): 49 | return uuid.uuid4() 50 | 51 | 52 | # Test DNS resolution 53 | # Returns {True,IP address} if successful and {False,error description} for NXDOMAIN/if DNS resolution failed 54 | def resolveFQDN(fqdn:str): 55 | try: 56 | return True,socket.gethostbyname(fqdn) 57 | except Exception as e: 58 | return False,e 59 | 60 | -------------------------------------------------------------------------------- /src/v5_2/NGINXOneUtils.py: -------------------------------------------------------------------------------- 1 | """ 2 | NGINX One support functions 3 | """ 4 | 5 | import requests 6 | import json 7 | 8 | 9 | # Fetch a cluster ID from NGINX One 10 | # Return None if not found 11 | def getConfigSyncGroupId(nOneUrl: str, nOneToken: str, nameSpace: str, configSyncGroupName: str): 12 | # Retrieve config sync group uid 13 | cSyncGroup = requests.get(url=f'{nOneUrl}/api/nginx/one/namespaces/{nameSpace}/config-sync-groups', 14 | verify=False, headers = {"Authorization": f"Bearer APIToken {nOneToken}"}) 15 | 16 | if cSyncGroup.status_code != 200: 17 | if cSyncGroup.status_code == 401: 18 | return cSyncGroup.status_code, "NGINX One authentication failed" 19 | else: 20 | return cSyncGroup.status_code, f"Error fetching config sync group uid: {cSyncGroup.text}" 21 | 22 | # Get the instance group id 23 | igUid = None 24 | igJson = json.loads(cSyncGroup.text) 25 | for i in igJson['items']: 26 | if i['name'] == configSyncGroupName: 27 | igUid = i['object_id'] 28 | 29 | if igUid is None: 30 | return 404, f"config sync group [{configSyncGroupName}] not found" 31 | 32 | return 200, igUid 33 | -------------------------------------------------------------------------------- /src/v5_2/NIMUtils.py: -------------------------------------------------------------------------------- 1 | """ 2 | NGINX Instance Manager support functions 3 | """ 4 | 5 | import requests 6 | import json 7 | 8 | 9 | # Fetch an instance group UID from NGINX Instance Manager 10 | # Return None if not found 11 | def getNIMInstanceGroupUid(nmsUrl: str, nmsUsername: str, nmsPassword: str, instanceGroupName: str): 12 | # Retrieve instance group uid 13 | ig = requests.get(url=f'{nmsUrl}/api/platform/v1/instance-groups', auth=(nmsUsername, nmsPassword), 14 | verify=False) 15 | 16 | if ig.status_code != 200: 17 | return None 18 | 19 | # Get the instance group id 20 | igUid = None 21 | igJson = json.loads(ig.text) 22 | for i in igJson['items']: 23 | if i['name'] == instanceGroupName: 24 | igUid = i['uid'] 25 | 26 | return igUid 27 | -------------------------------------------------------------------------------- /src/v5_2/OpenAPIParser.py: -------------------------------------------------------------------------------- 1 | """ 2 | OpenAPI schema parser support functions 3 | """ 4 | 5 | import json 6 | 7 | class OpenAPIParser: 8 | httpMethods = ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'CONNECT', 'OPTIONS', 'TRACE', 'PATCH'] 9 | 10 | def __init__(self, openAPISchema): 11 | self.openAPISchema = openAPISchema 12 | 13 | def version(self): 14 | if 'openapi' in self.openAPISchema: 15 | return self.openAPISchema['openapi'] 16 | elif 'swagger' in self.openAPISchema: 17 | return self.openAPISchema['swagger'] 18 | 19 | return None 20 | 21 | def info(self): 22 | return self.openAPISchema['info'] 23 | 24 | def servers(self): 25 | self.allServers = [] 26 | 27 | # Loop over OpenAPI schema servers 28 | if 'servers' in self.openAPISchema: 29 | for server in self.openAPISchema['servers']: 30 | urlName = server['url'] 31 | self.s = {} 32 | self.s['url'] = urlName 33 | 34 | if 'description' in server: 35 | self.s['description'] = server['description'] 36 | 37 | self.allServers.append(self.s) 38 | 39 | return self.allServers 40 | 41 | def paths(self): 42 | self.allPaths = [] 43 | 44 | # Loop over OpenAPI schema paths 45 | if 'paths' in self.openAPISchema: 46 | for path in self.openAPISchema['paths'].keys(): 47 | #print(f"- {path}") 48 | self.p = {} 49 | self.p['path'] = path 50 | self.p['methods'] = [] 51 | 52 | # Loop over path HTTP methods found in schema 53 | for method in self.openAPISchema['paths'][path].keys(): 54 | methodInfo = self.openAPISchema['paths'][path][method] 55 | 56 | if method.upper() in self.httpMethods: 57 | self.m = {} 58 | self.m['method'] = method 59 | self.m['details'] = {} 60 | 61 | if 'description' in methodInfo and methodInfo['description']: 62 | self.m['details']['description'] = methodInfo['description'] 63 | if 'operationId' in methodInfo and methodInfo['operationId']: 64 | self.m['details']['operationId'] = methodInfo['operationId'] 65 | 66 | self.p['methods'].append(self.m) 67 | 68 | self.allPaths.append(self.p) 69 | 70 | return self.allPaths -------------------------------------------------------------------------------- /src/v5_3/APIGateway.py: -------------------------------------------------------------------------------- 1 | """ 2 | API Gateway support functions 3 | """ 4 | 5 | import json 6 | 7 | import v5_3.GitOps 8 | import v5_3.MiscUtils 9 | from v5_3.OpenAPIParser import OpenAPIParser 10 | 11 | # pydantic models 12 | from V5_3_NginxConfigDeclaration import * 13 | 14 | 15 | # Builds the declarative JSON for the API Gateway configuration 16 | # Return a tuple: status, description. If status = 200 things were successful 17 | def createAPIGateway(locationDeclaration: dict, authProfiles: Authentication={}): 18 | apiGwDeclaration = {} 19 | 20 | if locationDeclaration['apigateway']['openapi_schema']: 21 | status, apiSchemaString = v5_3.GitOps.getObjectFromRepo(object=locationDeclaration['apigateway']['openapi_schema'], 22 | authProfiles = authProfiles['server'] if 'server' in authProfiles else {}, base64Encode=False) 23 | 24 | if v5_3.MiscUtils.yaml_or_json(apiSchemaString['content']) == 'yaml': 25 | # YAML to JSON conversion 26 | apiSchemaString['content'] = v5_3.MiscUtils.yaml_to_json(apiSchemaString['content']) 27 | 28 | apiSchema = OpenAPIParser(json.loads(apiSchemaString['content'])) 29 | 30 | apiGwDeclaration = {} 31 | apiGwDeclaration['location'] = locationDeclaration 32 | apiGwDeclaration['info'] = apiSchema.info() 33 | apiGwDeclaration['servers'] = apiSchema.servers() 34 | apiGwDeclaration['paths'] = apiSchema.paths() 35 | apiGwDeclaration['version'] = apiSchema.version() 36 | 37 | return 200, apiGwDeclaration, apiSchemaString['content'] -------------------------------------------------------------------------------- /src/v5_3/Asynchronous.py: -------------------------------------------------------------------------------- 1 | """" 2 | Asynchronous declarations support 3 | """ 4 | import json 5 | import pickle 6 | 7 | import v5_3.MiscUtils 8 | from NcgRedis import NcgRedis 9 | 10 | # pydantic models 11 | from V5_3_NginxConfigDeclaration import ConfigDeclaration 12 | 13 | # 14 | # Check if the incoming request is asynchronous 15 | # 16 | def checkIfAsynch(declaration: ConfigDeclaration, method: str, apiVersion: str, configUid: str): 17 | djson = declaration.model_dump() 18 | 19 | if djson['output']['synchronous']: 20 | # Synchronous declaration, normal processing 21 | return None, None 22 | 23 | # Asynchronous declaration, submit to FIFO queue 24 | submissionUid = str(v5_3.MiscUtils.getuniqueid()) 25 | submissionPayload = {'declaration': declaration, 'method': method, 'configUid': configUid, "apiVersion": apiVersion, "submissionUid": submissionUid} 26 | NcgRedis.asyncQueue.put(submissionPayload) 27 | 28 | response = {} 29 | response['code'] = 202 30 | response['message'] = f'Declaration submitted' 31 | response['configUid'] = configUid 32 | response['submissionUid'] = submissionUid 33 | 34 | NcgRedis.redis.set(f'ncg.async.submission.{submissionUid}', json.dumps(response)) 35 | 36 | return 202, response -------------------------------------------------------------------------------- /src/v5_3/DevPortal.py: -------------------------------------------------------------------------------- 1 | """ 2 | API Gateway Developer Portal support functions 3 | """ 4 | 5 | import json 6 | import requests 7 | import base64 8 | 9 | # NGINX Declarative API modules 10 | from NcgConfig import NcgConfig 11 | import v5_3.GitOps 12 | import v5_3.MiscUtils 13 | 14 | # pydantic models 15 | from V5_3_NginxConfigDeclaration import * 16 | 17 | def buildDevPortal(openapischema): 18 | try: 19 | response = requests.post(f"http://{NcgConfig.config['devportal']['host']}:" 20 | f"{NcgConfig.config['devportal']['port']}{NcgConfig.config['devportal']['uri']}", 21 | headers={'Content-Type': 'application/json'}, data=openapischema) 22 | except Exception as e: 23 | return 400, "" 24 | 25 | return response.status_code, json.loads(response.text) 26 | 27 | 28 | # Builds the declarative JSON for the API Gateway configuration 29 | # Return a tuple: status, description. If status = 200 things were successful 30 | def createDevPortal(locationDeclaration: dict, authProfiles: Authentication={}): 31 | if locationDeclaration['apigateway']['openapi_schema']: 32 | status, apiSchemaString = v5_3.GitOps.getObjectFromRepo( 33 | object = locationDeclaration['apigateway']['openapi_schema'], authProfiles = authProfiles['server'] if 'server' in authProfiles else {}, base64Encode = False) 34 | 35 | if v5_3.MiscUtils.yaml_or_json(apiSchemaString['content']) == 'yaml': 36 | # YAML to JSON conversion 37 | status, devportalJSON = buildDevPortal(openapischema = v5_3.MiscUtils.yaml_to_json(apiSchemaString['content'])) 38 | else: 39 | status, devportalJSON = buildDevPortal(openapischema = apiSchemaString['content']) 40 | 41 | if status == 200: 42 | devportalHTML = base64.b64encode(bytes(devportalJSON['devportal'], 'utf-8')).decode('utf-8') 43 | else: 44 | devportalHTML = "" 45 | 46 | return status, devportalHTML -------------------------------------------------------------------------------- /src/v5_3/GitOps.py: -------------------------------------------------------------------------------- 1 | """ 2 | GitOps support functions 3 | """ 4 | 5 | import base64 6 | import requests 7 | 8 | from requests import ReadTimeout, HTTPError, Timeout, ConnectionError, ConnectTimeout 9 | 10 | # pydantic models 11 | from V5_3_NginxConfigDeclaration import * 12 | 13 | 14 | # Fetches a URL content 15 | def __fetchfromsourceoftruth__(url, headers = {} ): 16 | # Object is fetched from external repository 17 | 18 | try: 19 | reply = requests.get(url = url, headers = headers, verify=False) 20 | except (ConnectTimeout, HTTPError, ReadTimeout, Timeout, ConnectionError): 21 | return 408, "URL " + url + " unreachable" 22 | 23 | return reply.status_code, reply.text 24 | 25 | 26 | # If content starts with http(s):// fetches the object and return it b64-encoded by default. 27 | # base64Encode to be set to False to disable b64 encoding 28 | # Returns the status original content otherwise. 29 | # Return is a tuple: status_code, content 30 | def getObjectFromRepo(object: ObjectFromSourceOfTruth, authProfiles: Authentication={}, base64Encode: bool=True): 31 | status_code = 200 32 | response = object 33 | 34 | if object: 35 | if object['content'].lower().startswith(("http://","https://")): 36 | # Object is fetched from external repository 37 | headers = {} 38 | 39 | # Set server authentication if needed 40 | if authProfiles and 'server' in authProfiles and len(object['authentication'])>0: 41 | for authP in authProfiles['server']: 42 | if object['authentication'][0]['profile'] == authP['name']: 43 | # Sets up authentication 44 | if authP['type'].lower() == 'token': 45 | 46 | authToken = authP['token']['token'] 47 | authTokenType = authP['token']['type'] 48 | 49 | if authTokenType.lower() == 'bearer': 50 | headers['Authorization'] = f"Bearer {authToken}" 51 | elif authTokenType.lower() == 'basic': 52 | authTokenUsername = authP['token']['username'] 53 | authTokenPassword = base64.b64decode(authP['token']['password']).decode('utf-8') 54 | 55 | headers['Authorization'] = f"Basic {base64.b64encode(str.encode(authTokenUsername + ':' + authTokenPassword)).decode('utf-8')}" 56 | elif authTokenType.lower() == 'header': 57 | authTokenLocation = authP['token']['location'] 58 | 59 | headers[authTokenLocation] = authToken 60 | 61 | status_code, fetchedContent = __fetchfromsourceoftruth__(url = object['content'], headers = headers) 62 | 63 | if status_code == 200: 64 | if base64Encode == True: 65 | fetchedContent = base64.b64encode(bytes(fetchedContent, 'utf-8')).decode('utf-8') 66 | else: 67 | fetchedContent = bytes(fetchedContent, 'utf-8').decode("utf-8") 68 | 69 | response['content'] = fetchedContent 70 | 71 | return status_code, response -------------------------------------------------------------------------------- /src/v5_3/MiscUtils.py: -------------------------------------------------------------------------------- 1 | """ 2 | Support functions 3 | """ 4 | 5 | import re 6 | import json 7 | import yaml 8 | import uuid 9 | import socket 10 | 11 | 12 | # Searches for a nested key in a dictionary and returns its value, or None if nothing was found. 13 | # key_lookup must be a string where each key is deparated by a given "separator" character, which by default is a dot 14 | def getDictKey(_dict: dict, key_lookup: str, separator='.'): 15 | keys = key_lookup.split(separator) 16 | subdict = _dict 17 | 18 | for k in keys: 19 | subdict = subdict[k] if k in subdict else None 20 | if subdict is None: 21 | return None 22 | 23 | return subdict 24 | 25 | # Jinja2 regexp filter 26 | def regex_replace(s, find, replace): 27 | return re.sub(find, replace, s) 28 | 29 | # JSON/YAML detection 30 | def yaml_or_json(document: str): 31 | try: 32 | json.load(document) 33 | return 'json' 34 | except Exception: 35 | return 'yaml' 36 | 37 | # YAML to JSON conversion 38 | def yaml_to_json(document: str): 39 | return json.dumps(yaml.safe_load(document)) 40 | 41 | 42 | # JSON TO YAML conversion 43 | def json_to_yaml(document: str): 44 | return yaml.dump(json.loads(document)) 45 | 46 | 47 | # Returns a unique ID 48 | def getuniqueid(): 49 | return uuid.uuid4() 50 | 51 | 52 | # Test DNS resolution 53 | # Returns {True,IP address} if successful and {False,error description} for NXDOMAIN/if DNS resolution failed 54 | def resolveFQDN(fqdn:str): 55 | try: 56 | return True,socket.gethostbyname(fqdn) 57 | except Exception as e: 58 | return False,e 59 | 60 | -------------------------------------------------------------------------------- /src/v5_3/NGINXOneUtils.py: -------------------------------------------------------------------------------- 1 | """ 2 | NGINX One support functions 3 | """ 4 | 5 | import requests 6 | import json 7 | 8 | 9 | # Fetch a cluster ID from NGINX One 10 | # Return None if not found 11 | def getConfigSyncGroupId(nOneUrl: str, nOneToken: str, nameSpace: str, configSyncGroupName: str): 12 | # Retrieve config sync group uid 13 | cSyncGroup = requests.get(url=f'{nOneUrl}/api/nginx/one/namespaces/{nameSpace}/config-sync-groups?paginated=false', 14 | verify=False, headers = {"Authorization": f"Bearer APIToken {nOneToken}"}) 15 | 16 | if cSyncGroup.status_code != 200: 17 | if cSyncGroup.status_code == 401: 18 | return cSyncGroup.status_code, "NGINX One authentication failed" 19 | else: 20 | return cSyncGroup.status_code, f"Error fetching config sync group uid: {cSyncGroup.text}" 21 | 22 | # Get the instance group id 23 | igUid = None 24 | igJson = json.loads(cSyncGroup.text) 25 | for i in igJson['items']: 26 | if i['name'] == configSyncGroupName: 27 | igUid = i['object_id'] 28 | 29 | if igUid is None: 30 | return 404, f"config sync group [{configSyncGroupName}] not found" 31 | 32 | return 200, igUid 33 | -------------------------------------------------------------------------------- /src/v5_3/NIMUtils.py: -------------------------------------------------------------------------------- 1 | """ 2 | NGINX Instance Manager support functions 3 | """ 4 | 5 | import requests 6 | import json 7 | 8 | 9 | # Fetch an instance group UID from NGINX Instance Manager 10 | # Return None if not found 11 | def getNIMInstanceGroupUid(nmsUrl: str, nmsUsername: str, nmsPassword: str, instanceGroupName: str): 12 | # Retrieve instance group uid 13 | ig = requests.get(url=f'{nmsUrl}/api/platform/v1/instance-groups', auth=(nmsUsername, nmsPassword), 14 | verify=False) 15 | 16 | if ig.status_code != 200: 17 | return None 18 | 19 | # Get the instance group id 20 | igUid = None 21 | igJson = json.loads(ig.text) 22 | for i in igJson['items']: 23 | if i['name'] == instanceGroupName: 24 | igUid = i['uid'] 25 | 26 | return igUid 27 | -------------------------------------------------------------------------------- /src/v5_3/OpenAPIParser.py: -------------------------------------------------------------------------------- 1 | """ 2 | OpenAPI schema parser support functions 3 | """ 4 | 5 | import json 6 | 7 | class OpenAPIParser: 8 | httpMethods = ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'CONNECT', 'OPTIONS', 'TRACE', 'PATCH'] 9 | 10 | def __init__(self, openAPISchema): 11 | self.openAPISchema = openAPISchema 12 | 13 | def version(self): 14 | if 'openapi' in self.openAPISchema: 15 | return self.openAPISchema['openapi'] 16 | elif 'swagger' in self.openAPISchema: 17 | return self.openAPISchema['swagger'] 18 | 19 | return None 20 | 21 | def info(self): 22 | return self.openAPISchema['info'] 23 | 24 | def servers(self): 25 | self.allServers = [] 26 | 27 | # Loop over OpenAPI schema servers 28 | if 'servers' in self.openAPISchema: 29 | for server in self.openAPISchema['servers']: 30 | urlName = server['url'] 31 | self.s = {} 32 | self.s['url'] = urlName 33 | 34 | if 'description' in server: 35 | self.s['description'] = server['description'] 36 | 37 | self.allServers.append(self.s) 38 | 39 | return self.allServers 40 | 41 | def paths(self): 42 | self.allPaths = [] 43 | 44 | # Loop over OpenAPI schema paths 45 | if 'paths' in self.openAPISchema: 46 | for path in self.openAPISchema['paths'].keys(): 47 | #print(f"- {path}") 48 | self.p = {} 49 | self.p['path'] = path 50 | self.p['methods'] = [] 51 | 52 | # Loop over path HTTP methods found in schema 53 | for method in self.openAPISchema['paths'][path].keys(): 54 | methodInfo = self.openAPISchema['paths'][path][method] 55 | 56 | if method.upper() in self.httpMethods: 57 | self.m = {} 58 | self.m['method'] = method 59 | self.m['details'] = {} 60 | 61 | if 'description' in methodInfo and methodInfo['description']: 62 | self.m['details']['description'] = methodInfo['description'] 63 | if 'operationId' in methodInfo and methodInfo['operationId']: 64 | self.m['details']['operationId'] = methodInfo['operationId'] 65 | 66 | self.p['methods'].append(self.m) 67 | 68 | self.allPaths.append(self.p) 69 | 70 | return self.allPaths -------------------------------------------------------------------------------- /templates/v5.1/authn/client/jwks.tmpl: -------------------------------------------------------------------------------- 1 | location = /_auth/jwt/{{ authprofile.name | replace(" ", "_") }}/_jwks_uri { 2 | internal; 3 | 4 | {% if authprofile.jwt.key.startswith('http://') or authprofile.jwt.key.startswith('https://') -%} 5 | proxy_method GET; 6 | proxy_pass {{ authprofile.jwt.key }}; 7 | {% else -%} 8 | return 200 '{{ authprofile.jwt.key }}'; 9 | {%- endif %} 10 | 11 | } 12 | -------------------------------------------------------------------------------- /templates/v5.1/authn/client/jwt.tmpl: -------------------------------------------------------------------------------- 1 | auth_jwt "{{ authprofile.jwt.realm }}"{% if authprofile.jwt.token_location %} token={{ authprofile.jwt.token_location }}{% endif %}; 2 | auth_jwt_type {{ authprofile.jwt.jwt_type }}; 3 | auth_jwt_key_request /_auth/jwt/{{ authprofile.name | replace(" ", "_") }}/_jwks_uri; 4 | {% if authprofile.jwt.cachetime != 0 %} 5 | auth_jwt_key_cache {{ authprofile.jwt.cachetime }}; 6 | {% endif %} 7 | -------------------------------------------------------------------------------- /templates/v5.1/authn/client/mtls.tmpl: -------------------------------------------------------------------------------- 1 | {%- if authprofile.mtls.enabled|lower != "off" -%} 2 | ssl_verify_client {{ authprofile.mtls.enabled }}; 3 | {% if authprofile.mtls.client_certificates -%} 4 | ssl_client_certificate {{ ncgconfig.nms.certs_dir }}/{{ authprofile.mtls.client_certificates }}.crt; 5 | {% endif %} 6 | 7 | {% if authprofile.mtls.trusted_ca_certificates -%} 8 | ssl_trusted_certificate {{ ncgconfig.nms.certs_dir }}/{{ authprofile.mtls.trusted_ca_certificates }}.crt; 9 | {% endif %} 10 | 11 | {# --- OCSP section start --- #} 12 | {%- if authprofile.mtls.ocsp and authprofile.mtls.ocsp.enabled|lower != "off" -%} 13 | ssl_ocsp {{ authprofile.mtls.ocsp.enabled }}; 14 | {% if authprofile.mtls.ocsp.responder -%} 15 | ssl_ocsp_responder {{ authprofile.mtls.ocsp.responder }}; 16 | {% endif %} 17 | {% endif %} 18 | {# --- OCSP section end --- #} 19 | 20 | {# --- TLS stapling section start --- #} 21 | {%- if authprofile.mtls.stapling and authprofile.mtls.stapling.enabled == True -%} 22 | ssl_stapling on; 23 | ssl_stapling_verify {% if authprofile.mtls.stapling.verify == True %}on{% else %}off{% endif %}; 24 | {% if authprofile.mtls.stapling.responder -%} 25 | ssl_stapling_responder {{ authprofile.mtls.stapling.responder }}; 26 | {% endif -%} 27 | {%- endif %} 28 | {# --- TLS stapling section end --- #} 29 | {% endif %} -------------------------------------------------------------------------------- /templates/v5.1/authn/server/mtls.tmpl: -------------------------------------------------------------------------------- 1 | proxy_ssl_certificate {{ ncgconfig.nms.certs_dir }}/{{ authprofile.mtls.certificate }}.crt; 2 | proxy_ssl_certificate_key {{ ncgconfig.nms.certs_dir }}/{{ authprofile.mtls.certificate }}.key; 3 | -------------------------------------------------------------------------------- /templates/v5.1/authn/server/token.tmpl: -------------------------------------------------------------------------------- 1 | {% if authprofile.token.type == "bearer" %} 2 | proxy_set_header Authorization "Bearer {{ authprofile.token.token }}"; 3 | {% elif authprofile.token.type == "basic" %} 4 | proxy_set_header Authorization "Basic {{ (authprofile.token.username + ':' + (authprofile.token.password | b64decode) ) | b64encode }}"; 5 | {% elif authprofile.token.type == "header" %} 6 | proxy_set_header {{ authprofile.token.location }} "{{ authprofile.token.token }}"; 7 | {% endif %} -------------------------------------------------------------------------------- /templates/v5.1/authz/client/jwt-authz-map.tmpl: -------------------------------------------------------------------------------- 1 | {% for claim in authprofile.jwt.claims %} 2 | auth_jwt_claim_set $authz_match_jwt_claim_{{ claim.name }}_{{ authprofile.name | replace(" ", "_") }} {{ claim.name }}; 3 | {% endfor %} 4 | 5 | {% for claim in authprofile.jwt.claims %} 6 | # JWT claim {{ claim.name }} validation for profile "{{ authprofile.name }}" 7 | map $authz_match_jwt_claim_{{ claim.name }}_{{ authprofile.name | replace(" ", "_") }} $jwt_authz_claim_{{ claim.name }}_{{ authprofile.name | replace(" ", "_") }} { 8 | {% for value in claim.value %} 9 | "{{ value }}" 1; 10 | {% endfor %} 11 | default 0; 12 | } 13 | 14 | {% endfor %} -------------------------------------------------------------------------------- /templates/v5.1/authz/client/jwt.tmpl: -------------------------------------------------------------------------------- 1 | {% for claim in authprofile.jwt.claims %} 2 | auth_jwt_require $jwt_authz_claim_{{ claim.name }}_{{ authprofile.name | replace(" ", "_") }} error={{ claim.errorcode }}; 3 | {% endfor %} -------------------------------------------------------------------------------- /templates/v5.1/configmap.tmpl: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: {{ name }} 5 | {% if namespace -%} 6 | namespace: {{ namespace }} 7 | {% endif %} 8 | 9 | data: 10 | {{ filename }}: |- 11 | {% filter indent(width = 4) %} 12 | {{ nginxconfig }} 13 | {% endfilter %} -------------------------------------------------------------------------------- /templates/v5.1/devportal/backstage.tmpl: -------------------------------------------------------------------------------- 1 | apiVersion: backstage.io/v1alpha1 2 | kind: API 3 | metadata: 4 | name: {{ declaration.name }} 5 | annotations: 6 | github.com/project-slug: backstage/backstage 7 | backstage.io/techdocs-ref: dir:. 8 | lighthouse.com/website-url: https://backstage.io 9 | spec: 10 | type: openapi 11 | lifecycle: {{ declaration.lifecycle }} 12 | owner: {{ declaration.owner }} 13 | system: {{ declaration.system }} 14 | definition: | 15 | {% filter indent(width=4) %} 16 | {{ openAPISchema }} 17 | {% endfilter %} -------------------------------------------------------------------------------- /templates/v5.1/logformat.tmpl: -------------------------------------------------------------------------------- 1 | { 2 | "filter": { 3 | "request_type": "{{ log.type }}" 4 | }, 5 | 6 | "content": { 7 | "format": "{{ log.format }}", 8 | "format_string": "{{ log.format_string }}", 9 | "max_request_size": "{{ log.max_request_size }}", 10 | "max_message_size": "{{ log.max_message_size }}" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /templates/v5.1/misc/resolver.tmpl: -------------------------------------------------------------------------------- 1 | # DNS resolver template 2 | 3 | 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 %}; 4 | {% if resolverprofile.timeout %}resolver_timeout {{ resolverprofile.timeout }}{% endif %}; -------------------------------------------------------------------------------- /templates/v5.1/misc/upstream-http.tmpl: -------------------------------------------------------------------------------- 1 | # HTTP upstream template 2 | 3 | {% if u.name %} 4 | {% if u.origin %} 5 | upstream {{ u.name }} { 6 | zone {{ u.name }} 64k; 7 | {% for o in u.origin -%} 8 | 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 %}; 9 | {% endfor %} 10 | 11 | {% if u.sticky and u.sticky.cookie and u.sticky.expires and u.sticky.domain and u.sticky.path -%} 12 | 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 %}; 13 | {% endif -%} 14 | 15 | {% if u.resolver -%} 16 | include "{{ ncgconfig.nms.resolver_dir }}/{{ u.resolver | replace(" ", "_") }}.conf"; 17 | {% endif -%} 18 | 19 | {% if u.snippet and u.snippet.content %}{{ u.snippet.content | b64decode }}{% endif %} 20 | 21 | } 22 | {% endif %} 23 | {% endif %} -------------------------------------------------------------------------------- /templates/v5.1/misc/upstream-stream.tmpl: -------------------------------------------------------------------------------- 1 | # Stream upstream template 2 | 3 | {% if u.name %} 4 | {% if u.origin %} 5 | upstream {{ u.name }} { 6 | zone {{ u.name }} 64k; 7 | {% for o in u.origin -%} 8 | 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 %}; 9 | {% endfor %} 10 | 11 | {% if u.snippet and u.snippet.content %}{{ u.snippet.content }}{% endif %} 12 | 13 | {% if u.resolver -%} 14 | include "{{ ncgconfig.nms.resolver_dir }}/{{ u.resolver | replace(" ", "_") }}.conf"; 15 | {% endif %} 16 | 17 | } 18 | {% endif %} 19 | {% endif %} -------------------------------------------------------------------------------- /templates/v5.1/nginx-conf/mime.types: -------------------------------------------------------------------------------- 1 | types { 2 | text/html html htm shtml; 3 | text/css css; 4 | text/xml xml; 5 | image/gif gif; 6 | image/jpeg jpeg jpg; 7 | application/javascript js; 8 | application/atom+xml atom; 9 | application/rss+xml rss; 10 | 11 | text/mathml mml; 12 | text/plain txt; 13 | text/vnd.sun.j2me.app-descriptor jad; 14 | text/vnd.wap.wml wml; 15 | text/x-component htc; 16 | 17 | image/png png; 18 | image/svg+xml svg svgz; 19 | image/tiff tif tiff; 20 | image/vnd.wap.wbmp wbmp; 21 | image/webp webp; 22 | image/x-icon ico; 23 | image/x-jng jng; 24 | image/x-ms-bmp bmp; 25 | 26 | font/woff woff; 27 | font/woff2 woff2; 28 | 29 | application/java-archive jar war ear; 30 | application/json json; 31 | application/mac-binhex40 hqx; 32 | application/msword doc; 33 | application/pdf pdf; 34 | application/postscript ps eps ai; 35 | application/rtf rtf; 36 | application/vnd.apple.mpegurl m3u8; 37 | application/vnd.google-earth.kml+xml kml; 38 | application/vnd.google-earth.kmz kmz; 39 | application/vnd.ms-excel xls; 40 | application/vnd.ms-fontobject eot; 41 | application/vnd.ms-powerpoint ppt; 42 | application/vnd.oasis.opendocument.graphics odg; 43 | application/vnd.oasis.opendocument.presentation odp; 44 | application/vnd.oasis.opendocument.spreadsheet ods; 45 | application/vnd.oasis.opendocument.text odt; 46 | application/vnd.openxmlformats-officedocument.presentationml.presentation 47 | pptx; 48 | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet 49 | xlsx; 50 | application/vnd.openxmlformats-officedocument.wordprocessingml.document 51 | docx; 52 | application/vnd.wap.wmlc wmlc; 53 | application/wasm wasm; 54 | application/x-7z-compressed 7z; 55 | application/x-cocoa cco; 56 | application/x-java-archive-diff jardiff; 57 | application/x-java-jnlp-file jnlp; 58 | application/x-makeself run; 59 | application/x-perl pl pm; 60 | application/x-pilot prc pdb; 61 | application/x-rar-compressed rar; 62 | application/x-redhat-package-manager rpm; 63 | application/x-sea sea; 64 | application/x-shockwave-flash swf; 65 | application/x-stuffit sit; 66 | application/x-tcl tcl tk; 67 | application/x-x509-ca-cert der pem crt; 68 | application/x-xpinstall xpi; 69 | application/xhtml+xml xhtml; 70 | application/xspf+xml xspf; 71 | application/zip zip; 72 | 73 | application/octet-stream bin exe dll; 74 | application/octet-stream deb; 75 | application/octet-stream dmg; 76 | application/octet-stream iso img; 77 | application/octet-stream msi msp msm; 78 | 79 | audio/midi mid midi kar; 80 | audio/mpeg mp3; 81 | audio/ogg ogg; 82 | audio/x-m4a m4a; 83 | audio/x-realaudio ra; 84 | 85 | video/3gpp 3gpp 3gp; 86 | video/mp2t ts; 87 | video/mp4 mp4; 88 | video/mpeg mpeg mpg; 89 | video/quicktime mov; 90 | video/webm webm; 91 | video/x-flv flv; 92 | video/x-m4v m4v; 93 | video/x-mng mng; 94 | video/x-ms-asf asx asf; 95 | video/x-ms-wmv wmv; 96 | video/x-msvideo avi; 97 | } -------------------------------------------------------------------------------- /templates/v5.1/nginx-conf/nginx.conf: -------------------------------------------------------------------------------- 1 | user nginx; 2 | worker_processes auto; 3 | 4 | error_log /var/log/nginx/error.log notice; 5 | pid /var/run/nginx.pid; 6 | 7 | {% for m in nginxconf.modules %} 8 | load_module modules/{{m}}.so; 9 | {% endfor %} 10 | 11 | events { 12 | worker_connections 1024; 13 | } 14 | 15 | http { 16 | include /etc/nginx/mime.types; 17 | default_type application/octet-stream; 18 | 19 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 20 | '$status $body_bytes_sent "$http_referer" ' 21 | '"$http_user_agent" "$http_x_forwarded_for"'; 22 | 23 | access_log /var/log/nginx/access.log main; 24 | 25 | sendfile on; 26 | #tcp_nopush on; 27 | keepalive_timeout 65; 28 | #gzip on; 29 | include /etc/nginx/conf.d/*.conf; 30 | } 31 | 32 | 33 | # TCP/UDP proxy and load balancing block 34 | stream { 35 | log_format stream-main '$remote_addr [$time_local] ' 36 | '$protocol $status $bytes_sent $bytes_received ' 37 | '$session_time "$ssl_preread_server_name"'; 38 | #access_log /dev/stdout stream-main; 39 | include /etc/nginx/stream-conf.d/*.conf; 40 | } -------------------------------------------------------------------------------- /templates/v5.1/stream.tmpl: -------------------------------------------------------------------------------- 1 | # NGINX configuration file - Stream servers - generated by https://github.com/f5devcentral/NGINX-Declarative-API 2 | 3 | {# --- Upstreams section --- #} 4 | {% if declaration.upstreams %} 5 | {% for u in declaration.upstreams %} 6 | {% if u.name %} 7 | include "{{ ncgconfig.nms.upstream_stream_dir }}/{{ u.name | replace(' ', '_') }}.conf"; 8 | {% endif %} 9 | {% endfor %} 10 | {% endif %} 11 | 12 | {# --- Stream server section --- #} 13 | 14 | {% for s in declaration.servers %} 15 | {%- if s.listen %} 16 | {% if s.listen.address %} 17 | 18 | server { 19 | listen {{ s.listen.address }}{% if s.listen.protocol == "udp" %} {{ s.listen.protocol }}{% endif %}; 20 | status_zone {{ s.name | replace(" ", "_") }}; 21 | {% endif -%} 22 | {% endif -%} 23 | 24 | {% if s.resolver -%} 25 | include "{{ ncgconfig.nms.resolver_dir }}/{{ s.resolver | replace(" ", "_") }}.conf"; 26 | {% endif -%} 27 | 28 | {# --- TLS section --- #} 29 | {%- if s.listen.tls -%} 30 | {%- if s.listen.tls.certificate -%} 31 | ssl_certificate {{ ncgconfig.nms.certs_dir }}/{{ s.listen.tls.certificate }}.crt; 32 | {% endif -%} 33 | {%- if s.listen.tls.key -%} 34 | ssl_certificate_key {{ ncgconfig.nms.certs_dir }}/{{ s.listen.tls.key }}.key; 35 | {% endif -%} 36 | {% if s.listen.tls.ciphers -%} 37 | ssl_ciphers {{ s.listen.tls.ciphers }}; 38 | {% endif -%} 39 | {% if s.listen.tls.protocols -%} 40 | ssl_protocols{% for p in s.listen.tls.protocols %} {{ p }}{% endfor %}; 41 | {% endif %} 42 | {% endif %} 43 | 44 | {% if s.upstream -%} 45 | proxy_pass {{ s.upstream }}; 46 | {% endif %} 47 | 48 | {% if s.snippet and s.snippet.content %}{{ s.snippet.content | b64decode }}{% endif %} 49 | 50 | {%- if s.listen %} 51 | {%- if s.listen.address %} 52 | 53 | } 54 | {% endif -%} 55 | {% endif -%} 56 | 57 | {%- endfor %} 58 | -------------------------------------------------------------------------------- /templates/v5.1/visibility/moesif/http.tmpl: -------------------------------------------------------------------------------- 1 | # Moesif integration - https://www.moesif.com/docs/server-integration/nginx-openresty/ 2 | # URI: {{ loc.uri }} 3 | # application ID: {{ vis.moesif.application_id }} 4 | 5 | lua_shared_dict moesif_conf 5m; 6 | 7 | init_by_lua_block { 8 | local config = ngx.shared.moesif_conf; 9 | config:set("application_id", "{{ vis.moesif.application_id }}") 10 | } 11 | 12 | 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"; 13 | 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"; 14 | 15 | -------------------------------------------------------------------------------- /templates/v5.1/visibility/moesif/server.tmpl: -------------------------------------------------------------------------------- 1 | # Moesif integration - https://www.moesif.com/docs/server-integration/nginx-openresty/ 2 | # URI: {{ loc.uri }} 3 | # application ID: {{ vis.moesif.application_id }} 4 | 5 | # Define the variables Moesif requires 6 | set $moesif_user_id nil; 7 | set $moesif_company_id nil; 8 | set $moesif_req_body nil; 9 | set $moesif_res_body nil; 10 | 11 | # Optionally, set moesif_user_id and moesif_company_id such from a request header or NGINX var to identify customer 12 | header_filter_by_lua_block { 13 | ngx.var.moesif_user_id = ngx.req.get_headers()["X-User-Id"] 14 | ngx.var.moesif_company_id = ngx.req.get_headers()["X-Company-Id"] 15 | } 16 | 17 | # Add Moesif plugin 18 | access_by_lua_file {{ vis.moesif.plugin_path }}/read_req_body.lua; 19 | body_filter_by_lua_file {{ vis.moesif.plugin_path }}/read_res_body.lua; 20 | log_by_lua_file {{ vis.moesif.plugin_path }}/send_event.lua; 21 | 22 | -------------------------------------------------------------------------------- /templates/v5.2/authn/client/jwks.tmpl: -------------------------------------------------------------------------------- 1 | location = /_auth/jwt/{{ authprofile.name | replace(" ", "_") }}/_jwks_uri { 2 | internal; 3 | 4 | {% if authprofile.jwt.key.startswith('http://') or authprofile.jwt.key.startswith('https://') -%} 5 | proxy_method GET; 6 | proxy_pass {{ authprofile.jwt.key }}; 7 | {% else -%} 8 | return 200 '{{ authprofile.jwt.key }}'; 9 | {%- endif %} 10 | 11 | } 12 | -------------------------------------------------------------------------------- /templates/v5.2/authn/client/jwt.tmpl: -------------------------------------------------------------------------------- 1 | auth_jwt "{{ authprofile.jwt.realm }}"{% if authprofile.jwt.token_location %} token={{ authprofile.jwt.token_location }}{% endif %}; 2 | auth_jwt_type {{ authprofile.jwt.jwt_type }}; 3 | auth_jwt_key_request /_auth/jwt/{{ authprofile.name | replace(" ", "_") }}/_jwks_uri; 4 | {% if authprofile.jwt.cachetime != 0 %} 5 | auth_jwt_key_cache {{ authprofile.jwt.cachetime }}; 6 | {% endif %} 7 | -------------------------------------------------------------------------------- /templates/v5.2/authn/client/mtls.tmpl: -------------------------------------------------------------------------------- 1 | {%- if authprofile.mtls.enabled|lower != "off" -%} 2 | ssl_verify_client {{ authprofile.mtls.enabled }}; 3 | {% if authprofile.mtls.client_certificates -%} 4 | ssl_client_certificate {{ ncgconfig.nms.certs_dir }}/{{ authprofile.mtls.client_certificates }}.crt; 5 | {% endif %} 6 | 7 | {% if authprofile.mtls.trusted_ca_certificates -%} 8 | ssl_trusted_certificate {{ ncgconfig.nms.certs_dir }}/{{ authprofile.mtls.trusted_ca_certificates }}.crt; 9 | {% endif %} 10 | 11 | {# --- OCSP section start --- #} 12 | {%- if authprofile.mtls.ocsp and authprofile.mtls.ocsp.enabled|lower != "off" -%} 13 | ssl_ocsp {{ authprofile.mtls.ocsp.enabled }}; 14 | {% if authprofile.mtls.ocsp.responder -%} 15 | ssl_ocsp_responder {{ authprofile.mtls.ocsp.responder }}; 16 | {% endif %} 17 | {% endif %} 18 | {# --- OCSP section end --- #} 19 | 20 | {# --- TLS stapling section start --- #} 21 | {%- if authprofile.mtls.stapling and authprofile.mtls.stapling.enabled == True -%} 22 | ssl_stapling on; 23 | ssl_stapling_verify {% if authprofile.mtls.stapling.verify == True %}on{% else %}off{% endif %}; 24 | {% if authprofile.mtls.stapling.responder -%} 25 | ssl_stapling_responder {{ authprofile.mtls.stapling.responder }}; 26 | {% endif -%} 27 | {%- endif %} 28 | {# --- TLS stapling section end --- #} 29 | {% endif %} -------------------------------------------------------------------------------- /templates/v5.2/authn/server/mtls.tmpl: -------------------------------------------------------------------------------- 1 | proxy_ssl_certificate {{ ncgconfig.nms.certs_dir }}/{{ authprofile.mtls.certificate }}.crt; 2 | proxy_ssl_certificate_key {{ ncgconfig.nms.certs_dir }}/{{ authprofile.mtls.certificate }}.key; 3 | -------------------------------------------------------------------------------- /templates/v5.2/authn/server/token.tmpl: -------------------------------------------------------------------------------- 1 | {% if authprofile.token.type == "bearer" %} 2 | proxy_set_header Authorization "Bearer {{ authprofile.token.token }}"; 3 | {% elif authprofile.token.type == "basic" %} 4 | proxy_set_header Authorization "Basic {{ (authprofile.token.username + ':' + (authprofile.token.password | b64decode) ) | b64encode }}"; 5 | {% elif authprofile.token.type == "header" %} 6 | proxy_set_header {{ authprofile.token.location }} "{{ authprofile.token.token }}"; 7 | {% endif %} -------------------------------------------------------------------------------- /templates/v5.2/authz/client/jwt-authz-map.tmpl: -------------------------------------------------------------------------------- 1 | {% for claim in authprofile.jwt.claims %} 2 | auth_jwt_claim_set $authz_match_jwt_claim_{{ claim.name }}_{{ authprofile.name | replace(" ", "_") }} {{ claim.name }}; 3 | {% endfor %} 4 | 5 | {% for claim in authprofile.jwt.claims %} 6 | # JWT claim {{ claim.name }} validation for profile "{{ authprofile.name }}" 7 | map $authz_match_jwt_claim_{{ claim.name }}_{{ authprofile.name | replace(" ", "_") }} $jwt_authz_claim_{{ claim.name }}_{{ authprofile.name | replace(" ", "_") }} { 8 | {% for value in claim.value %} 9 | "{{ value }}" 1; 10 | {% endfor %} 11 | default 0; 12 | } 13 | 14 | {% endfor %} -------------------------------------------------------------------------------- /templates/v5.2/authz/client/jwt.tmpl: -------------------------------------------------------------------------------- 1 | {% for claim in authprofile.jwt.claims %} 2 | auth_jwt_require $jwt_authz_claim_{{ claim.name }}_{{ authprofile.name | replace(" ", "_") }} error={{ claim.errorcode }}; 3 | {% endfor %} -------------------------------------------------------------------------------- /templates/v5.2/devportal/backstage.tmpl: -------------------------------------------------------------------------------- 1 | apiVersion: backstage.io/v1alpha1 2 | kind: API 3 | metadata: 4 | name: {{ declaration.name }} 5 | annotations: 6 | github.com/project-slug: backstage/backstage 7 | backstage.io/techdocs-ref: dir:. 8 | lighthouse.com/website-url: https://backstage.io 9 | spec: 10 | type: openapi 11 | lifecycle: {{ declaration.lifecycle }} 12 | owner: {{ declaration.owner }} 13 | system: {{ declaration.system }} 14 | definition: | 15 | {% filter indent(width=4) %} 16 | {{ openAPISchema }} 17 | {% endfilter %} -------------------------------------------------------------------------------- /templates/v5.2/logformat.tmpl: -------------------------------------------------------------------------------- 1 | { 2 | "filter": { 3 | "request_type": "{{ log.type }}" 4 | }, 5 | 6 | "content": { 7 | "format": "{{ log.format }}", 8 | "format_string": "{{ log.format_string }}", 9 | "max_request_size": "{{ log.max_request_size }}", 10 | "max_message_size": "{{ log.max_message_size }}" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /templates/v5.2/misc/resolver.tmpl: -------------------------------------------------------------------------------- 1 | # DNS resolver template 2 | 3 | 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 %}; 4 | {% if resolverprofile.timeout %}resolver_timeout {{ resolverprofile.timeout }}{% endif %}; -------------------------------------------------------------------------------- /templates/v5.2/misc/upstream-http.tmpl: -------------------------------------------------------------------------------- 1 | # HTTP upstream template 2 | 3 | {% if u.name %} 4 | {% if u.origin %} 5 | upstream {{ u.name }} { 6 | zone {{ u.name }} 64k; 7 | {% for o in u.origin -%} 8 | 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 %}; 9 | {% endfor %} 10 | 11 | {% if u.sticky and u.sticky.cookie and u.sticky.expires and u.sticky.domain and u.sticky.path -%} 12 | 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 %}; 13 | {% endif -%} 14 | 15 | {% if u.resolver -%} 16 | include "{{ ncgconfig.nms.resolver_dir }}/{{ u.resolver | replace(" ", "_") }}.conf"; 17 | {% endif -%} 18 | 19 | {% if u.snippet and u.snippet.content %}{{ u.snippet.content | b64decode }}{% endif %} 20 | 21 | } 22 | {% endif %} 23 | {% endif %} -------------------------------------------------------------------------------- /templates/v5.2/misc/upstream-stream.tmpl: -------------------------------------------------------------------------------- 1 | # Stream upstream template 2 | 3 | {% if u.name %} 4 | {% if u.origin %} 5 | upstream {{ u.name }} { 6 | zone {{ u.name }} 64k; 7 | {% for o in u.origin -%} 8 | 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 %}; 9 | {% endfor %} 10 | 11 | {% if u.snippet and u.snippet.content %}{{ u.snippet.content }}{% endif %} 12 | 13 | {% if u.resolver -%} 14 | include "{{ ncgconfig.nms.resolver_dir }}/{{ u.resolver | replace(" ", "_") }}.conf"; 15 | {% endif %} 16 | 17 | } 18 | {% endif %} 19 | {% endif %} -------------------------------------------------------------------------------- /templates/v5.2/nginx-conf/license-key.tmpl: -------------------------------------------------------------------------------- 1 | {{ nginxconf.license.token }} -------------------------------------------------------------------------------- /templates/v5.2/nginx-conf/mime.types: -------------------------------------------------------------------------------- 1 | types { 2 | text/html html htm shtml; 3 | text/css css; 4 | text/xml xml; 5 | image/gif gif; 6 | image/jpeg jpeg jpg; 7 | application/javascript js; 8 | application/atom+xml atom; 9 | application/rss+xml rss; 10 | 11 | text/mathml mml; 12 | text/plain txt; 13 | text/vnd.sun.j2me.app-descriptor jad; 14 | text/vnd.wap.wml wml; 15 | text/x-component htc; 16 | 17 | image/png png; 18 | image/svg+xml svg svgz; 19 | image/tiff tif tiff; 20 | image/vnd.wap.wbmp wbmp; 21 | image/webp webp; 22 | image/x-icon ico; 23 | image/x-jng jng; 24 | image/x-ms-bmp bmp; 25 | 26 | font/woff woff; 27 | font/woff2 woff2; 28 | 29 | application/java-archive jar war ear; 30 | application/json json; 31 | application/mac-binhex40 hqx; 32 | application/msword doc; 33 | application/pdf pdf; 34 | application/postscript ps eps ai; 35 | application/rtf rtf; 36 | application/vnd.apple.mpegurl m3u8; 37 | application/vnd.google-earth.kml+xml kml; 38 | application/vnd.google-earth.kmz kmz; 39 | application/vnd.ms-excel xls; 40 | application/vnd.ms-fontobject eot; 41 | application/vnd.ms-powerpoint ppt; 42 | application/vnd.oasis.opendocument.graphics odg; 43 | application/vnd.oasis.opendocument.presentation odp; 44 | application/vnd.oasis.opendocument.spreadsheet ods; 45 | application/vnd.oasis.opendocument.text odt; 46 | application/vnd.openxmlformats-officedocument.presentationml.presentation 47 | pptx; 48 | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet 49 | xlsx; 50 | application/vnd.openxmlformats-officedocument.wordprocessingml.document 51 | docx; 52 | application/vnd.wap.wmlc wmlc; 53 | application/wasm wasm; 54 | application/x-7z-compressed 7z; 55 | application/x-cocoa cco; 56 | application/x-java-archive-diff jardiff; 57 | application/x-java-jnlp-file jnlp; 58 | application/x-makeself run; 59 | application/x-perl pl pm; 60 | application/x-pilot prc pdb; 61 | application/x-rar-compressed rar; 62 | application/x-redhat-package-manager rpm; 63 | application/x-sea sea; 64 | application/x-shockwave-flash swf; 65 | application/x-stuffit sit; 66 | application/x-tcl tcl tk; 67 | application/x-x509-ca-cert der pem crt; 68 | application/x-xpinstall xpi; 69 | application/xhtml+xml xhtml; 70 | application/xspf+xml xspf; 71 | application/zip zip; 72 | 73 | application/octet-stream bin exe dll; 74 | application/octet-stream deb; 75 | application/octet-stream dmg; 76 | application/octet-stream iso img; 77 | application/octet-stream msi msp msm; 78 | 79 | audio/midi mid midi kar; 80 | audio/mpeg mp3; 81 | audio/ogg ogg; 82 | audio/x-m4a m4a; 83 | audio/x-realaudio ra; 84 | 85 | video/3gpp 3gpp 3gp; 86 | video/mp2t ts; 87 | video/mp4 mp4; 88 | video/mpeg mpeg mpg; 89 | video/quicktime mov; 90 | video/webm webm; 91 | video/x-flv flv; 92 | video/x-m4v m4v; 93 | video/x-mng mng; 94 | video/x-ms-asf asx asf; 95 | video/x-ms-wmv wmv; 96 | video/x-msvideo avi; 97 | } -------------------------------------------------------------------------------- /templates/v5.2/nginx-conf/nginx.conf: -------------------------------------------------------------------------------- 1 | user nginx; 2 | worker_processes auto; 3 | 4 | error_log /var/log/nginx/error.log notice; 5 | pid /var/run/nginx.pid; 6 | 7 | {% for m in nginxconf.modules %} 8 | load_module modules/{{m}}.so; 9 | {% endfor %} 10 | 11 | events { 12 | worker_connections 1024; 13 | } 14 | 15 | http { 16 | include /etc/nginx/mime.types; 17 | default_type application/octet-stream; 18 | 19 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 20 | '$status $body_bytes_sent "$http_referer" ' 21 | '"$http_user_agent" "$http_x_forwarded_for"'; 22 | 23 | access_log /var/log/nginx/access.log main; 24 | 25 | sendfile on; 26 | #tcp_nopush on; 27 | keepalive_timeout 65; 28 | #gzip on; 29 | include /etc/nginx/conf.d/*.conf; 30 | } 31 | 32 | # TCP/UDP proxy and load balancing block 33 | stream { 34 | log_format stream-main '$remote_addr [$time_local] ' 35 | '$protocol $status $bytes_sent $bytes_received ' 36 | '$session_time "$ssl_preread_server_name"'; 37 | #access_log /dev/stdout stream-main; 38 | include /etc/nginx/stream-conf.d/*.conf; 39 | } 40 | 41 | {% if nginxconf.license %} 42 | # NGINX R33+ license 43 | mgmt { 44 | # Default reporting sent to product.connect.nginx.com 45 | usage_report endpoint={{ nginxconf.license.endpoint }}; 46 | license_token /etc/nginx/license.jwt; 47 | 48 | # Set to 'off' to begin the 180-day reporting enforcement grace period. 49 | # Reporting must begin or resume before the end of the grace period 50 | # to ensure continued operation. 51 | enforce_initial_report {% if nginxconf.license.grace_period == False %}on{% else %}off{% endif %}; 52 | 53 | # Set to 'off' to trust all SSL certificates (not recommended). 54 | # Useful for reporting to NGINX Instance Manager without a local PKI. 55 | ssl_verify {% if nginxconf.license.ssl_verify == True %}on{% else %}off{% endif %}; 56 | } 57 | {% endif %} -------------------------------------------------------------------------------- /templates/v5.2/stream.tmpl: -------------------------------------------------------------------------------- 1 | # NGINX configuration file - Stream servers - generated by https://github.com/f5devcentral/NGINX-Declarative-API 2 | 3 | {# --- Upstreams section --- #} 4 | {% if declaration.upstreams %} 5 | {% for u in declaration.upstreams %} 6 | {% if u.name %} 7 | include "{{ ncgconfig.nms.upstream_stream_dir }}/{{ u.name | replace(' ', '_') }}.conf"; 8 | {% endif %} 9 | {% endfor %} 10 | {% endif %} 11 | 12 | {# --- Stream server section --- #} 13 | 14 | {% for s in declaration.servers %} 15 | {%- if s.listen %} 16 | {% if s.listen.address %} 17 | 18 | server { 19 | listen {{ s.listen.address }}{% if s.listen.protocol == "udp" %} {{ s.listen.protocol }}{% endif %}; 20 | status_zone {{ s.name | replace(" ", "_") }}; 21 | {% endif -%} 22 | {% endif -%} 23 | 24 | {% if s.resolver -%} 25 | include "{{ ncgconfig.nms.resolver_dir }}/{{ s.resolver | replace(" ", "_") }}.conf"; 26 | {% endif -%} 27 | 28 | {# --- TLS section --- #} 29 | {%- if s.listen.tls -%} 30 | {%- if s.listen.tls.certificate -%} 31 | ssl_certificate {{ ncgconfig.nms.certs_dir }}/{{ s.listen.tls.certificate }}.crt; 32 | {% endif -%} 33 | {%- if s.listen.tls.key -%} 34 | ssl_certificate_key {{ ncgconfig.nms.certs_dir }}/{{ s.listen.tls.key }}.key; 35 | {% endif -%} 36 | {% if s.listen.tls.ciphers -%} 37 | ssl_ciphers {{ s.listen.tls.ciphers }}; 38 | {% endif -%} 39 | {% if s.listen.tls.protocols -%} 40 | ssl_protocols{% for p in s.listen.tls.protocols %} {{ p }}{% endfor %}; 41 | {% endif %} 42 | {% endif %} 43 | 44 | {% if s.upstream -%} 45 | proxy_pass {{ s.upstream }}; 46 | {% endif %} 47 | 48 | {% if s.snippet and s.snippet.content %}{{ s.snippet.content | b64decode }}{% endif %} 49 | 50 | {%- if s.listen %} 51 | {%- if s.listen.address %} 52 | 53 | } 54 | {% endif -%} 55 | {% endif -%} 56 | 57 | {%- endfor %} 58 | -------------------------------------------------------------------------------- /templates/v5.2/visibility/moesif/http.tmpl: -------------------------------------------------------------------------------- 1 | # Moesif integration - https://www.moesif.com/docs/server-integration/nginx-openresty/ 2 | # URI: {{ loc.uri }} 3 | # application ID: {{ vis.moesif.application_id }} 4 | 5 | lua_shared_dict moesif_conf 5m; 6 | 7 | init_by_lua_block { 8 | local config = ngx.shared.moesif_conf; 9 | config:set("application_id", "{{ vis.moesif.application_id }}") 10 | } 11 | 12 | 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"; 13 | 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"; 14 | 15 | -------------------------------------------------------------------------------- /templates/v5.2/visibility/moesif/server.tmpl: -------------------------------------------------------------------------------- 1 | # Moesif integration - https://www.moesif.com/docs/server-integration/nginx-openresty/ 2 | # URI: {{ loc.uri }} 3 | # application ID: {{ vis.moesif.application_id }} 4 | 5 | # Define the variables Moesif requires 6 | set $moesif_user_id nil; 7 | set $moesif_company_id nil; 8 | set $moesif_req_body nil; 9 | set $moesif_res_body nil; 10 | 11 | # Optionally, set moesif_user_id and moesif_company_id such from a request header or NGINX var to identify customer 12 | header_filter_by_lua_block { 13 | ngx.var.moesif_user_id = ngx.req.get_headers()["X-User-Id"] 14 | ngx.var.moesif_company_id = ngx.req.get_headers()["X-Company-Id"] 15 | } 16 | 17 | # Add Moesif plugin 18 | access_by_lua_file {{ vis.moesif.plugin_path }}/read_req_body.lua; 19 | body_filter_by_lua_file {{ vis.moesif.plugin_path }}/read_res_body.lua; 20 | log_by_lua_file {{ vis.moesif.plugin_path }}/send_event.lua; 21 | 22 | -------------------------------------------------------------------------------- /templates/v5.3/authn/client/jwks.tmpl: -------------------------------------------------------------------------------- 1 | location = /_auth/jwt/{{ authprofile.name | replace(" ", "_") }}/_jwks_uri { 2 | internal; 3 | 4 | {% if authprofile.jwt.key.startswith('http://') or authprofile.jwt.key.startswith('https://') -%} 5 | proxy_method GET; 6 | proxy_pass {{ authprofile.jwt.key }}; 7 | {% else -%} 8 | return 200 '{{ authprofile.jwt.key }}'; 9 | {%- endif %} 10 | 11 | } 12 | -------------------------------------------------------------------------------- /templates/v5.3/authn/client/jwt.tmpl: -------------------------------------------------------------------------------- 1 | auth_jwt "{{ authprofile.jwt.realm }}"{% if authprofile.jwt.token_location %} token={{ authprofile.jwt.token_location }}{% endif %}; 2 | auth_jwt_type {{ authprofile.jwt.jwt_type }}; 3 | auth_jwt_key_request /_auth/jwt/{{ authprofile.name | replace(" ", "_") }}/_jwks_uri; 4 | {% if authprofile.jwt.cachetime != 0 %} 5 | auth_jwt_key_cache {{ authprofile.jwt.cachetime }}; 6 | {% endif %} 7 | -------------------------------------------------------------------------------- /templates/v5.3/authn/client/mtls.tmpl: -------------------------------------------------------------------------------- 1 | {%- if authprofile.mtls.enabled|lower != "off" -%} 2 | ssl_verify_client {{ authprofile.mtls.enabled }}; 3 | {% if authprofile.mtls.client_certificates -%} 4 | ssl_client_certificate {{ ncgconfig.nms.certs_dir }}/{{ authprofile.mtls.client_certificates }}.crt; 5 | {% endif %} 6 | 7 | {% if authprofile.mtls.trusted_ca_certificates -%} 8 | ssl_trusted_certificate {{ ncgconfig.nms.certs_dir }}/{{ authprofile.mtls.trusted_ca_certificates }}.crt; 9 | {% endif %} 10 | 11 | {# --- OCSP section start --- #} 12 | {%- if authprofile.mtls.ocsp and authprofile.mtls.ocsp.enabled|lower != "off" -%} 13 | ssl_ocsp {{ authprofile.mtls.ocsp.enabled }}; 14 | {% if authprofile.mtls.ocsp.responder -%} 15 | ssl_ocsp_responder {{ authprofile.mtls.ocsp.responder }}; 16 | {% endif %} 17 | {% endif %} 18 | {# --- OCSP section end --- #} 19 | 20 | {# --- TLS stapling section start --- #} 21 | {%- if authprofile.mtls.stapling and authprofile.mtls.stapling.enabled == True -%} 22 | ssl_stapling on; 23 | ssl_stapling_verify {% if authprofile.mtls.stapling.verify == True %}on{% else %}off{% endif %}; 24 | {% if authprofile.mtls.stapling.responder -%} 25 | ssl_stapling_responder {{ authprofile.mtls.stapling.responder }}; 26 | {% endif -%} 27 | {%- endif %} 28 | {# --- TLS stapling section end --- #} 29 | {% endif %} -------------------------------------------------------------------------------- /templates/v5.3/authn/server/mtls.tmpl: -------------------------------------------------------------------------------- 1 | proxy_ssl_certificate {{ ncgconfig.nms.certs_dir }}/{{ authprofile.mtls.certificate }}.crt; 2 | proxy_ssl_certificate_key {{ ncgconfig.nms.certs_dir }}/{{ authprofile.mtls.certificate }}.key; 3 | -------------------------------------------------------------------------------- /templates/v5.3/authn/server/token.tmpl: -------------------------------------------------------------------------------- 1 | {% if authprofile.token.type == "bearer" %} 2 | proxy_set_header Authorization "Bearer {{ authprofile.token.token }}"; 3 | {% elif authprofile.token.type == "basic" %} 4 | proxy_set_header Authorization "Basic {{ (authprofile.token.username + ':' + (authprofile.token.password | b64decode) ) | b64encode }}"; 5 | {% elif authprofile.token.type == "header" %} 6 | proxy_set_header {{ authprofile.token.location }} "{{ authprofile.token.token }}"; 7 | {% endif %} -------------------------------------------------------------------------------- /templates/v5.3/authz/client/jwt-authz-map.tmpl: -------------------------------------------------------------------------------- 1 | {% for claim in authprofile.jwt.claims %} 2 | auth_jwt_claim_set $authz_match_jwt_claim_{{ claim.name }}_{{ authprofile.name | replace(" ", "_") }} {{ claim.name }}; 3 | {% endfor %} 4 | 5 | {% for claim in authprofile.jwt.claims %} 6 | # JWT claim {{ claim.name }} validation for profile "{{ authprofile.name }}" 7 | map $authz_match_jwt_claim_{{ claim.name }}_{{ authprofile.name | replace(" ", "_") }} $jwt_authz_claim_{{ claim.name }}_{{ authprofile.name | replace(" ", "_") }} { 8 | {% for value in claim.value %} 9 | "{{ value }}" 1; 10 | {% endfor %} 11 | default 0; 12 | } 13 | 14 | {% endfor %} -------------------------------------------------------------------------------- /templates/v5.3/authz/client/jwt.tmpl: -------------------------------------------------------------------------------- 1 | {% for claim in authprofile.jwt.claims %} 2 | auth_jwt_require $jwt_authz_claim_{{ claim.name }}_{{ authprofile.name | replace(" ", "_") }} error={{ claim.errorcode }}; 3 | {% endfor %} -------------------------------------------------------------------------------- /templates/v5.3/devportal/backstage.tmpl: -------------------------------------------------------------------------------- 1 | apiVersion: backstage.io/v1alpha1 2 | kind: API 3 | metadata: 4 | name: {{ declaration.name }} 5 | annotations: 6 | github.com/project-slug: backstage/backstage 7 | backstage.io/techdocs-ref: dir:. 8 | lighthouse.com/website-url: https://backstage.io 9 | spec: 10 | type: openapi 11 | lifecycle: {{ declaration.lifecycle }} 12 | owner: {{ declaration.owner }} 13 | system: {{ declaration.system }} 14 | definition: | 15 | {% filter indent(width=4) %} 16 | {{ openAPISchema }} 17 | {% endfilter %} -------------------------------------------------------------------------------- /templates/v5.3/logformat.tmpl: -------------------------------------------------------------------------------- 1 | { 2 | "filter": { 3 | "request_type": "{{ log.type }}" 4 | }, 5 | 6 | "content": { 7 | "format": "{{ log.format }}", 8 | "format_string": "{{ log.format_string }}", 9 | "max_request_size": "{{ log.max_request_size }}", 10 | "max_message_size": "{{ log.max_message_size }}" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /templates/v5.3/misc/resolver.tmpl: -------------------------------------------------------------------------------- 1 | # DNS resolver template 2 | 3 | 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 %}; 4 | {% if resolverprofile.timeout %}resolver_timeout {{ resolverprofile.timeout }}{% endif %}; -------------------------------------------------------------------------------- /templates/v5.3/misc/upstream-http.tmpl: -------------------------------------------------------------------------------- 1 | # HTTP upstream template 2 | 3 | {% if u.name %} 4 | {% if u.origin %} 5 | upstream {{ u.name }} { 6 | zone {{ u.name }} 64k; 7 | {% for o in u.origin -%} 8 | 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 %}; 9 | {% endfor %} 10 | 11 | {% if u.sticky and u.sticky.cookie and u.sticky.expires and u.sticky.domain and u.sticky.path -%} 12 | 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 %}; 13 | {% endif -%} 14 | 15 | {% if u.resolver -%} 16 | include "{{ ncgconfig.nms.resolver_dir }}/{{ u.resolver | replace(" ", "_") }}.conf"; 17 | {% endif -%} 18 | 19 | {% if u.snippet and u.snippet.content %}{{ u.snippet.content | b64decode }}{% endif %} 20 | 21 | } 22 | {% endif %} 23 | {% endif %} -------------------------------------------------------------------------------- /templates/v5.3/misc/upstream-stream.tmpl: -------------------------------------------------------------------------------- 1 | # Stream upstream template 2 | 3 | {% if u.name %} 4 | {% if u.origin %} 5 | upstream {{ u.name }} { 6 | zone {{ u.name }} 64k; 7 | {% for o in u.origin -%} 8 | 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 %}; 9 | {% endfor %} 10 | 11 | {% if u.snippet and u.snippet.content %}{{ u.snippet.content }}{% endif %} 12 | 13 | {% if u.resolver -%} 14 | include "{{ ncgconfig.nms.resolver_dir }}/{{ u.resolver | replace(" ", "_") }}.conf"; 15 | {% endif %} 16 | 17 | } 18 | {% endif %} 19 | {% endif %} -------------------------------------------------------------------------------- /templates/v5.3/nginx-conf/license-key.tmpl: -------------------------------------------------------------------------------- 1 | {{ nginxconf.license.token }} -------------------------------------------------------------------------------- /templates/v5.3/nginx-conf/mime.types: -------------------------------------------------------------------------------- 1 | types { 2 | text/html html htm shtml; 3 | text/css css; 4 | text/xml xml; 5 | image/gif gif; 6 | image/jpeg jpeg jpg; 7 | application/javascript js; 8 | application/atom+xml atom; 9 | application/rss+xml rss; 10 | 11 | text/mathml mml; 12 | text/plain txt; 13 | text/vnd.sun.j2me.app-descriptor jad; 14 | text/vnd.wap.wml wml; 15 | text/x-component htc; 16 | 17 | image/png png; 18 | image/svg+xml svg svgz; 19 | image/tiff tif tiff; 20 | image/vnd.wap.wbmp wbmp; 21 | image/webp webp; 22 | image/x-icon ico; 23 | image/x-jng jng; 24 | image/x-ms-bmp bmp; 25 | 26 | font/woff woff; 27 | font/woff2 woff2; 28 | 29 | application/java-archive jar war ear; 30 | application/json json; 31 | application/mac-binhex40 hqx; 32 | application/msword doc; 33 | application/pdf pdf; 34 | application/postscript ps eps ai; 35 | application/rtf rtf; 36 | application/vnd.apple.mpegurl m3u8; 37 | application/vnd.google-earth.kml+xml kml; 38 | application/vnd.google-earth.kmz kmz; 39 | application/vnd.ms-excel xls; 40 | application/vnd.ms-fontobject eot; 41 | application/vnd.ms-powerpoint ppt; 42 | application/vnd.oasis.opendocument.graphics odg; 43 | application/vnd.oasis.opendocument.presentation odp; 44 | application/vnd.oasis.opendocument.spreadsheet ods; 45 | application/vnd.oasis.opendocument.text odt; 46 | application/vnd.openxmlformats-officedocument.presentationml.presentation 47 | pptx; 48 | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet 49 | xlsx; 50 | application/vnd.openxmlformats-officedocument.wordprocessingml.document 51 | docx; 52 | application/vnd.wap.wmlc wmlc; 53 | application/wasm wasm; 54 | application/x-7z-compressed 7z; 55 | application/x-cocoa cco; 56 | application/x-java-archive-diff jardiff; 57 | application/x-java-jnlp-file jnlp; 58 | application/x-makeself run; 59 | application/x-perl pl pm; 60 | application/x-pilot prc pdb; 61 | application/x-rar-compressed rar; 62 | application/x-redhat-package-manager rpm; 63 | application/x-sea sea; 64 | application/x-shockwave-flash swf; 65 | application/x-stuffit sit; 66 | application/x-tcl tcl tk; 67 | application/x-x509-ca-cert der pem crt; 68 | application/x-xpinstall xpi; 69 | application/xhtml+xml xhtml; 70 | application/xspf+xml xspf; 71 | application/zip zip; 72 | 73 | application/octet-stream bin exe dll; 74 | application/octet-stream deb; 75 | application/octet-stream dmg; 76 | application/octet-stream iso img; 77 | application/octet-stream msi msp msm; 78 | 79 | audio/midi mid midi kar; 80 | audio/mpeg mp3; 81 | audio/ogg ogg; 82 | audio/x-m4a m4a; 83 | audio/x-realaudio ra; 84 | 85 | video/3gpp 3gpp 3gp; 86 | video/mp2t ts; 87 | video/mp4 mp4; 88 | video/mpeg mpeg mpg; 89 | video/quicktime mov; 90 | video/webm webm; 91 | video/x-flv flv; 92 | video/x-m4v m4v; 93 | video/x-mng mng; 94 | video/x-ms-asf asx asf; 95 | video/x-ms-wmv wmv; 96 | video/x-msvideo avi; 97 | } -------------------------------------------------------------------------------- /templates/v5.3/nginx-conf/nginx.conf: -------------------------------------------------------------------------------- 1 | user nginx; 2 | worker_processes auto; 3 | 4 | error_log /var/log/nginx/error.log notice; 5 | pid /var/run/nginx.pid; 6 | 7 | {% for m in nginxconf.modules %} 8 | load_module modules/{{m}}.so; 9 | {% endfor %} 10 | 11 | events { 12 | worker_connections 1024; 13 | } 14 | 15 | http { 16 | include /etc/nginx/mime.types; 17 | default_type application/octet-stream; 18 | 19 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 20 | '$status $body_bytes_sent "$http_referer" ' 21 | '"$http_user_agent" "$http_x_forwarded_for"'; 22 | 23 | access_log /var/log/nginx/access.log main; 24 | 25 | sendfile on; 26 | #tcp_nopush on; 27 | keepalive_timeout 65; 28 | #gzip on; 29 | include /etc/nginx/conf.d/*.conf; 30 | } 31 | 32 | # TCP/UDP proxy and load balancing block 33 | stream { 34 | log_format stream-main '$remote_addr [$time_local] ' 35 | '$protocol $status $bytes_sent $bytes_received ' 36 | '$session_time "$ssl_preread_server_name"'; 37 | #access_log /dev/stdout stream-main; 38 | include /etc/nginx/stream-conf.d/*.conf; 39 | } 40 | 41 | {% if nginxconf.license %} 42 | # NGINX R33+ license 43 | mgmt { 44 | # Default reporting sent to product.connect.nginx.com 45 | usage_report endpoint={{ nginxconf.license.endpoint }}; 46 | license_token /etc/nginx/license.jwt; 47 | 48 | # Set to 'off' to begin the 180-day reporting enforcement grace period. 49 | # Reporting must begin or resume before the end of the grace period 50 | # to ensure continued operation. 51 | enforce_initial_report {% if nginxconf.license.grace_period == False %}on{% else %}off{% endif %}; 52 | 53 | # Set to 'off' to trust all SSL certificates (not recommended). 54 | # Useful for reporting to NGINX Instance Manager without a local PKI. 55 | ssl_verify {% if nginxconf.license.ssl_verify == True %}on{% else %}off{% endif %}; 56 | } 57 | {% endif %} -------------------------------------------------------------------------------- /templates/v5.3/stream.tmpl: -------------------------------------------------------------------------------- 1 | # NGINX configuration file - Stream servers - generated by https://github.com/f5devcentral/NGINX-Declarative-API 2 | 3 | {# --- Upstreams section --- #} 4 | {% if declaration.upstreams %} 5 | # Upstreams 6 | {% for u in declaration.upstreams %} 7 | {% if u.name %} 8 | include "{{ ncgconfig.nms.upstream_stream_dir }}/{{ u.name | replace(' ', '_') }}.conf"; 9 | {% endif %} 10 | {% endfor %} 11 | {% endif %} 12 | 13 | {# --- Stream server section --- #} 14 | 15 | {% for s in declaration.servers %} 16 | {%- if s.listen %} 17 | {% if s.listen.address %} 18 | 19 | server { 20 | listen {{ s.listen.address }}{% if s.listen.protocol == "udp" %} {{ s.listen.protocol }}{% endif %}; 21 | status_zone {{ s.name | replace(" ", "_") }}; 22 | {% endif -%} 23 | {% endif -%} 24 | 25 | {% if s.resolver -%} 26 | include "{{ ncgconfig.nms.resolver_dir }}/{{ s.resolver | replace(" ", "_") }}.conf"; 27 | {% endif -%} 28 | 29 | {# --- TLS section --- #} 30 | {%- if s.listen.tls -%} 31 | {%- if s.listen.tls.certificate -%} 32 | ssl_certificate {{ ncgconfig.nms.certs_dir }}/{{ s.listen.tls.certificate }}.crt; 33 | {% endif -%} 34 | {%- if s.listen.tls.key -%} 35 | ssl_certificate_key {{ ncgconfig.nms.certs_dir }}/{{ s.listen.tls.key }}.key; 36 | {% endif -%} 37 | {% if s.listen.tls.ciphers -%} 38 | ssl_ciphers {{ s.listen.tls.ciphers }}; 39 | {% endif -%} 40 | {% if s.listen.tls.protocols -%} 41 | ssl_protocols{% for p in s.listen.tls.protocols %} {{ p }}{% endfor %}; 42 | {% endif %} 43 | {% endif %} 44 | 45 | {% if s.upstream -%} 46 | proxy_pass {{ s.upstream }}; 47 | {% endif %} 48 | 49 | {% if s.snippet and s.snippet.content %}{{ s.snippet.content | b64decode }}{% endif %} 50 | 51 | {%- if s.listen %} 52 | {%- if s.listen.address %} 53 | 54 | } 55 | {% endif -%} 56 | {% endif -%} 57 | 58 | {%- endfor %} 59 | -------------------------------------------------------------------------------- /templates/v5.3/visibility/moesif/http.tmpl: -------------------------------------------------------------------------------- 1 | # Moesif integration - https://www.moesif.com/docs/server-integration/nginx-openresty/ 2 | # URI: {{ loc.uri }} 3 | # application ID: {{ vis.moesif.application_id }} 4 | 5 | lua_shared_dict moesif_conf 5m; 6 | 7 | init_by_lua_block { 8 | local config = ngx.shared.moesif_conf; 9 | config:set("application_id", "{{ vis.moesif.application_id }}") 10 | } 11 | 12 | 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"; 13 | 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"; 14 | 15 | -------------------------------------------------------------------------------- /templates/v5.3/visibility/moesif/server.tmpl: -------------------------------------------------------------------------------- 1 | # Moesif integration - https://www.moesif.com/docs/server-integration/nginx-openresty/ 2 | # URI: {{ loc.uri }} 3 | # application ID: {{ vis.moesif.application_id }} 4 | 5 | # Define the variables Moesif requires 6 | set $moesif_user_id nil; 7 | set $moesif_company_id nil; 8 | set $moesif_req_body nil; 9 | set $moesif_res_body nil; 10 | 11 | # Optionally, set moesif_user_id and moesif_company_id such from a request header or NGINX var to identify customer 12 | header_filter_by_lua_block { 13 | ngx.var.moesif_user_id = ngx.req.get_headers()["X-User-Id"] 14 | ngx.var.moesif_company_id = ngx.req.get_headers()["X-Company-Id"] 15 | } 16 | 17 | # Add Moesif plugin 18 | access_by_lua_file {{ vis.moesif.plugin_path }}/read_req_body.lua; 19 | body_filter_by_lua_file {{ vis.moesif.plugin_path }}/read_res_body.lua; 20 | log_by_lua_file {{ vis.moesif.plugin_path }}/send_event.lua; 21 | 22 | --------------------------------------------------------------------------------