Compare commits

...

49 Commits

Author SHA1 Message Date
Ned Wright
3061342b45 Nov_12_2023-Dev 2023-11-12 18:50:17 +00:00
WrightNed
0869b8f24d Merge pull request #68 from bxlxx/main
fix installation usage errors in README
2023-11-05 16:06:57 +02:00
Syin Wu
1a4ab5f0d7 fix installation errors in README 2023-11-03 11:19:44 +08:00
WrightNed
4a2d25ab65 Update CMakeLists.txt 2023-10-24 18:04:33 +03:00
Ned Wright
f2ca7301b9 Updating charts 2023-10-08 13:38:39 +00:00
Ned Wright
3d11ead170 Updating charts 2023-10-08 07:15:09 +00:00
Ned Wright
39b8c5a5ff Update core/version/build_version_vars_h.py 2023-10-08 06:26:36 +00:00
Ned Wright
de6f1033bd Merge branch 'main' of https://github.com/openappsec/openappsec 2023-10-05 13:51:42 +00:00
Ned Wright
58958b2436 Change information collection flag 2023-10-05 13:50:29 +00:00
roybarda
59e7f00b3e Merge pull request #62 from openappsec/open_appsec_add_agent_cache_for_rate_limit
Open appsec add agent cache for rate limit
2023-10-05 15:44:37 +03:00
Daniel Eisenberg
e102b25b7d add cache conf file 2023-10-05 15:27:19 +03:00
Daniel Eisenberg
0386431eee add cache conf file 2023-10-05 15:21:12 +03:00
Daniel Eisenberg
fd1a77628e add cache conf file 2023-10-05 15:16:58 +03:00
Daniel Eisenberg
da911582a5 use sh instead of bash 2023-10-05 14:49:07 +03:00
roybarda
798dd2a7d1 Merge pull request #61 from openappsec/open_appsec_add_agent_cache_for_rate_limit
adding agent cache service for docker
2023-10-05 14:04:46 +03:00
Daniel Eisenberg
6bda60ae84 adding agent cache service to entry.sh 2023-10-05 14:03:00 +03:00
roybarda
5b9769e94e Update README.md
add redis for rate limit packaging purposes
2023-10-05 13:58:09 +03:00
roybarda
6693176131 Merge pull request #60 from openappsec/open_appsec_add_agent_cache_for_rate_limit
Open appsec add agent cache for rate limit
2023-10-05 13:46:11 +03:00
Daniel Eisenberg
c2ced075eb Merge branch 'main' of https://github.com/openappsec/openappsec into open_appsec_add_agent_cache_for_rate_limit 2023-10-05 13:45:02 +03:00
WrightNed
0b4bdd3677 Merge pull request #59 from openappsec/orianelou-patch-2
Update README.md
2023-10-05 13:41:15 +03:00
orianelou
d6599cc7bc Update README.md
updated supported versions
2023-10-05 13:34:25 +03:00
Daniel Eisenberg
4db7a54c27 adding agent cache service 2023-10-04 21:35:52 +03:00
Ned Wright
f3ede0c60e Update nodes/orchestration/scripts/cp-nano-makefile-generator.sh 2023-10-04 14:37:21 +00:00
roybarda
79bac9f501 adding model version to AI model 2023-10-03 09:52:26 +03:00
Ned Wright
89263f6f34 Change default cloud logging 2023-10-02 10:04:52 +00:00
Ned Wright
5feb12f7e4 Refactor rate limit 2023-10-01 10:03:24 +00:00
WrightNed
a2ee6ca839 Merge pull request #57 from openappsec/Sep_24_2023-Dev
Sep 24 2023 dev
2023-09-28 19:43:02 +03:00
Ned Wright
1c10a12f6f Minor fixes 2023-09-28 16:40:42 +00:00
Ned Wright
e9f6ebd02b Minor fixes 2023-09-28 16:38:31 +00:00
Ned Wright
433c7c2d91 Remove old files 2023-09-28 13:11:47 +00:00
Ned Wright
582791e37a Sep_24_2023-Dev 2023-09-24 10:28:57 +00:00
Ned Wright
a4d1fb6f7f Ading explict k8s check update invocation 2023-09-19 09:16:27 +00:00
bilbogh
dfbfdca1a9 Update README.md 2023-09-15 10:07:49 +02:00
bilbogh
36f511f449 Update README.md 2023-09-14 23:21:06 +02:00
bilbogh
f91f283b77 Added new section 2023-09-14 22:59:28 +02:00
bilbogh
7c762e97a3 Added charts 2023-09-14 22:36:50 +02:00
Ned Wright
aaa1fbe8ed Adding links to command line tools 2023-09-12 16:42:52 +00:00
Ned Wright
67e68c84c3 Fix finding libraries 2023-09-11 12:40:26 +03:00
Ned Wright
149a7305b7 Remove old deafult fog 2023-09-07 14:54:40 +00:00
Ned Wright
ea20a51689 Add upload option to open-appsec-ctl 2023-09-04 16:15:06 +00:00
bilbogh
19f2383ae2 Update README.md
Brought back lines that were accidentally deleted
2023-09-01 14:18:16 +02:00
WrightNed
4038c18bda Update CMakeLists.txt 2023-08-24 20:26:18 +03:00
WrightNed
a9b6d2e715 Merge pull request #47 from openappsec/Aug_23_2023-Dev
Aug 23 2023 dev
2023-08-24 15:10:14 +03:00
Ned Wright
81c75495cc temporarily disabling some unit-tests 2023-08-24 11:56:16 +00:00
WrightNed
5505022f47 Update cp-nano-package-list 2023-08-23 20:46:45 +03:00
Ned Wright
b25fd8def5 Aug_23_2023-Dev 2023-08-23 14:15:32 +00:00
Ned Wright
702c1184ea Merge branch 'main' of https://github.com/openappsec/openappsec 2023-08-17 17:40:54 +00:00
Ned Wright
b3cfd7e9d8 Check /etc/environment exists before using it 2023-08-17 17:40:22 +00:00
WrightNed
e36b990161 Merge pull request #43 from openappsec/changing_socket_readiness_testing
Change socket readiness testing
2023-08-10 00:22:37 +03:00
307 changed files with 17110 additions and 4145 deletions

View File

@@ -3,6 +3,11 @@ project (ngen)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wall -Wno-terminate -Dalpine")
execute_process(COMMAND grep -c "Alpine Linux" /etc/os-release OUTPUT_VARIABLE IS_ALPINE)
if(IS_ALPINE EQUAL "1")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Dalpine")
endif()
find_package(Boost REQUIRED)
find_package(ZLIB REQUIRED)
find_package(GTest REQUIRED)

139
README.md
View File

@@ -18,25 +18,41 @@ Every request to the application goes through two phases:
2. If the request is identified as a valid and legitimate request the request is allowed, and forwarded to your application. If, however, the request is considered suspicious or high risk, it then gets evaluated by the unsupervised model, which was trained in your specific environment. This model uses information such as the URL and the users involved to create a final confidence score that determines whether the request should be allowed or blocked.
## Machine Learning models
![image](https://github.com/openappsec/openappsec/assets/114033741/f32f1c99-9c45-4d21-aa85-61408a16a18e)
open-appsec uses two models:
open-appsec uses two machine learning models:
1. A supervised model that was trained offline based on millions of requests, both malicious and benign.
* A basic model is provided as part of this repository. It is recommended for use in Monitor-Only and Test environments.
* An advanced model which is more accurate and recommended for Production use can be downloaded from the [open-appsec portal](https://my.openappsec.io)->User Menu->Download advanced ML model. This model updates from time to time and you will get an email when these updates happen.
* A **basic model** is provided as part of this repository. It is recommended for use in Monitor-Only and Test environments.
* An **advanced model** which is more accurate and **recommended for Production** use can be downloaded from the [open-appsec portal](https://my.openappsec.io)->User Menu->Download advanced ML model. This model updates from time to time and you will get an email when these updates happen.
2. An unsupervised model that is being built in real time in the protected environment. This model uses traffic patterns specific to the environment.
# Management
open-appsec can be managed using multiple methods:
* [Declarative configuration files](https://docs.openappsec.io/getting-started/getting-started)
* [Kubernetes Helm Charts and annotations](https://docs.openappsec.io/getting-started/getting-started)
* [Using SaaS Web Management](https://docs.openappsec.io/getting-started/using-the-web-ui-saas)
open-appsec Web UI:
![image](https://github.com/openappsec/openappsec/assets/114033741/22d99379-df52-45c8-984f-1b820635f3b9)
## Deployment Playgrounds (Virtual labs)
You can experiment with open-appsec using [Playgrounds](https://www.openappsec.io/playground)
![image](https://github.com/openappsec/openappsec/assets/114033741/14d35d69-4577-48fc-ae87-ea344888e94d)
# Resources
* [Project Website](https://openappsec.io)
* [Offical Documentation](https://docs.openappsec.io/)
* [Video Tutorials](https://www.openappsec.io/tutorials)
* [Live Playgrounds](https://www.openappsec.io/playground)
# open-appsec Installation
# Installation
For Kubernetes (NGINX Ingress) using the installer:
@@ -47,11 +63,11 @@ $ ./open-appsec-k8s-install
For Kubernetes (NGINX or Kong) using Helm: follow [documentation](https://docs.openappsec.io/getting-started/start-with-kubernetes/install-using-helm-ingress-nginx-and-kong) use this method if youve built your own containers.
For Linux (NGINX or Kong) using the installer (list of supported/pre-compiled NGINX attachments is available [here](https://downloads.openappsec.io/supported-nginx.txt)):
For Linux (NGINX or Kong) using the installer (list of supported/pre-compiled NGINX attachments is available [here](https://downloads.openappsec.io/packages/supported-nginx.txt)):
```bash
$ wget https://downloads.openappsec.io/open-appsec-install && chmod +x open-appsec-install
$ ./open-appsec-install auto
$ ./open-appsec-install --auto
```
For Linux, if youve built your own package use the following commands:
@@ -63,3 +79,108 @@ $ install-cp-nano-attachment-registration-manager.sh --install
```
You can add the ```--token <token>``` and ```--email <email address>``` options to the first command, to get a token follow [documentation](https://docs.openappsec.io/getting-started/using-the-web-ui-saas/connect-deployed-agents-to-saas-management-k8s-and-linux).
For Docker: follow [documentation](https://docs.openappsec.io/getting-started/start-with-docker)
For more information read the [documentation](https://docs.openappsec.io/) or follow the [video tutorials](https://www.openappsec.io/tutorials).
# Repositories
open-appsec GitHub includes four main repositories:
* [openappsec/openappsec](https://github.com/openappsec/openappsec) the main code and logic of open-appsec. Developed in C++.
* [openappsec/attachment](https://github.com/openappsec/attachment) connects between processes that provide HTTP data (e.g NGINX) and the open-appsec Agent security logic. Developed in C.
* [openappsec/smartsync](https://github.com/openappsec/smartsync) in charge of correlating learning data from multiple agent instances and delivering a unified learning model for each asset. Developed in Golang.
* [openappsec/smartsync-shared-files](https://github.com/openappsec/smartsync-shared-files) interface to physical storage used by smartsync service for storing learning data. Developed in Golang.
# Compilation instructions
## Installing external dependencies
Before compiling the services, you'll need to ensure the latest development versions of the following libraries:
* Boost
* OpenSSL
* PCRE2
* libxml2
* GTest
* GMock
* cURL
* Redis
* Hiredis
An example of installing the packages on Alpine:
```bash
$ apk update
$ apk add boost-dev openssl-dev pcre2-dev libxml2-dev gtest-dev curl-dev hiredis-dev redis
```
## Compiling and packaging the agent code
1. Clone this repository
2. Run CMake command
3. Run make install command
```bash
$ git clone https://github.com/openappsec/openappsec.git
$ cd openappsec/
$ cmake -DCMAKE_INSTALL_PREFIX=build_out .
$ make install
$ make package
```
## Placing the agent code inside an Alpine docker image
Once the agent code has been compiled and packaged, an Alpine image running it can be created. This requires permissions to execute the `docker` command.
```bash
$ make docker
```
This will create a local image for your docker called `agent-docker`.
## Deployment of the agent docker image as a container
To run a Nano-Agent as a container the following steps are required:
1. If you are using a container management system / plan on deploying the container using your CI, add the agent docker image to an accessible registry.
2. If you are planning to manage the agent using the open-appsec UI, then make sure to obtain an agent token from the Management Portal and Enforce.
3. Run the agent with the following command (where -e https_proxy parameter is optional):
`docker run -d --name=agent-container --ipc=host -v=<path to persistent location for agent config>:/etc/cp/conf -v=<path to persistent location for agent data files>:/etc/cp/data -v=<path to persistent location for agent debugs and logs>:/var/log/nano_agent -e https_proxy=<user:password@Proxy address:port> -it <agent-image> /cp-nano-agent [--token <token> | --standalone]`
Example:
```bash
$ docker run -d --name=agent-container --ipc=host -v=/home/admin/agent/conf:/etc/cp/conf -v=/home/admin/agent/data:/etc/cp/data -v=/home/admin/agent/logs:/var/log/nano_agent e https_proxy=user:password@1.2.3.4:8080 -it agent-docker /cp-nano-agent --standalone
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1e67f2abbfd4 agent-docker "/cp-nano-agent --hybrid-mode" 1 minute ago Up 1 minute agent-container
```
Note that you are not required to use a token from the Management Portal if you are managing your security policy locally. However, you are required to use the --standalone flag in such cases. In addition, the volumes in the command are mandatory only if you wish to have persistency upon restart/upgrade/crash of the agent and its re-execution.
Lastly, --ipc=host argument is mandatory in order for the agent to have access to shared memory with a protected attachment (NGINX server).
4. Create or replace the NGINX container using the [Attachment Repository](https://github.com/openappsec/attachment).
This will run a docker container using the agent docker image.
# Contributing
We welcome everyone that wishes to share their knowledge and expertise to enhance and expand the project.
Please see the [Contributing Guidelines](https://github.com/openappsec/openappsec/blob/main/CONTRIBUTING.md).
# Security
### Security Audit
open-appsec code was audited by an independent third party in September-October 2022.
See the [full report](https://github.com/openappsec/openappsec/blob/main/LEXFO-CHP20221014-Report-Code_audit-OPEN-APPSEC-v1.2.pdf).
### Reporting security vulnerabilities
If you've found a vulnerability or a potential vulnerability in open-appsec please let us know at securityalert@openappsec.io. We'll send a confirmation email to acknowledge your report within 24 hours, and we'll send an additional email when we've identified the issue positively or negatively.
# License
open-appsec is open source and available under Apache 2.0 license.
The basic ML model is open source and available under Apache 2.0 license.
The advanced ML model is open source and available under Machine Learning Model license, available upon download in the tar file.

View File

@@ -32,5 +32,6 @@ DEFINE_KDEBUG_FLAG(statelessValidation)
DEFINE_KDEBUG_FLAG(kernelMetric)
DEFINE_KDEBUG_FLAG(tproxy)
DEFINE_KDEBUG_FLAG(tenantStats)
DEFINE_KDEBUG_FLAG(uuidTranslation)
#endif // DEFINE_KDEBUG_FLAG

View File

@@ -1,12 +1,9 @@
annotations:
artifacthub.io/changes: |
- "Added a doc line to the missing helm value service.internal.loadBalancerIP (#9406)"
- "feat(helm): Add loadBalancerClass (#9562)"
- "added helmshowvalues example (#10019)"
- "Update Ingress-Nginx version controller-v1.8.1"
- "Update Ingress-Nginx version controller-v1.9.1"
artifacthub.io/prerelease: "false"
apiVersion: v2
appVersion: 1.8.1
appVersion: latest
keywords:
- ingress
- nginx
@@ -14,4 +11,4 @@ kubeVersion: '>=1.20.0-0'
name: open-appsec-k8s-nginx-ingress
sources:
- https://github.com/kubernetes/ingress-nginx
version: 4.7.1
version: 4.8.1

View File

@@ -2,7 +2,7 @@
[ingress-nginx](https://github.com/kubernetes/ingress-nginx) Ingress controller for Kubernetes using NGINX as a reverse proxy and load balancer
![Version: 4.7.1](https://img.shields.io/badge/Version-4.7.1-informational?style=flat-square) ![AppVersion: 1.8.1](https://img.shields.io/badge/AppVersion-1.8.1-informational?style=flat-square)
![Version: 4.8.1](https://img.shields.io/badge/Version-4.8.1-informational?style=flat-square) ![AppVersion: 1.9.1](https://img.shields.io/badge/AppVersion-1.9.1-informational?style=flat-square)
To use, add `ingressClassName: nginx` spec field or the `kubernetes.io/ingress.class: nginx` annotation to your Ingress resources.
@@ -249,7 +249,6 @@ As of version `1.26.0` of this chart, by simply not providing any clusterIP valu
| controller.admissionWebhooks.key | string | `"/usr/local/certificates/key"` | |
| controller.admissionWebhooks.labels | object | `{}` | Labels to be added to admission webhooks |
| controller.admissionWebhooks.namespaceSelector | object | `{}` | |
| controller.admissionWebhooks.networkPolicyEnabled | bool | `false` | |
| controller.admissionWebhooks.objectSelector | object | `{}` | |
| controller.admissionWebhooks.patch.enabled | bool | `true` | |
| controller.admissionWebhooks.patch.image.digest | string | `"sha256:543c40fd093964bc9ab509d3e791f9989963021f1e9e4c9c7b6700b02bfb227b"` | |
@@ -274,7 +273,7 @@ As of version `1.26.0` of this chart, by simply not providing any clusterIP valu
| controller.admissionWebhooks.service.servicePort | int | `443` | |
| controller.admissionWebhooks.service.type | string | `"ClusterIP"` | |
| controller.affinity | object | `{}` | Affinity and anti-affinity rules for server scheduling to nodes # Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity # |
| controller.allowSnippetAnnotations | bool | `true` | This configuration defines if Ingress Controller should allow users to set their own *-snippet annotations, otherwise this is forbidden / dropped when users add those annotations. Global snippets in ConfigMap are still respected |
| controller.allowSnippetAnnotations | bool | `false` | This configuration defines if Ingress Controller should allow users to set their own *-snippet annotations, otherwise this is forbidden / dropped when users add those annotations. Global snippets in ConfigMap are still respected |
| controller.annotations | object | `{}` | Annotations to be added to the controller Deployment or DaemonSet # |
| controller.autoscaling.annotations | object | `{}` | |
| controller.autoscaling.behavior | object | `{}` | |
@@ -294,8 +293,9 @@ As of version `1.26.0` of this chart, by simply not providing any clusterIP valu
| controller.dnsConfig | object | `{}` | Optionally customize the pod dnsConfig. |
| controller.dnsPolicy | string | `"ClusterFirst"` | Optionally change this to ClusterFirstWithHostNet in case you have 'hostNetwork: true'. By default, while using host network, name resolution uses the host's DNS. If you wish nginx-controller to keep resolving names inside the k8s network, use ClusterFirstWithHostNet. |
| controller.electionID | string | `""` | Election ID to use for status update, by default it uses the controller name combined with a suffix of 'leader' |
| controller.enableAnnotationValidations | bool | `false` | |
| controller.enableMimalloc | bool | `true` | Enable mimalloc as a drop-in replacement for malloc. # ref: https://github.com/microsoft/mimalloc # |
| controller.enableTopologyAwareRouting | bool | `false` | This configuration enables Topology Aware Routing feature, used together with service annotation service.kubernetes.io/topology-aware-hints="auto" Defaults to false |
| controller.enableTopologyAwareRouting | bool | `false` | This configuration enables Topology Aware Routing feature, used together with service annotation service.kubernetes.io/topology-mode="auto" Defaults to false |
| controller.existingPsp | string | `""` | Use an existing PSP instead of creating one |
| controller.extraArgs | object | `{}` | Additional command line arguments to pass to Ingress-Nginx Controller E.g. to specify the default SSL certificate you can use |
| controller.extraContainers | list | `[]` | Additional containers to be added to the controller pod. See https://github.com/lemonldap-ng-controller/lemonldap-ng-controller as example. |
@@ -306,6 +306,7 @@ As of version `1.26.0` of this chart, by simply not providing any clusterIP valu
| controller.extraVolumes | list | `[]` | Additional volumes to the controller pod. |
| controller.healthCheckHost | string | `""` | Address to bind the health check endpoint. It is better to set this option to the internal node address if the Ingress-Nginx Controller is running in the `hostNetwork: true` mode. |
| controller.healthCheckPath | string | `"/healthz"` | Path of the health check endpoint. All requests received on the port defined by the healthz-port parameter are forwarded internally to this path. |
| controller.hostAliases | list | `[]` | Optionally customize the pod hostAliases. |
| controller.hostNetwork | bool | `false` | Required for use with CNI based kubernetes installations (such as ones set up by kubeadm), since CNI and hostport don't mix yet. Can be deprecated once https://github.com/kubernetes/kubernetes/issues/23920 is merged |
| controller.hostPort.enabled | bool | `false` | Enable 'hostPort' or not |
| controller.hostPort.ports.http | int | `80` | 'hostPort' http port |
@@ -313,13 +314,13 @@ As of version `1.26.0` of this chart, by simply not providing any clusterIP valu
| controller.hostname | object | `{}` | Optionally customize the pod hostname. |
| controller.image.allowPrivilegeEscalation | bool | `true` | |
| controller.image.chroot | bool | `false` | |
| controller.image.digest | string | `"sha256:e5c4824e7375fcf2a393e1c03c293b69759af37a9ca6abdb91b13d78a93da8bd"` | |
| controller.image.digestChroot | string | `"sha256:e0d4121e3c5e39de9122e55e331a32d5ebf8d4d257227cb93ab54a1b912a7627"` | |
| controller.image.digest | string | `"sha256:605a737877de78969493a4b1213b21de4ee425d2926906857b98050f57a95b25"` | |
| controller.image.digestChroot | string | `"sha256:2ac744ef08850ee86ad7162451a6879f47c1a41c6a757f6b6f913c52103b8836"` | |
| controller.image.image | string | `"ingress-nginx/controller"` | |
| controller.image.pullPolicy | string | `"IfNotPresent"` | |
| controller.image.registry | string | `"registry.k8s.io"` | |
| controller.image.runAsUser | int | `101` | |
| controller.image.tag | string | `"v1.8.1"` | |
| controller.image.tag | string | `"v1.9.1"` | |
| controller.ingressClass | string | `"nginx"` | For backwards compatibility with ingress.class annotation, use ingressClass. Algorithm is as follows, first ingressClassName is considered, if not present, controller looks for ingress.class annotation |
| controller.ingressClassByName | bool | `false` | Process IngressClass per name (additionally as per spec.controller). |
| controller.ingressClassResource.controllerValue | string | `"k8s.io/ingress-nginx"` | Controller-value of the controller that is processing this ingressClass |
@@ -372,10 +373,12 @@ As of version `1.26.0` of this chart, by simply not providing any clusterIP valu
| controller.minAvailable | int | `1` | Minimum available pods set in PodDisruptionBudget. Define either 'minAvailable' or 'maxUnavailable', never both. |
| controller.minReadySeconds | int | `0` | `minReadySeconds` to avoid killing pods before we are ready # |
| controller.name | string | `"controller"` | |
| controller.networkPolicy.enabled | bool | `false` | Enable 'networkPolicy' or not |
| controller.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node labels for controller pod assignment # Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/ # |
| controller.opentelemetry.containerSecurityContext.allowPrivilegeEscalation | bool | `false` | |
| controller.opentelemetry.enabled | bool | `false` | |
| controller.opentelemetry.image | string | `"registry.k8s.io/ingress-nginx/opentelemetry:v20230527@sha256:fd7ec835f31b7b37187238eb4fdad4438806e69f413a203796263131f4f02ed0"` | |
| controller.opentelemetry.image | string | `"registry.k8s.io/ingress-nginx/opentelemetry:v20230721-3e2062ee5@sha256:13bee3f5223883d3ca62fee7309ad02d22ec00ff0d7033e3e9aca7a9f60fd472"` | |
| controller.opentelemetry.resources | object | `{}` | |
| controller.podAnnotations | object | `{}` | Annotations to be added to controller pods # |
| controller.podLabels | object | `{}` | Labels to add to the pod container metadata |
| controller.podSecurityContext | object | `{}` | Security Context policies for controller pods |
@@ -399,14 +402,14 @@ As of version `1.26.0` of this chart, by simply not providing any clusterIP valu
| controller.scope.enabled | bool | `false` | Enable 'scope' or not |
| controller.scope.namespace | string | `""` | Namespace to limit the controller to; defaults to $(POD_NAMESPACE) |
| controller.scope.namespaceSelector | string | `""` | When scope.enabled == false, instead of watching all namespaces, we watching namespaces whose labels only match with namespaceSelector. Format like foo=bar. Defaults to empty, means watching all namespaces. |
| controller.service.annotations | object | `{}` | |
| controller.service.annotations | object | `{}` | Annotations are mandatory for the load balancer to come up. Varies with the cloud service. Values passed through helm tpl engine. |
| controller.service.appProtocol | bool | `true` | If enabled is adding an appProtocol option for Kubernetes service. An appProtocol field replacing annotations that were using for setting a backend protocol. Here is an example for AWS: service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http It allows choosing the protocol for each backend specified in the Kubernetes service. See the following GitHub issue for more details about the purpose: https://github.com/kubernetes/kubernetes/issues/40244 Will be ignored for Kubernetes versions older than 1.20 # |
| controller.service.enableHttp | bool | `true` | |
| controller.service.enableHttps | bool | `true` | |
| controller.service.enabled | bool | `true` | |
| controller.service.external.enabled | bool | `true` | |
| controller.service.externalIPs | list | `[]` | List of IP addresses at which the controller services are available # Ref: https://kubernetes.io/docs/concepts/services-networking/service/#external-ips # |
| controller.service.internal.annotations | object | `{}` | Annotations are mandatory for the load balancer to come up. Varies with the cloud service. |
| controller.service.internal.annotations | object | `{}` | Annotations are mandatory for the load balancer to come up. Varies with the cloud service. Values passed through helm tpl engine. |
| controller.service.internal.enabled | bool | `false` | Enables an additional internal load balancer (besides the external one). |
| controller.service.internal.loadBalancerIP | string | `""` | Used by cloud providers to connect the resulting internal LoadBalancer to a pre-existing static IP. Make sure to add to the service the needed annotation to specify the subnet which the static IP belongs to. For instance, `networking.gke.io/internal-load-balancer-subnet` for GCP and `service.beta.kubernetes.io/aws-load-balancer-subnets` for AWS. |
| controller.service.internal.loadBalancerSourceRanges | list | `[]` | Restrict access For LoadBalancer service. Defaults to 0.0.0.0/0. |
@@ -469,6 +472,7 @@ As of version `1.26.0` of this chart, by simply not providing any clusterIP valu
| defaultBackend.minAvailable | int | `1` | |
| defaultBackend.minReadySeconds | int | `0` | `minReadySeconds` to avoid killing pods before we are ready # |
| defaultBackend.name | string | `"defaultbackend"` | |
| defaultBackend.networkPolicy.enabled | bool | `false` | Enable 'networkPolicy' or not |
| defaultBackend.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node labels for default backend pod assignment # Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/ # |
| defaultBackend.podAnnotations | object | `{}` | Annotations to be added to default backend pods # |
| defaultBackend.podLabels | object | `{}` | Labels to add to the pod container metadata |

View File

@@ -0,0 +1,9 @@
# Changelog
This file documents all notable changes to [ingress-nginx](https://github.com/kubernetes/ingress-nginx) Helm Chart. The release numbering uses [semantic versioning](http://semver.org).
### 4.7.2
* Update Ingress-Nginx version controller-v1.8.2
**Full Changelog**: https://github.com/kubernetes/ingress-nginx/compare/helm-chart-4.7.1...helm-chart-4.7.2

View File

@@ -0,0 +1,13 @@
# Changelog
This file documents all notable changes to [ingress-nginx](https://github.com/kubernetes/ingress-nginx) Helm Chart. The release numbering uses [semantic versioning](http://semver.org).
### 4.8.0-beta.0
* ci(helm): fix Helm Chart release action 422 error (#10237)
* helm: Use .Release.Namespace as default for ServiceMonitor namespace (#10249)
* [helm] configure allow to configure hostAliases (#10180)
* [helm] pass service annotations through helm tpl engine (#10084)
* Update Ingress-Nginx version controller-v1.9.0-beta.0
**Full Changelog**: https://github.com/kubernetes/ingress-nginx/compare/helm-chart-4.7.2...helm-chart-4.8.0-beta.0

View File

@@ -0,0 +1,13 @@
# Changelog
This file documents all notable changes to [ingress-nginx](https://github.com/kubernetes/ingress-nginx) Helm Chart. The release numbering uses [semantic versioning](http://semver.org).
### 4.8.0
* ci(helm): fix Helm Chart release action 422 error (#10237)
* helm: Use .Release.Namespace as default for ServiceMonitor namespace (#10249)
* [helm] configure allow to configure hostAliases (#10180)
* [helm] pass service annotations through helm tpl engine (#10084)
* Update Ingress-Nginx version controller-v1.9.0
**Full Changelog**: https://github.com/kubernetes/ingress-nginx/compare/helm-chart-4.7.2...helm-chart-4.8.0

View File

@@ -0,0 +1,9 @@
# Changelog
This file documents all notable changes to [ingress-nginx](https://github.com/kubernetes/ingress-nginx) Helm Chart. The release numbering uses [semantic versioning](http://semver.org).
### 4.8.1
* Update Ingress-Nginx version controller-v1.9.1
**Full Changelog**: https://github.com/kubernetes/ingress-nginx/compare/helm-chart-4.8.0...helm-chart-4.8.1

View File

@@ -198,7 +198,6 @@ IngressClass parameters.
Extra modules.
*/}}
{{- define "extraModules" -}}
- name: {{ .name }}
image: {{ .image }}
{{- if .distroless | default false }}
@@ -209,8 +208,10 @@ Extra modules.
{{- if .containerSecurityContext }}
securityContext: {{ .containerSecurityContext | toYaml | nindent 4 }}
{{- end }}
{{- if .resources }}
resources: {{ .resources | toYaml | nindent 4 }}
{{- end }}
volumeMounts:
- name: {{ toYaml "modules"}}
mountPath: {{ toYaml "/modules_mount"}}
{{- end -}}

View File

@@ -1,5 +1,8 @@
{{- define "ingress-nginx.params" -}}
- /nginx-ingress-controller
{{- if .Values.controller.enableAnnotationValidations }}
- --enable-annotation-validation=true
{{- end }}
{{- if .Values.defaultBackend.enabled }}
- --default-backend-service=$(POD_NAMESPACE)/{{ include "ingress-nginx.defaultBackend.fullname" . }}
{{- end }}

View File

@@ -1,4 +1,4 @@
{{- if and .Values.controller.admissionWebhooks.enabled .Values.controller.admissionWebhooks.networkPolicyEnabled }}
{{- if and .Values.controller.admissionWebhooks.enabled .Values.controller.admissionWebhooks.patch.enabled (not .Values.controller.admissionWebhooks.certManager.enabled) -}}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
@@ -16,11 +16,11 @@ metadata:
spec:
podSelector:
matchLabels:
{{- include "ingress-nginx.labels" . | nindent 6 }}
{{- include "ingress-nginx.selectorLabels" . | nindent 6 }}
app.kubernetes.io/component: admission-webhook
policyTypes:
- Ingress
- Egress
- Ingress
- Egress
egress:
- {}
- {}
{{- end }}

View File

@@ -27,7 +27,7 @@ spec:
matchLabels:
{{- include "ingress-nginx.selectorLabels" . | nindent 6 }}
app.kubernetes.io/component: controller
{{- if not .Values.controller.autoscaling.enabled }}
{{- if not (or .Values.controller.autoscaling.enabled .Values.controller.keda.enabled) }}
{{- if eq .Values.kind "AppSecStateful" }}
serviceName: "open-appsec-stateful-set"
{{- end }}
@@ -38,11 +38,10 @@ spec:
revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
{{- if .Values.controller.updateStrategy }}
{{- if (and (not (eq .Values.kind "AppSecStateful")) (eq .Values.controller.kind "DaemonSet")) }}
updateStrategy:
updateStrategy: {{ toYaml .Values.controller.updateStrategy | nindent 4 }}:
{{- else }}
strategy:
strategy: {{ toYaml .Values.controller.updateStrategy | nindent 4 }}
{{- end }}
{{ toYaml .Values.controller.updateStrategy | nindent 4 }}
{{- end }}
{{- if (eq .Values.kind "AppSec") }}
minReadySeconds: {{ .Values.controller.minReadySeconds }}
@@ -68,6 +67,9 @@ spec:
{{- if .Values.controller.dnsConfig }}
dnsConfig: {{ toYaml .Values.controller.dnsConfig | nindent 8 }}
{{- end }}
{{- if .Values.controller.hostAliases }}
hostAliases: {{ tpl (toYaml .Values.controller.hostAliases) $ | nindent 8 }}
{{- end }}
{{- if .Values.controller.hostname }}
hostname: {{ toYaml .Values.controller.hostname | nindent 8 }}
{{- end }}
@@ -268,17 +270,14 @@ spec:
{{- end }}
{{- if .Values.controller.extraModules }}
{{- range .Values.controller.extraModules }}
{{ $containerSecurityContext := .containerSecurityContext | default $.Values.controller.containerSecurityContext }}
{{ include "extraModules" (dict "name" .name "image" .image "containerSecurityContext" $containerSecurityContext) | indent 8 }}
{{- $containerSecurityContext := .containerSecurityContext | default $.Values.controller.containerSecurityContext }}
{{- include "extraModules" (dict "name" .name "image" .image "containerSecurityContext" $containerSecurityContext) | nindent 8 }}
{{- end }}
{{- end }}
{{- if .Values.controller.opentelemetry.enabled}}
{{ $otelContainerSecurityContext := $.Values.controller.opentelemetry.containerSecurityContext | default $.Values.controller.containerSecurityContext }}
{{- if (and (not (eq .Values.kind "AppSecStateful")) (eq .Values.controller.kind "DaemonSet")) }}
{{- include "extraModules" (dict "name" "opentelemetry" "image" .Values.controller.opentelemetry.image "containerSecurityContext" $otelContainerSecurityContext ) | nindent 8}}
{{ else }}
{{- include "extraModules" (dict "name" "opentelemetry" "image" .Values.controller.opentelemetry.image "containerSecurityContext" $otelContainerSecurityContext "distroless" false) | nindent 8}}
{{- end }}
{{- $otelContainerSecurityContext := $.Values.controller.opentelemetry.containerSecurityContext | default $.Values.controller.containerSecurityContext }}
{{ $otelResources := $.Values.controller.opentelemetry.resources | default dict }}
{{- include "extraModules" (dict "name" "opentelemetry" "image" .Values.controller.opentelemetry.image "containerSecurityContext" $otelContainerSecurityContext "distroless" true "resources" $otelResources) | nindent 8}}
{{- end}}
{{- end }}
{{- if .Values.controller.hostNetwork }}
@@ -294,7 +293,7 @@ spec:
affinity: {{ toYaml .Values.controller.affinity | nindent 8 }}
{{- end }}
{{- if .Values.controller.topologySpreadConstraints }}
topologySpreadConstraints: {{ toYaml .Values.controller.topologySpreadConstraints | nindent 8 }}
topologySpreadConstraints: {{ tpl (toYaml .Values.controller.topologySpreadConstraints) $ | nindent 8 }}
{{- end }}
serviceAccountName: {{ template "ingress-nginx.serviceAccountName" . }}
terminationGracePeriodSeconds: {{ .Values.controller.terminationGracePeriodSeconds }}

View File

@@ -45,6 +45,9 @@ spec:
{{- if .Values.controller.dnsConfig }}
dnsConfig: {{ toYaml .Values.controller.dnsConfig | nindent 8 }}
{{- end }}
{{- if .Values.controller.hostAliases }}
hostAliases: {{ tpl (toYaml .Values.controller.hostAliases) $ | nindent 8 }}
{{- end }}
{{- if .Values.controller.hostname }}
hostname: {{ toYaml .Values.controller.hostname | nindent 8 }}
{{- end }}
@@ -180,13 +183,14 @@ spec:
{{- end }}
{{- if .Values.controller.extraModules }}
{{- range .Values.controller.extraModules }}
{{ $containerSecurityContext := .containerSecurityContext | default $.Values.controller.containerSecurityContext }}
{{ include "extraModules" (dict "name" .name "image" .image "containerSecurityContext" $containerSecurityContext) | indent 8 }}
{{- $containerSecurityContext := .containerSecurityContext | default $.Values.controller.containerSecurityContext }}
{{- include "extraModules" (dict "name" .name "image" .image "containerSecurityContext" $containerSecurityContext) | nindent 8 }}
{{- end }}
{{- end }}
{{- if .Values.controller.opentelemetry.enabled}}
{{ $otelContainerSecurityContext := $.Values.controller.opentelemetry.containerSecurityContext | default $.Values.controller.containerSecurityContext }}
{{- include "extraModules" (dict "name" "opentelemetry" "image" .Values.controller.opentelemetry.image "containerSecurityContext" $otelContainerSecurityContext) | nindent 8}}
{{- $otelContainerSecurityContext := $.Values.controller.opentelemetry.containerSecurityContext | default $.Values.controller.containerSecurityContext }}
{{ $otelResources := $.Values.controller.opentelemetry.resources | default dict }}
{{- include "extraModules" (dict "name" "opentelemetry" "image" .Values.controller.opentelemetry.image "containerSecurityContext" $otelContainerSecurityContext "distroless" true "resources" $otelResources) | nindent 8}}
{{- end}}
{{- end }}
{{- if .Values.controller.hostNetwork }}
@@ -202,7 +206,7 @@ spec:
affinity: {{ toYaml .Values.controller.affinity | nindent 8 }}
{{- end }}
{{- if .Values.controller.topologySpreadConstraints }}
topologySpreadConstraints: {{ toYaml .Values.controller.topologySpreadConstraints | nindent 8 }}
topologySpreadConstraints: {{ tpl (toYaml .Values.controller.topologySpreadConstraints) $ | nindent 8 }}
{{- end }}
serviceAccountName: {{ template "ingress-nginx.serviceAccountName" . }}
terminationGracePeriodSeconds: {{ .Values.controller.terminationGracePeriodSeconds }}

View File

@@ -19,13 +19,12 @@ spec:
matchLabels:
{{- include "ingress-nginx.selectorLabels" . | nindent 6 }}
app.kubernetes.io/component: controller
{{- if not .Values.controller.autoscaling.enabled }}
{{- if not (or .Values.controller.autoscaling.enabled .Values.controller.keda.enabled) }}
replicas: {{ .Values.controller.replicaCount }}
{{- end }}
revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
{{- if .Values.controller.updateStrategy }}
strategy:
{{ toYaml .Values.controller.updateStrategy | nindent 4 }}
strategy: {{ toYaml .Values.controller.updateStrategy | nindent 4 }}
{{- end }}
minReadySeconds: {{ .Values.controller.minReadySeconds }}
template:
@@ -49,6 +48,9 @@ spec:
{{- if .Values.controller.dnsConfig }}
dnsConfig: {{ toYaml .Values.controller.dnsConfig | nindent 8 }}
{{- end }}
{{- if .Values.controller.hostAliases }}
hostAliases: {{ tpl (toYaml .Values.controller.hostAliases) $ | nindent 8 }}
{{- end }}
{{- if .Values.controller.hostname }}
hostname: {{ toYaml .Values.controller.hostname | nindent 8 }}
{{- end }}
@@ -184,13 +186,14 @@ spec:
{{- end }}
{{- if .Values.controller.extraModules }}
{{- range .Values.controller.extraModules }}
{{ $containerSecurityContext := .containerSecurityContext | default $.Values.controller.containerSecurityContext }}
{{ include "extraModules" (dict "name" .name "image" .image "containerSecurityContext" $containerSecurityContext) | indent 8 }}
{{- $containerSecurityContext := .containerSecurityContext | default $.Values.controller.containerSecurityContext }}
{{- include "extraModules" (dict "name" .name "image" .image "containerSecurityContext" $containerSecurityContext) | nindent 8 }}
{{- end }}
{{- end }}
{{- if .Values.controller.opentelemetry.enabled}}
{{ $otelContainerSecurityContext := $.Values.controller.opentelemetry.containerSecurityContext | default $.Values.controller.containerSecurityContext }}
{{- include "extraModules" (dict "name" "opentelemetry" "image" .Values.controller.opentelemetry.image "containerSecurityContext" $otelContainerSecurityContext "distroless" false) | nindent 8}}
{{- $otelContainerSecurityContext := $.Values.controller.opentelemetry.containerSecurityContext | default $.Values.controller.containerSecurityContext }}
{{ $otelResources := $.Values.controller.opentelemetry.resources | default dict }}
{{- include "extraModules" (dict "name" "opentelemetry" "image" .Values.controller.opentelemetry.image "containerSecurityContext" $otelContainerSecurityContext "distroless" true "resources" $otelResources) | nindent 8}}
{{- end}}
{{- end }}
{{- if .Values.controller.hostNetwork }}
@@ -206,7 +209,7 @@ spec:
affinity: {{ toYaml .Values.controller.affinity | nindent 8 }}
{{- end }}
{{- if .Values.controller.topologySpreadConstraints }}
topologySpreadConstraints: {{ toYaml .Values.controller.topologySpreadConstraints | nindent 8 }}
topologySpreadConstraints: {{ tpl (toYaml .Values.controller.topologySpreadConstraints) $ | nindent 8 }}
{{- end }}
serviceAccountName: {{ template "ingress-nginx.serviceAccountName" . }}
terminationGracePeriodSeconds: {{ .Values.controller.terminationGracePeriodSeconds }}

View File

@@ -0,0 +1,45 @@
{{- if .Values.controller.networkPolicy.enabled }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
labels:
{{- include "ingress-nginx.labels" . | nindent 4 }}
app.kubernetes.io/component: controller
{{- with .Values.controller.labels }}
{{- toYaml . | nindent 4 }}
{{- end }}
name: {{ include "ingress-nginx.controller.fullname" . }}
namespace: {{ .Release.Namespace }}
spec:
podSelector:
matchLabels:
{{- include "ingress-nginx.selectorLabels" . | nindent 6 }}
app.kubernetes.io/component: controller
policyTypes:
- Ingress
- Egress
ingress:
- ports:
{{- range $key, $value := .Values.controller.containerPort }}
- protocol: TCP
port: {{ $value }}
{{- end }}
{{- if .Values.controller.metrics.enabled }}
- protocol: TCP
port: {{ .Values.controller.metrics.port }}
{{- end }}
{{- if .Values.controller.admissionWebhooks.enabled }}
- protocol: TCP
port: {{ .Values.controller.admissionWebhooks.port }}
{{- end }}
{{- range $key, $value := .Values.tcp }}
- protocol: TCP
port: {{ $key }}
{{- end }}
{{- range $key, $value := .Values.udp }}
- protocol: UDP
port: {{ $key }}
{{- end }}
egress:
- {}
{{- end }}

View File

@@ -4,7 +4,7 @@ kind: Service
metadata:
annotations:
{{- range $key, $value := .Values.controller.service.internal.annotations }}
{{ $key }}: {{ $value | quote }}
{{ $key }}: {{ tpl ($value | toString) $ | quote }}
{{- end }}
labels:
{{- include "ingress-nginx.labels" . | nindent 4 }}

View File

@@ -4,7 +4,7 @@ kind: Service
metadata:
annotations:
{{- range $key, $value := .Values.controller.service.annotations }}
{{ $key }}: {{ $value | quote }}
{{ $key }}: {{ tpl ($value | toString) $ | quote }}
{{- end }}
labels:
{{- include "ingress-nginx.labels" . | nindent 4 }}

View File

@@ -11,8 +11,7 @@ metadata:
name: {{ template "ingress-nginx.serviceAccountName" . }}
namespace: {{ .Release.Namespace }}
{{- if .Values.serviceAccount.annotations }}
annotations:
{{- toYaml .Values.serviceAccount.annotations | nindent 4 }}
annotations: {{ toYaml .Values.serviceAccount.annotations | nindent 4 }}
{{- end }}
automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }}
{{- end }}

View File

@@ -5,6 +5,8 @@ metadata:
name: {{ include "ingress-nginx.controller.fullname" . }}
{{- if .Values.controller.metrics.serviceMonitor.namespace }}
namespace: {{ .Values.controller.metrics.serviceMonitor.namespace | quote }}
{{- else }}
namespace: {{ .Release.Namespace }}
{{- end }}
labels:
{{- include "ingress-nginx.labels" . | nindent 4 }}

View File

@@ -1,19 +0,0 @@
{{- if .Values.controller.admissionWebhooks.enabled }}
{{- if .Values.controller.admissionWebhooks.networkPolicyEnabled }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: {{ include "ingress-nginx.fullname" . }}-webhooks-allow
namespace: {{ .Release.Namespace }}
spec:
ingress:
- {}
podSelector:
matchLabels:
app.kubernetes.io/name: {{ include "ingress-nginx.name" . }}
policyTypes:
- Ingress
{{- end }}
{{- end }}

View File

@@ -0,0 +1,25 @@
{{- if and .Values.defaultBackend.enabled .Values.defaultBackend.networkPolicy.enabled }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
labels:
{{- include "ingress-nginx.labels" . | nindent 4 }}
app.kubernetes.io/component: default-backend
{{- with .Values.defaultBackend.labels }}
{{- toYaml . | nindent 4 }}
{{- end }}
name: {{ include "ingress-nginx.defaultBackend.fullname" . }}
namespace: {{ .Release.Namespace }}
spec:
podSelector:
matchLabels:
{{- include "ingress-nginx.selectorLabels" . | nindent 6 }}
app.kubernetes.io/component: default-backend
policyTypes:
- Ingress
- Egress
ingress:
- ports:
- protocol: TCP
port: {{ .Values.defaultBackend.port }}
{{- end }}

View File

@@ -15,6 +15,7 @@ commonLabels: {}
controller:
name: controller
enableAnnotationValidations: false
image:
## Keep false as default for now!
chroot: false
@@ -23,9 +24,9 @@ controller:
## for backwards compatibility consider setting the full image url via the repository value below
## use *either* current default registry/image or repository format or installing chart by providing the values.yaml will fail
## repository:
tag: "v1.8.1"
digest: sha256:e5c4824e7375fcf2a393e1c03c293b69759af37a9ca6abdb91b13d78a93da8bd
digestChroot: sha256:e0d4121e3c5e39de9122e55e331a32d5ebf8d4d257227cb93ab54a1b912a7627
tag: "v1.9.1"
digest: sha256:605a737877de78969493a4b1213b21de4ee425d2926906857b98050f57a95b25
digestChroot: sha256:2ac744ef08850ee86ad7162451a6879f47c1a41c6a757f6b6f913c52103b8836
pullPolicy: IfNotPresent
# www-data -> uid 101
runAsUser: 101
@@ -48,6 +49,16 @@ controller:
addHeaders: {}
# -- Optionally customize the pod dnsConfig.
dnsConfig: {}
# -- Optionally customize the pod hostAliases.
hostAliases: []
# - ip: 127.0.0.1
# hostnames:
# - foo.local
# - bar.local
# - ip: 10.1.2.3
# hostnames:
# - foo.remote
# - bar.remote
# -- Optionally customize the pod hostname.
hostname: {}
# -- Optionally change this to ClusterFirstWithHostNet in case you have 'hostNetwork: true'.
@@ -63,14 +74,14 @@ controller:
watchIngressWithoutClass: false
# -- Process IngressClass per name (additionally as per spec.controller).
ingressClassByName: false
# -- This configuration enables Topology Aware Routing feature, used together with service annotation service.kubernetes.io/topology-aware-hints="auto"
# -- This configuration enables Topology Aware Routing feature, used together with service annotation service.kubernetes.io/topology-mode="auto"
# Defaults to false
enableTopologyAwareRouting: false
# -- This configuration defines if Ingress Controller should allow users to set
# their own *-snippet annotations, otherwise this is forbidden / dropped
# when users add those annotations.
# Global snippets in ConfigMap are still respected
allowSnippetAnnotations: true
allowSnippetAnnotations: false
# -- Required for use with CNI based kubernetes installations (such as ones set up by kubeadm),
# since CNI and hostport don't mix yet. Can be deprecated once https://github.com/kubernetes/kubernetes/issues/23920
# is merged
@@ -85,6 +96,10 @@ controller:
http: 80
# -- 'hostPort' https port
https: 443
# NetworkPolicy for controller component.
networkPolicy:
# -- Enable 'networkPolicy' or not
enabled: false
# -- Election ID to use for status update, by default it uses the controller name combined with a suffix of 'leader'
electionID: ""
## This section refers to the creation of the IngressClass resource
@@ -245,12 +260,22 @@ controller:
## Ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/
##
topologySpreadConstraints: []
# - maxSkew: 1
# topologyKey: topology.kubernetes.io/zone
# whenUnsatisfiable: DoNotSchedule
# labelSelector:
# - labelSelector:
# matchLabels:
# app.kubernetes.io/instance: ingress-nginx-internal
# app.kubernetes.io/name: '{{ include "ingress-nginx.name" . }}'
# app.kubernetes.io/instance: '{{ .Release.Name }}'
# app.kubernetes.io/component: controller
# topologyKey: topology.kubernetes.io/zone
# maxSkew: 1
# whenUnsatisfiable: ScheduleAnyway
# - labelSelector:
# matchLabels:
# app.kubernetes.io/name: '{{ include "ingress-nginx.name" . }}'
# app.kubernetes.io/instance: '{{ .Release.Name }}'
# app.kubernetes.io/component: controller
# topologyKey: kubernetes.io/hostname
# maxSkew: 1
# whenUnsatisfiable: ScheduleAnyway
# -- `terminationGracePeriodSeconds` to avoid killing pods before we are ready
## wait up to five minutes for the drain of connections
@@ -415,6 +440,7 @@ controller:
# Will be ignored for Kubernetes versions older than 1.20
##
appProtocol: true
# -- Annotations are mandatory for the load balancer to come up. Varies with the cloud service. Values passed through helm tpl engine.
annotations: {}
labels: {}
# clusterIP: ""
@@ -476,7 +502,7 @@ controller:
internal:
# -- Enables an additional internal load balancer (besides the external one).
enabled: false
# -- Annotations are mandatory for the load balancer to come up. Varies with the cloud service.
# -- Annotations are mandatory for the load balancer to come up. Varies with the cloud service. Values passed through helm tpl engine.
annotations: {}
# -- Used by cloud providers to connect the resulting internal LoadBalancer to a pre-existing static IP. Make sure to add to the service the needed annotation to specify the subnet which the static IP belongs to. For instance, `networking.gke.io/internal-load-balancer-subnet` for GCP and `service.beta.kubernetes.io/aws-load-balancer-subnets` for AWS.
loadBalancerIP: ""
@@ -552,9 +578,10 @@ controller:
opentelemetry:
enabled: false
image: registry.k8s.io/ingress-nginx/opentelemetry:v20230527@sha256:fd7ec835f31b7b37187238eb4fdad4438806e69f413a203796263131f4f02ed0
image: registry.k8s.io/ingress-nginx/opentelemetry:v20230721-3e2062ee5@sha256:13bee3f5223883d3ca62fee7309ad02d22ec00ff0d7033e3e9aca7a9f60fd472
containerSecurityContext:
allowPrivilegeEscalation: false
resources: {}
admissionWebhooks:
annotations: {}
# ignore-check.kube-linter.io/no-read-only-rootfs: "This deployment needs write access to root filesystem".
@@ -583,7 +610,6 @@ controller:
labels: {}
# -- Use an existing PSP instead of creating one
existingPsp: ""
networkPolicyEnabled: false
service:
annotations: {}
# clusterIP: ""
@@ -849,6 +875,10 @@ defaultBackend:
maxReplicas: 2
targetCPUUtilizationPercentage: 50
targetMemoryUtilizationPercentage: 50
# NetworkPolicy for default backend component.
networkPolicy:
# -- Enable 'networkPolicy' or not
enabled: false
service:
annotations: {}
# clusterIP: ""
@@ -909,8 +939,8 @@ appsec:
image:
#registry:
repository: ghcr.io/openappsec
image: agent
tag: latest
image: "agent"
tag: "latest"
pullPolicy: Always
securityContext: {}

View File

@@ -1,5 +1,98 @@
# Changelog
## Unreleased
Nothing yet.
## 2.29.0
### Improvements
* Make it possible to set the admission webhook's `timeoutSeconds`.
## 2.28.1
### Fixed
* The admission webhook now includes Gateway API resources and Ingress
resources for controller versions 2.12+. This version introduces new
validations for Kong's regex path implementation.
## 2.28.0
### Improvements
* Bump default `kong` image tag to 3.4.
[#883](https://github.com/Kong/charts/pull/883)
* Bump default ingress controller image tag to 2.12.
* Added validation rule for `latency` upstream load balancing algorithm to
CRDs. [Upgrade your CRDs](https://github.com/Kong/charts/blob/main/charts/kong/UPGRADE.md#updates-to-crds)
when installing this release.
## 2.27.0
### Improvements
* Listens now all support `.address` configuration. This was an existing
setting that was not applied properly for some listens.
[#881](https://github.com/Kong/charts/pull/881)
## 2.26.5
### Fixed
* Kuma ServiceAccount Token hints and volumes are also available in migrations
Pods.
[#877](https://github.com/Kong/charts/pull/877)
## 2.26.4
### Fixed
* updated `admin_api_uri` to `admin_gui_api_url` as per [kong documentation](https://docs.konghq.com/gateway/3.4.x/reference/configuration/#admin_api_uri).
## 2.26.3
### Fixed
* Enabled Service and Ingress in Kong Manager for non enterprise users.
## 2.26.2
### Fixed
* Add missing CRD KongConsumerGroup and extend status subresource for CRDs
## 2.26.1
### Fixed
* Fix parsing enterprise tags (like e.g. `3.4.0.0`)
[#857](https://github.com/Kong/charts/pull/857)
## 2.26.0
### Breaking changes
2.26 changes the default proxy readiness endpoint for newer Kong versions. This
causes an issue in a narrow edge case. If all of the following are true:
* You use Kong 3.3 or newer.
* You use controller 2.10 or older.
* You run the controller and proxy in separate Deployments.
you are affected and should review [the 2.26 upgrade instructions](https://github.com/Kong/charts/blob/main/charts/kong/UPGRADE.md#2260).
### Improvements
* Use the Kong 3.3 `/status/ready` endpoint for readiness probes by default if
available. If not available, use the old `/status` default.
[#844](https://github.com/Kong/charts/pull/844)
* Add ArgoCD `Sync` and `BeforeHookCreation` [hook policies](https://argo-cd.readthedocs.io/en/stable/user-guide/resource_hooks/)
to the the init and pre-upgrade migrations Jobs.
* Add controller's RBAC rules for `KongConsumerGroups` CRD.
[#850](https://github.com/Kong/charts/pull/850)
* Updated controller version to 2.11.
## 2.25.0
- Generate the `adminApiService.name` value from `.Release.Name` rather than

View File

@@ -1,5 +1,5 @@
apiVersion: v2
appVersion: "3.3"
appVersion: 1.1.0
dependencies:
- condition: postgresql.enabled
name: postgresql
@@ -16,4 +16,4 @@ maintainers:
name: open-appsec-kong
sources:
- https://github.com/Kong/charts/tree/main/charts/kong
version: 2.25.0
version: 2.29.0

View File

@@ -71,6 +71,7 @@ $ helm install kong/kong --generate-name
- [Sessions](#sessions)
- [Email/SMTP](#emailsmtp)
- [Prometheus Operator integration](#prometheus-operator-integration)
- [Argo CD considerations](#argo-cd-considerations)
- [Changelog](https://github.com/Kong/charts/blob/main/charts/kong/CHANGELOG.md)
- [Upgrading](https://github.com/Kong/charts/blob/main/charts/kong/UPGRADE.md)
- [Seeking help](#seeking-help)
@@ -599,7 +600,8 @@ directory.
| Parameter | Description | Default |
| ---------------------------------- | ------------------------------------------------------------------------------------- | ------------------- |
| image.repository | Kong image | `kong` |
| image.tag | Kong image version | `2.5` |
| image.tag | Kong image version | `3.4` |
| image.effectiveSemver | Semantic version to use for version-dependent features (if `tag` is not a semver) | |
| image.pullPolicy | Image pull policy | `IfNotPresent` |
| image.pullSecrets | Image pull secrets | `null` |
| replicaCount | Kong instance count. It has no effect when `autoscaling.enabled` is set to true | `1` |
@@ -723,7 +725,7 @@ section of `values.yaml` file:
|--------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------|
| enabled | Deploy the ingress controller, rbac and crd | true |
| image.repository | Docker image with the ingress controller | kong/kubernetes-ingress-controller |
| image.tag | Version of the ingress controller | 2.0 |
| image.tag | Version of the ingress controller | `2.12` |
| image.effectiveSemver | Version of the ingress controller used for version-specific features when image.tag is not a valid semantic version | |
| readinessProbe | Kong ingress controllers readiness probe | |
| livenessProbe | Kong ingress controllers liveness probe | |
@@ -737,11 +739,13 @@ section of `values.yaml` file:
| admissionWebhook.enabled | Whether to enable the validating admission webhook | true |
| admissionWebhook.failurePolicy | How unrecognized errors from the admission endpoint are handled (Ignore or Fail) | Ignore |
| admissionWebhook.port | The port the ingress controller will listen on for admission webhooks | 8080 |
| admissionWebhook.address | The address the ingress controller will listen on for admission webhooks, if not 0.0.0.0 | |
| admissionWebhook.annotations | Annotations for the Validation Webhook Configuration | |
| admissionWebhook.certificate.provided | Use a provided certificate. When set to false, the chart will automatically generate a certificate. | false |
| admissionWebhook.certificate.secretName | Name of the TLS secret for the provided webhook certificate | |
| admissionWebhook.certificate.caBundle | PEM encoded CA bundle which will be used to validate the provided webhook certificate | |
| admissionWebhook.namespaceSelector | Add namespaceSelector to the webhook. Please go to [Kubernetes doc for the specs](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#matching-requests-namespaceselector) | |
| admissionWebhook.timeoutSeconds | Kubernetes `apiserver`'s timeout when running this webhook. Default: 10 seconds. | |
| userDefinedVolumes | Create volumes. Please go to Kubernetes doc for the spec of the volumes | |
| userDefinedVolumeMounts | Create volumeMounts. Please go to Kubernetes doc for the spec of the volumeMounts | |
| terminationGracePeriodSeconds | Sets the [termination grace period](https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#hook-handler-execution) for Deployment pod | 30 |
@@ -1045,7 +1049,7 @@ must know where other Kong services (namely the admin and files APIs) can be
accessed in order to function properly. Kong's default behavior for attempting
to locate these absent configuration is unlikely to work in common Kubernetes
environments. Because of this, you should set each of `admin_gui_url`,
`admin_api_uri`, `proxy_url`, `portal_api_url`, `portal_gui_host`, and
`admin_gui_api_url`, `proxy_url`, `portal_api_url`, `portal_gui_host`, and
`portal_gui_protocol` under the `.env` key in values.yaml to locations where
each of their respective services can be accessed to ensure that Kong services
can locate one another and properly set CORS headers. See the
@@ -1161,6 +1165,28 @@ admin:
enable-metrics: "true"
```
## Argo CD Considerations
The built-in database subchart (`postgresql.enabled` in values) is not
supported when installing the chart via Argo CD.
Argo CD does not support the full Helm lifecycle. There is no distinction
between the initial install and upgrades. Both operations are a "sync" in Argo
terms. This affects when migration Jobs execute in database-backed Kong
installs.
The chart sets the `Sync` and `BeforeHookCreation` deletion
[hook policies](https://argo-cd.readthedocs.io/en/stable/user-guide/resource_hooks/)
on the `init-migrations` and `pre-upgrade-migrations` Jobs.
The `pre-upgrade-migrations` Job normally uses Helm's `pre-upgrade` policy. Argo
translates this to its `PreSync` policy, which would create the Job before all
sync phase resources. Doing this before various sync phase resources (such as
the ServiceAccount) are in place would prevent the Job from running
successfully. Overriding this with Argo's `Sync` policy starts the Job at the
same time as the upgraded Deployment Pods. The new Pods may fail to start
temporarily, but will eventually start normally once migrations complete.
## Seeking help
If you run into an issue, bug or have a question, please reach out to the Kong

View File

@@ -17,7 +17,8 @@ upgrading from a previous version.
## Table of contents
- [Upgrade considerations for all versions](#upgrade-considerations-for-all-versions)
- [2.17.0](#2170)
- [2.26.0](#2260)
- [2.19.0](#2190)
- [2.13.0](#2130)
- [2.8.0](#280)
- [2.7.0](#270)
@@ -83,6 +84,35 @@ https://raw.githubusercontent.com/Kong/charts/kong-<version>/charts/kong/crds/cu
For example, if your release is 2.6.4, you would apply
`https://raw.githubusercontent.com/Kong/charts/kong-2.6.4/charts/kong/crds/custom-resource-definitions.yaml`.
## 2.26.0
If you are using controller version 2.10 or lower and proxy version 3.3 or
higher in separate Deployments (such as when using the `ingress` chart), proxy
Pods will not become ready unless you override the default readiness endpoint:
```
readinessProbe:
httpGet:
path: /status
```
This section goes under the `gateway` section when using the `ingress` chart.
2.26 changes the default proxy readiness endpoint to the `/status/ready`
endpoint introduced in Kong 3.3. This endpoint reports true when Kong has
configuration available, whereas the previous `/status` endpoint returned true
immediately after start, and could result in proxy instances attempting to
serve requests before they had configuration.
The chart has logic to fall back to the older endpoint if the proxy and
controller versions do not work well with the new endpoint. However, the chart
detection cannot determine the controller version when the controller is in a
separate Deployment, and will always use the new endpoint if the Kong image
version is 3.3 or higher.
Kong recommends Kong 3.3 and higher users update to controller 2.11 at their
earliest convenience to take advantage of the improved readiness behavior.
## 2.19.0
2.19 sets a default [security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/)

View File

@@ -0,0 +1,18 @@
admin:
enabled: true
type: ClusterIP
# Stub config to make the instance become ready
dblessConfig:
config: |
_format_version: "1.1"
services:
- name: example.com
url: http://example.com
routes:
- name: example
paths:
- "/example"
ingressController:
enabled: false

View File

@@ -1,6 +0,0 @@
admin:
enabled: true
type: ClusterIP
ingressController:
enabled: false

View File

@@ -1,6 +1,3 @@
# install chart with some extra labels
extraLabels:
acme.com/some-key: some-value

View File

@@ -1,7 +1,4 @@
# install chart with default values
proxy:
type: NodePort
env:
anonymous_reports: "off"
ingressController:

View File

@@ -1,6 +1,5 @@
# CI test for empty hostname including tls secret using string
proxy:
type: NodePort
ingress:
enabled: true
tls: "kong.proxy.example.secret"

View File

@@ -1,6 +1,5 @@
# CI test for hostname including tls secret using string
proxy:
type: NodePort
ingress:
enabled: true
hostname: "proxy.kong.example"

View File

@@ -1,6 +1,5 @@
# CI test for using ingress hosts configuration
proxy:
type: NodePort
ingress:
enabled: true
hosts:

View File

@@ -1,6 +1,5 @@
# CI test for testing combined ingress hostname and hosts configuration including tls configuraion using slice
proxy:
type: NodePort
ingress:
enabled: true
hostname: "proxy.kong.example"

View File

@@ -2,9 +2,7 @@
# use single image strings instead of repository/tag
image:
unifiedRepoTag: kong:2.6
proxy:
type: NodePort
unifiedRepoTag: kong:3.4
env:
anonymous_reports: "off"
@@ -12,4 +10,4 @@ ingressController:
env:
anonymous_reports: "false"
image:
unifiedRepoTag: kong/kubernetes-ingress-controller:2.0.2
unifiedRepoTag: kong/kubernetes-ingress-controller:2.12

View File

@@ -0,0 +1,14 @@
ingressController:
enabled: false
image:
repository: kong/kong-gateway
tag: "3.4.0.0"
readinessProbe:
httpGet:
path: "/status"
port: status
scheme: HTTP
initialDelaySeconds: 1
periodSeconds: 1

View File

@@ -30,14 +30,12 @@ podLabels:
environment: test
# - ingress resources are created with hosts
admin:
type: NodePort
ingress:
enabled: true
hostname: admin.kong.example
annotations: {}
path: /
proxy:
type: NodePort
ingress:
enabled: true
hostname: proxy.kong.example

View File

@@ -3,8 +3,12 @@
# - stream listens work
# - a mixture of controller, Kong, and shared volumes successfully mount
# - watchNamespaces is set
# - the admission webhook is enabled; has the timeout explicitly set
ingressController:
enabled: true
admissionWebhook:
enabled: true
timeoutSeconds: 5
env:
anonymous_reports: "false"
customEnv:
@@ -21,13 +25,11 @@ env:
database: "postgres"
# - ingress resources are created without hosts
admin:
type: NodePort
ingress:
enabled: true
hosts: []
path: /
proxy:
type: NodePort
ingress:
enabled: true
hostname: proxy.kong.example

View File

@@ -8,8 +8,6 @@ env:
database: "off"
postgresql:
enabled: false
proxy:
type: NodePort
deployment:
initContainers:
- name: "bash"

View File

@@ -12,7 +12,6 @@ env:
postgresql:
enabled: false
proxy:
type: NodePort
# - add stream listens
stream:
- containerPort: 9000

View File

@@ -26,13 +26,11 @@ customEnv:
client_id: "exampleId"
# - ingress resources are created without hosts
admin:
type: NodePort
ingress:
enabled: true
hosts: []
path: /
proxy:
type: NodePort
ingress:
enabled: true
hostname: proxy.kong.example

View File

@@ -1,34 +0,0 @@
# CI test for testing dbless deployment without ingress controllers
# - disable ingress controller
# - no static config
ingressController:
enabled: false
# - disable DB for kong
env:
anonymous_reports: "off"
database: "off"
postgresql:
enabled: false
proxy:
type: NodePort
deployment:
initContainers:
- name: "bash"
image: "bash:latest"
command: ["/bin/sh", "-c", "true"]
resources:
limits:
cpu: "100m"
memory: "64Mi"
requests:
cpu: "100m"
memory: "64Mi"
volumeMounts:
- name: "tmpdir"
mountPath: "/opt/tmp"
userDefinedVolumes:
- name: "tmpdir"
emptyDir: {}
userDefinedVolumeMounts:
- name: "tmpdir"
mountPath: "/opt/tmp"

View File

@@ -1,10 +1,9 @@
# generated using: kubectl kustomize github.com/kong/kubernetes-ingress-controller/config/crd?ref=v2.8.1
# generated using: kubectl kustomize 'github.com/kong/kubernetes-ingress-controller/config/crd?ref=v2.12.0'
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.11.1
creationTimestamp: null
controller-gen.kubebuilder.io/version: v0.13.0
name: ingressclassparameterses.configuration.konghq.com
spec:
group: configuration.konghq.com
@@ -56,8 +55,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.11.1
creationTimestamp: null
controller-gen.kubebuilder.io/version: v0.13.0
name: kongclusterplugins.configuration.konghq.com
spec:
group: configuration.konghq.com
@@ -91,6 +89,9 @@ spec:
name: Config
priority: 1
type: string
- jsonPath: .status.conditions[?(@.type=="Programmed")].status
name: Programmed
type: string
name: v1
schema:
openAPIV3Schema:
@@ -142,6 +143,11 @@ spec:
disabled:
description: Disabled set if the plugin is disabled or not.
type: boolean
instance_name:
description: InstanceName is an optional custom name to identify an instance
of the plugin. This is useful when running the same plugin in multiple
contexts, for example, on multiple services.
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
@@ -183,6 +189,8 @@ spec:
description: Protocols configures plugin to run on requests received on
specific protocols.
items:
description: KongProtocol is a valid Kong protocol. This alias is necessary
to deal with https://github.com/kubernetes-sigs/controller-tools/issues/342
enum:
- http
- https
@@ -201,6 +209,91 @@ spec:
- second
- all
type: string
status:
description: Status represents the current status of the KongClusterPlugin
resource.
properties:
conditions:
default:
- lastTransitionTime: "1970-01-01T00:00:00Z"
message: Waiting for controller
reason: Pending
status: Unknown
type: Programmed
description: "Conditions describe the current conditions of the KongClusterPluginStatus.
\n Known condition types are: \n * \"Programmed\""
items:
description: "Condition contains details for one aspect of the current
state of this API Resource. --- This struct is intended for direct
use as an array at the field path .status.conditions. For example,
\n type FooStatus struct{ // Represents the observations of a
foo's current state. // Known .status.conditions.type are: \"Available\",
\"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
// +listType=map // +listMapKey=type Conditions []metav1.Condition
`json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
properties:
lastTransitionTime:
description: lastTransitionTime is the last time the condition
transitioned from one status to another. This should be when
the underlying condition changed. If that is not known, then
using the time when the API field changed is acceptable.
format: date-time
type: string
message:
description: message is a human readable message indicating
details about the transition. This may be an empty string.
maxLength: 32768
type: string
observedGeneration:
description: observedGeneration represents the .metadata.generation
that the condition was set based upon. For instance, if .metadata.generation
is currently 12, but the .status.conditions[x].observedGeneration
is 9, the condition is out of date with respect to the current
state of the instance.
format: int64
minimum: 0
type: integer
reason:
description: reason contains a programmatic identifier indicating
the reason for the condition's last transition. Producers
of specific condition types may define expected values and
meanings for this field, and whether the values are considered
a guaranteed API. The value should be a CamelCase string.
This field may not be empty.
maxLength: 1024
minLength: 1
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
type: string
status:
description: status of the condition, one of True, False, Unknown.
enum:
- "True"
- "False"
- Unknown
type: string
type:
description: type of condition in CamelCase or in foo.example.com/CamelCase.
--- Many .condition.type values are consistent across resources
like Available, but because arbitrary conditions can be useful
(see .node.status.conditions), the ability to deconflict is
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
maxLength: 316
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
type: string
required:
- lastTransitionTime
- message
- reason
- status
- type
type: object
maxItems: 8
type: array
x-kubernetes-list-map-keys:
- type
x-kubernetes-list-type: map
type: object
required:
- plugin
type: object
@@ -213,8 +306,142 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.11.1
creationTimestamp: null
controller-gen.kubebuilder.io/version: v0.13.0
name: kongconsumergroups.configuration.konghq.com
spec:
group: configuration.konghq.com
names:
categories:
- kong-ingress-controller
kind: KongConsumerGroup
listKind: KongConsumerGroupList
plural: kongconsumergroups
shortNames:
- kcg
singular: kongconsumergroup
scope: Namespaced
versions:
- additionalPrinterColumns:
- description: Age
jsonPath: .metadata.creationTimestamp
name: Age
type: date
- jsonPath: .status.conditions[?(@.type=="Programmed")].status
name: Programmed
type: string
name: v1beta1
schema:
openAPIV3Schema:
description: KongConsumerGroup is the Schema for the kongconsumergroups API.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
status:
description: Status represents the current status of the KongConsumer
resource.
properties:
conditions:
default:
- lastTransitionTime: "1970-01-01T00:00:00Z"
message: Waiting for controller
reason: Pending
status: Unknown
type: Programmed
description: "Conditions describe the current conditions of the KongConsumerGroup.
\n Known condition types are: \n * \"Programmed\""
items:
description: "Condition contains details for one aspect of the current
state of this API Resource. --- This struct is intended for direct
use as an array at the field path .status.conditions. For example,
\n type FooStatus struct{ // Represents the observations of a
foo's current state. // Known .status.conditions.type are: \"Available\",
\"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
// +listType=map // +listMapKey=type Conditions []metav1.Condition
`json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
properties:
lastTransitionTime:
description: lastTransitionTime is the last time the condition
transitioned from one status to another. This should be when
the underlying condition changed. If that is not known, then
using the time when the API field changed is acceptable.
format: date-time
type: string
message:
description: message is a human readable message indicating
details about the transition. This may be an empty string.
maxLength: 32768
type: string
observedGeneration:
description: observedGeneration represents the .metadata.generation
that the condition was set based upon. For instance, if .metadata.generation
is currently 12, but the .status.conditions[x].observedGeneration
is 9, the condition is out of date with respect to the current
state of the instance.
format: int64
minimum: 0
type: integer
reason:
description: reason contains a programmatic identifier indicating
the reason for the condition's last transition. Producers
of specific condition types may define expected values and
meanings for this field, and whether the values are considered
a guaranteed API. The value should be a CamelCase string.
This field may not be empty.
maxLength: 1024
minLength: 1
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
type: string
status:
description: status of the condition, one of True, False, Unknown.
enum:
- "True"
- "False"
- Unknown
type: string
type:
description: type of condition in CamelCase or in foo.example.com/CamelCase.
--- Many .condition.type values are consistent across resources
like Available, but because arbitrary conditions can be useful
(see .node.status.conditions), the ability to deconflict is
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
maxLength: 316
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
type: string
required:
- lastTransitionTime
- message
- reason
- status
- type
type: object
maxItems: 8
type: array
x-kubernetes-list-map-keys:
- type
x-kubernetes-list-type: map
type: object
type: object
served: true
storage: true
subresources:
status: {}
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.13.0
name: kongconsumers.configuration.konghq.com
spec:
group: configuration.konghq.com
@@ -238,6 +465,9 @@ spec:
jsonPath: .metadata.creationTimestamp
name: Age
type: date
- jsonPath: .status.conditions[?(@.type=="Programmed")].status
name: Programmed
type: string
name: v1
schema:
openAPIV3Schema:
@@ -248,6 +478,12 @@ spec:
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
consumerGroups:
description: ConsumerGroups are references to consumer groups (that consumer
wants to be part of) provisioned in Kong.
items:
type: string
type: array
credentials:
description: Credentials are references to secrets containing a credential
to be provisioned in Kong.
@@ -265,6 +501,91 @@ spec:
type: string
metadata:
type: object
status:
description: Status represents the current status of the KongConsumer
resource.
properties:
conditions:
default:
- lastTransitionTime: "1970-01-01T00:00:00Z"
message: Waiting for controller
reason: Pending
status: Unknown
type: Programmed
description: "Conditions describe the current conditions of the KongConsumer.
\n Known condition types are: \n * \"Programmed\""
items:
description: "Condition contains details for one aspect of the current
state of this API Resource. --- This struct is intended for direct
use as an array at the field path .status.conditions. For example,
\n type FooStatus struct{ // Represents the observations of a
foo's current state. // Known .status.conditions.type are: \"Available\",
\"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
// +listType=map // +listMapKey=type Conditions []metav1.Condition
`json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
properties:
lastTransitionTime:
description: lastTransitionTime is the last time the condition
transitioned from one status to another. This should be when
the underlying condition changed. If that is not known, then
using the time when the API field changed is acceptable.
format: date-time
type: string
message:
description: message is a human readable message indicating
details about the transition. This may be an empty string.
maxLength: 32768
type: string
observedGeneration:
description: observedGeneration represents the .metadata.generation
that the condition was set based upon. For instance, if .metadata.generation
is currently 12, but the .status.conditions[x].observedGeneration
is 9, the condition is out of date with respect to the current
state of the instance.
format: int64
minimum: 0
type: integer
reason:
description: reason contains a programmatic identifier indicating
the reason for the condition's last transition. Producers
of specific condition types may define expected values and
meanings for this field, and whether the values are considered
a guaranteed API. The value should be a CamelCase string.
This field may not be empty.
maxLength: 1024
minLength: 1
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
type: string
status:
description: status of the condition, one of True, False, Unknown.
enum:
- "True"
- "False"
- Unknown
type: string
type:
description: type of condition in CamelCase or in foo.example.com/CamelCase.
--- Many .condition.type values are consistent across resources
like Available, but because arbitrary conditions can be useful
(see .node.status.conditions), the ability to deconflict is
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
maxLength: 316
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
type: string
required:
- lastTransitionTime
- message
- reason
- status
- type
type: object
maxItems: 8
type: array
x-kubernetes-list-map-keys:
- type
x-kubernetes-list-type: map
type: object
username:
description: Username is a Kong cluster-unique username of the consumer.
type: string
@@ -278,8 +599,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.11.1
creationTimestamp: null
controller-gen.kubebuilder.io/version: v0.13.0
name: kongingresses.configuration.konghq.com
spec:
group: configuration.konghq.com
@@ -381,8 +701,7 @@ spec:
type: integer
methods:
description: 'Methods is a list of HTTP methods that match this Route.
Deprecated: use Ingress'' "konghq.com/override-protocols" annotation
instead.'
Deprecated: use Ingress'' "konghq.com/methods" annotation instead.'
items:
type: string
type: array
@@ -407,6 +726,8 @@ spec:
allow. Deprecated: use Ingress'' "konghq.com/protocols" annotation
instead.'
items:
description: KongProtocol is a valid Kong protocol. This alias is
necessary to deal with https://github.com/kubernetes-sigs/controller-tools/issues/342
enum:
- http
- https
@@ -448,8 +769,8 @@ spec:
type: object
upstream:
description: Upstream represents a virtual hostname and can be used to
load balance incoming requests over multiple targets (e.g. Kubernetes
Services can be a target, or URLs can be targets).
loadbalance incoming requests over multiple targets (e.g. Kubernetes
`Services` can be a target, OR `Endpoints` can be targets).
properties:
algorithm:
description: Algorithm is the load balancing algorithm to use.
@@ -457,6 +778,7 @@ spec:
- round-robin
- consistent-hashing
- least-connections
- latency
type: string
hash_fallback:
description: 'HashFallback defines What to use as hashing input if
@@ -512,6 +834,12 @@ spec:
concurrency:
minimum: 1
type: integer
headers:
additionalProperties:
items:
type: string
type: array
type: object
healthy:
description: Healthy configures thresholds and HTTP status
codes to mark targets healthy for an upstream.
@@ -626,8 +954,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.11.1
creationTimestamp: null
controller-gen.kubebuilder.io/version: v0.13.0
name: kongplugins.configuration.konghq.com
spec:
group: configuration.konghq.com
@@ -661,6 +988,9 @@ spec:
name: Config
priority: 1
type: string
- jsonPath: .status.conditions[?(@.type=="Programmed")].status
name: Programmed
type: string
name: v1
schema:
openAPIV3Schema:
@@ -708,6 +1038,11 @@ spec:
disabled:
description: Disabled set if the plugin is disabled or not.
type: boolean
instance_name:
description: InstanceName is an optional custom name to identify an instance
of the plugin. This is useful when running the same plugin in multiple
contexts, for example, on multiple services.
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
@@ -749,6 +1084,8 @@ spec:
description: Protocols configures plugin to run on requests received on
specific protocols.
items:
description: KongProtocol is a valid Kong protocol. This alias is necessary
to deal with https://github.com/kubernetes-sigs/controller-tools/issues/342
enum:
- http
- https
@@ -767,6 +1104,90 @@ spec:
- second
- all
type: string
status:
description: Status represents the current status of the KongPlugin resource.
properties:
conditions:
default:
- lastTransitionTime: "1970-01-01T00:00:00Z"
message: Waiting for controller
reason: Pending
status: Unknown
type: Programmed
description: "Conditions describe the current conditions of the KongPluginStatus.
\n Known condition types are: \n * \"Programmed\""
items:
description: "Condition contains details for one aspect of the current
state of this API Resource. --- This struct is intended for direct
use as an array at the field path .status.conditions. For example,
\n type FooStatus struct{ // Represents the observations of a
foo's current state. // Known .status.conditions.type are: \"Available\",
\"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
// +listType=map // +listMapKey=type Conditions []metav1.Condition
`json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
properties:
lastTransitionTime:
description: lastTransitionTime is the last time the condition
transitioned from one status to another. This should be when
the underlying condition changed. If that is not known, then
using the time when the API field changed is acceptable.
format: date-time
type: string
message:
description: message is a human readable message indicating
details about the transition. This may be an empty string.
maxLength: 32768
type: string
observedGeneration:
description: observedGeneration represents the .metadata.generation
that the condition was set based upon. For instance, if .metadata.generation
is currently 12, but the .status.conditions[x].observedGeneration
is 9, the condition is out of date with respect to the current
state of the instance.
format: int64
minimum: 0
type: integer
reason:
description: reason contains a programmatic identifier indicating
the reason for the condition's last transition. Producers
of specific condition types may define expected values and
meanings for this field, and whether the values are considered
a guaranteed API. The value should be a CamelCase string.
This field may not be empty.
maxLength: 1024
minLength: 1
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
type: string
status:
description: status of the condition, one of True, False, Unknown.
enum:
- "True"
- "False"
- Unknown
type: string
type:
description: type of condition in CamelCase or in foo.example.com/CamelCase.
--- Many .condition.type values are consistent across resources
like Available, but because arbitrary conditions can be useful
(see .node.status.conditions), the ability to deconflict is
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
maxLength: 316
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
type: string
required:
- lastTransitionTime
- message
- reason
- status
- type
type: object
maxItems: 8
type: array
x-kubernetes-list-map-keys:
- type
x-kubernetes-list-type: map
type: object
required:
- plugin
type: object
@@ -779,8 +1200,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.11.1
creationTimestamp: null
controller-gen.kubebuilder.io/version: v0.13.0
name: tcpingresses.configuration.konghq.com
spec:
group: configuration.konghq.com
@@ -966,8 +1386,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.11.1
creationTimestamp: null
controller-gen.kubebuilder.io/version: v0.13.0
name: udpingresses.configuration.konghq.com
spec:
group: configuration.konghq.com

View File

@@ -88,7 +88,7 @@ enterprise:
enabled: true
env:
admin_access_log: /dev/stdout
admin_api_uri: https://kong.127-0-0-1.nip.io/api
admin_gui_api_url: https://kong.127-0-0-1.nip.io/api
admin_error_log: /dev/stdout
admin_gui_access_log: /dev/stdout
admin_gui_error_log: /dev/stdout
@@ -146,7 +146,7 @@ extraLabels:
konghq.com/component: quickstart
image:
repository: kong/kong-gateway
tag: "3.3"
tag: "3.4"
ingressController:
enabled: true
env:

View File

@@ -12,7 +12,7 @@
image:
repository: kong/kong-gateway
tag: "3.3"
tag: "3.4"
env:
prefix: /kong_prefix/

View File

@@ -9,7 +9,7 @@
image:
repository: kong/kong-gateway
tag: "3.3"
tag: "3.4"
admin:
enabled: true

View File

@@ -2,7 +2,7 @@
image:
repository: kong
tag: "3.3"
tag: "3.4"
env:
prefix: /kong_prefix/

View File

@@ -4,7 +4,7 @@
image:
repository: kong/kong-gateway
tag: "3.3"
tag: "3.4"
enterprise:
enabled: true

View File

@@ -14,7 +14,7 @@
image:
repository: kong/kong-gateway
tag: "3.3"
tag: "3.4"
env:
database: postgres

View File

@@ -12,7 +12,7 @@
image:
repository: kong/kong-gateway
tag: "3.3"
tag: "3.4"
env:
role: data_plane

View File

@@ -6,7 +6,7 @@
image:
repository: kong
tag: "3.3"
tag: "3.4"
env:
prefix: /kong_prefix/

View File

@@ -11,7 +11,7 @@
image:
repository: kong
tag: "3.3"
tag: "3.4"
env:
prefix: /kong_prefix/

View File

@@ -6,7 +6,7 @@
image:
repository: kong
tag: "3.3"
tag: "3.4"
env:
prefix: /kong_prefix/

View File

@@ -330,10 +330,11 @@ Create KONG_STREAM_LISTEN string
*/}}
{{- define "kong.streamListen" -}}
{{- $unifiedListen := list -}}
{{- $address := (default "0.0.0.0" .address) -}}
{{- range .stream -}}
{{- $listenConfig := dict -}}
{{- $listenConfig := merge $listenConfig . -}}
{{- $_ := set $listenConfig "address" "0.0.0.0" -}}
{{- $_ := set $listenConfig "address" $address -}}
{{/* You set NGINX stream listens to UDP using a parameter due to historical reasons.
Our configuration is dual-purpose, for both the Service and listen string, so we
forcibly inject this parameter if that's the Service protocol. The default handles
@@ -458,7 +459,8 @@ The name of the service used for the ingress controller's validation webhook
{{- $_ := set $autoEnv "CONTROLLER_ELECTION_ID" (printf "kong-ingress-controller-leader-%s" .Values.ingressController.ingressClass) -}}
{{- if .Values.ingressController.admissionWebhook.enabled }}
{{- $_ := set $autoEnv "CONTROLLER_ADMISSION_WEBHOOK_LISTEN" (printf "0.0.0.0:%d" (int64 .Values.ingressController.admissionWebhook.port)) -}}
{{- $address := (default "0.0.0.0" .Values.ingressController.admissionWebhook.address) -}}
{{- $_ := set $autoEnv "CONTROLLER_ADMISSION_WEBHOOK_LISTEN" (printf "%s:%d" $address (int64 .Values.ingressController.admissionWebhook.port)) -}}
{{- end }}
{{- if (not (eq (len .Values.ingressController.watchNamespaces) 0)) }}
{{- $_ := set $autoEnv "CONTROLLER_WATCH_NAMESPACE" (.Values.ingressController.watchNamespaces | join ",") -}}
@@ -552,6 +554,41 @@ The name of the service used for the ingress controller's validation webhook
- name: {{ template "kong.fullname" . }}-tmp
emptyDir:
sizeLimit: {{ .Values.deployment.tmpDir.sizeLimit }}
{{- if (and (not .Values.deployment.serviceAccount.automountServiceAccountToken) (or .Values.deployment.serviceAccount.create .Values.deployment.serviceAccount.name)) }}
- name: {{ template "kong.serviceAccountTokenName" . }}
{{- /* Due to GKE versions (e.g. v1.23.15-gke.1900) we need to handle pre-release part of the version as well.
See the related documentation of semver module that Helm depends on for semverCompare:
https://github.com/Masterminds/semver#working-with-prerelease-versions
Related Helm issue: https://github.com/helm/helm/issues/3810 */}}
{{- if semverCompare ">=1.20.0-0" .Capabilities.KubeVersion.Version }}
projected:
sources:
- serviceAccountToken:
expirationSeconds: 3607
path: token
- configMap:
items:
- key: ca.crt
path: ca.crt
name: kube-root-ca.crt
- downwardAPI:
items:
- fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
path: namespace
{{- else }}
secret:
secretName: {{ template "kong.serviceAccountTokenName" . }}
items:
- key: token
path: token
- key: ca.crt
path: ca.crt
- key: namespace
path: namespace
{{- end }}
{{- end }}
{{- if and ( .Capabilities.APIVersions.Has "cert-manager.io/v1" ) .Values.certificates.enabled -}}
{{- if .Values.certificates.cluster.enabled }}
- name: {{ include "kong.fullname" . }}-cluster-cert
@@ -786,10 +823,22 @@ The name of the service used for the ingress controller's validation webhook
{{/* effectiveVersion takes an image dict from values.yaml. if .effectiveSemver is set, it returns that, else it returns .tag */}}
{{- define "kong.effectiveVersion" -}}
{{- /* Because Kong Gateway enterprise uses versions with 4 segments and not 3 */ -}}
{{- /* as semver does, we need to account for that here by extracting */ -}}
{{- /* first 3 segments for comparison */ -}}
{{- if .effectiveSemver -}}
{{- .effectiveSemver -}}
{{- if regexMatch "^[0-9]+.[0-9]+.[0-9]+" .effectiveSemver -}}
{{- regexFind "^[0-9]+.[0-9]+.[0-9]+" .effectiveSemver -}}
{{- else -}}
{{- .effectiveSemver -}}
{{- end -}}
{{- else -}}
{{- (trimSuffix "-redhat" .tag) -}}
{{- $tag := (trimSuffix "-redhat" .tag) -}}
{{- if regexMatch "^[0-9]+.[0-9]+.[0-9]+" .tag -}}
{{- regexFind "^[0-9]+.[0-9]+.[0-9]+" .tag -}}
{{- else -}}
{{- .tag -}}
{{- end -}}
{{- end -}}
{{- end -}}
@@ -908,7 +957,7 @@ the template that it itself is using form the above sections.
{{- end -}}
{{- $listenConfig := dict -}}
{{- $listenConfig := merge $listenConfig . -}}
{{- $_ := set $listenConfig "address" $address -}}
{{- $_ := set $listenConfig "address" (default $address .address) -}}
{{- $_ := set $autoEnv "KONG_ADMIN_LISTEN" (include "kong.listen" $listenConfig) -}}
{{- if or .tls.client.secretName .tls.client.caBundle -}}
@@ -952,6 +1001,7 @@ the template that it itself is using form the above sections.
{{- end -}}
{{- if .Values.admin.ingress.enabled }}
{{- $_ := set $autoEnv "KONG_ADMIN_GUI_API_URL" (include "kong.ingress.serviceUrl" .Values.admin.ingress) -}}
{{- $_ := set $autoEnv "KONG_ADMIN_API_URI" (include "kong.ingress.serviceUrl" .Values.admin.ingress) -}}
{{- end -}}
@@ -1203,6 +1253,24 @@ resource roles into their separate templates.
- namespaces
verbs:
- list
{{- if (semverCompare ">= 2.11.0" (include "kong.effectiveVersion" .Values.ingressController.image)) }}
- apiGroups:
- configuration.konghq.com
resources:
- kongconsumergroups
verbs:
- get
- list
- watch
- apiGroups:
- configuration.konghq.com
resources:
- kongconsumergroups/status
verbs:
- get
- patch
- update
{{- end }}
{{- if (semverCompare "< 2.10.0" (include "kong.effectiveVersion" .Values.ingressController.image)) }}
- apiGroups:
- ""
@@ -1614,6 +1682,16 @@ networking.k8s.io/v1beta1
extensions/v1beta1
{{- end -}}
{{- end -}}
{{- define "kong.proxy.compatibleReadiness" -}}
{{- $proxyReadiness := .Values.readinessProbe -}}
{{- if (or (semverCompare "< 3.3.0" (include "kong.effectiveVersion" .Values.image)) (and .Values.ingressController.enabled (semverCompare "< 2.11.0" (include "kong.effectiveVersion" .Values.ingressController.image)))) -}}
{{- if (eq $proxyReadiness.httpGet.path "/status/ready") -}}
{{- $_ := set $proxyReadiness.httpGet "path" "/status" -}}
{{- end -}}
{{- end -}}
{{- (toYaml $proxyReadiness) -}}
{{- end -}}
{{/*
appsec labels
*/}}

View File

@@ -46,6 +46,9 @@ webhooks:
namespaceSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.ingressController.admissionWebhook.timeoutSeconds }}
timeoutSeconds: {{ . }}
{{- end }}
objectSelector:
matchExpressions:
- key: owner
@@ -80,6 +83,28 @@ webhooks:
- UPDATE
resources:
- secrets
{{- if (semverCompare ">= 2.12.0" (include "kong.effectiveVersion" .Values.ingressController.image)) }}
- apiGroups:
- networking.k8s.io
apiVersions:
- 'v1'
operations:
- CREATE
- UPDATE
resources:
- ingresses
- apiGroups:
- gateway.networking.k8s.io
apiVersions:
- 'v1alpha2'
- 'v1beta1'
operations:
- CREATE
- UPDATE
resources:
- gateways
- httproutes
{{- end }}
clientConfig:
{{- if not .Values.ingressController.admissionWebhook.certificate.provided }}
caBundle: {{ b64enc $caCert }}

View File

@@ -359,7 +359,7 @@ spec:
{{- include "kong.volumeMounts" . | nindent 10 }}
{{- include "kong.userDefinedVolumeMounts" .Values.deployment | nindent 10 }}
readinessProbe:
{{ toYaml .Values.readinessProbe | indent 10 }}
{{ include "kong.proxy.compatibleReadiness" . | indent 10 }}
livenessProbe:
{{ toYaml .Values.livenessProbe | indent 10 }}
{{- if .Values.startupProbe }}
@@ -403,41 +403,6 @@ spec:
{{- end }}
{{- include "kong.volumes" . | nindent 8 -}}
{{- include "kong.userDefinedVolumes" . | nindent 8 -}}
{{- if (and (not .Values.deployment.serviceAccount.automountServiceAccountToken) (or .Values.deployment.serviceAccount.create .Values.deployment.serviceAccount.name)) }}
- name: {{ template "kong.serviceAccountTokenName" . }}
{{- /* Due to GKE versions (e.g. v1.23.15-gke.1900) we need to handle pre-release part of the version as well.
See the related documentation of semver module that Helm depends on for semverCompare:
https://github.com/Masterminds/semver#working-with-prerelease-versions
Related Helm issue: https://github.com/helm/helm/issues/3810 */}}
{{- if semverCompare ">=1.20.0-0" .Capabilities.KubeVersion.Version }}
projected:
sources:
- serviceAccountToken:
expirationSeconds: 3607
path: token
- configMap:
items:
- key: ca.crt
path: ca.crt
name: kube-root-ca.crt
- downwardAPI:
items:
- fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
path: namespace
{{- else }}
secret:
secretName: {{ template "kong.serviceAccountTokenName" . }}
items:
- key: token
path: token
- key: ca.crt
path: ca.crt
- key: namespace
path: namespace
{{- end }}
{{- end }}
{{- if (and (eq .Values.kind "AppSecStateful") .Values.appsec.persistence.enabled) }}
volumeClaimTemplates:
- metadata:

View File

@@ -270,7 +270,7 @@ spec:
{{- include "kong.volumeMounts" . | nindent 10 }}
{{- include "kong.userDefinedVolumeMounts" .Values.deployment | nindent 10 }}
readinessProbe:
{{ toYaml .Values.readinessProbe | indent 10 }}
{{ include "kong.proxy.compatibleReadiness" . | indent 10 }}
livenessProbe:
{{ toYaml .Values.livenessProbe | indent 10 }}
{{- if .Values.startupProbe }}
@@ -302,39 +302,4 @@ spec:
volumes:
{{- include "kong.volumes" . | nindent 8 -}}
{{- include "kong.userDefinedVolumes" . | nindent 8 -}}
{{- if (and (not .Values.deployment.serviceAccount.automountServiceAccountToken) (or .Values.deployment.serviceAccount.create .Values.deployment.serviceAccount.name)) }}
- name: {{ template "kong.serviceAccountTokenName" . }}
{{- /* Due to GKE versions (e.g. v1.23.15-gke.1900) we need to handle pre-release part of the version as well.
See the related documentation of semver module that Helm depends on for semverCompare:
https://github.com/Masterminds/semver#working-with-prerelease-versions
Related Helm issue: https://github.com/helm/helm/issues/3810 */}}
{{- if semverCompare ">=1.20.0-0" .Capabilities.KubeVersion.Version }}
projected:
sources:
- serviceAccountToken:
expirationSeconds: 3607
path: token
- configMap:
items:
- key: ca.crt
path: ca.crt
name: kube-root-ca.crt
- downwardAPI:
items:
- fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
path: namespace
{{- else }}
secret:
secretName: {{ template "kong.serviceAccountTokenName" . }}
items:
- key: token
path: token
- key: ca.crt
path: ca.crt
- key: namespace
path: namespace
{{- end }}
{{- end }}
{{- end }}

View File

@@ -29,6 +29,9 @@ spec:
{{- range $key, $value := .Values.migrations.annotations }}
{{ $key }}: {{ $value | quote }}
{{- end }}
{{- if (and (not .Values.deployment.serviceAccount.automountServiceAccountToken) (or .Values.deployment.serviceAccount.create .Values.deployment.serviceAccount.name)) }}
kuma.io/service-account-token-volume: {{ template "kong.serviceAccountTokenName" . }}
{{- end }}
{{- end }}
spec:
{{- if or .Values.deployment.serviceAccount.create .Values.deployment.serviceAccount.name }}

View File

@@ -13,6 +13,8 @@ metadata:
annotations:
helm.sh/hook: "pre-upgrade"
helm.sh/hook-delete-policy: "before-hook-creation"
argocd.argoproj.io/hook: Sync
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
{{- range $key, $value := .Values.migrations.jobAnnotations }}
{{ $key }}: {{ $value | quote }}
{{- end }}
@@ -29,6 +31,9 @@ spec:
{{- range $key, $value := .Values.migrations.annotations }}
{{ $key }}: {{ $value | quote }}
{{- end }}
{{- if (and (not .Values.deployment.serviceAccount.automountServiceAccountToken) (or .Values.deployment.serviceAccount.create .Values.deployment.serviceAccount.name)) }}
kuma.io/service-account-token-volume: {{ template "kong.serviceAccountTokenName" . }}
{{- end }}
{{- end }}
spec:
{{- if or .Values.deployment.serviceAccount.create .Values.deployment.serviceAccount.name }}

View File

@@ -21,6 +21,8 @@ metadata:
{{- include "kong.metaLabels" . | nindent 4 }}
app.kubernetes.io/component: init-migrations
annotations:
argocd.argoproj.io/hook: Sync
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
{{- range $key, $value := .Values.migrations.jobAnnotations }}
{{ $key }}: {{ $value | quote }}
{{- end }}
@@ -37,6 +39,9 @@ spec:
{{- range $key, $value := .Values.migrations.annotations }}
{{ $key }}: {{ $value | quote }}
{{- end }}
{{- if (and (not .Values.deployment.serviceAccount.automountServiceAccountToken) (or .Values.deployment.serviceAccount.create .Values.deployment.serviceAccount.name)) }}
kuma.io/service-account-token-volume: {{ template "kong.serviceAccountTokenName" . }}
{{- end }}
{{- end }}
spec:
{{- if or .Values.deployment.serviceAccount.create .Values.deployment.serviceAccount.name }}

View File

@@ -1,5 +1,4 @@
{{- if .Values.deployment.kong.enabled }}
{{- if .Values.enterprise.enabled }}
{{- if and .Values.manager.enabled (or .Values.manager.http.enabled .Values.manager.tls.enabled) -}}
{{- $serviceConfig := dict -}}
{{- $serviceConfig := merge $serviceConfig .Values.manager -}}
@@ -16,4 +15,3 @@
{{- end -}}
{{- end -}}
{{- end -}}
{{- end -}}

View File

@@ -86,7 +86,7 @@ env:
database: "off"
# the chart uses the traditional router (for Kong 3.x+) because the ingress
# controller generates traditional routes. if you do not use the controller,
# you may set this to "traditional_compatible" or "expression" to use the new
# you may set this to "traditional_compatible" or "expressions" to use the new
# DSL-based router
router_flavor: "traditional"
nginx_worker_processes: "2"
@@ -121,11 +121,13 @@ extraLabels: {}
# Specify Kong's Docker image and repository details here
image:
repository: kong
tag: "3.3"
tag: "3.4"
# Kong Enterprise
# repository: kong/kong-gateway
# tag: "3.3"
# tag: "3.4"
# Specify a semver version if your image tag is not one (e.g. "nightly")
effectiveSemver:
pullPolicy: IfNotPresent
## Optionally specify an array of imagePullSecrets.
## Secrets must be manually created in the namespace.
@@ -514,7 +516,7 @@ ingressController:
enabled: true
image:
repository: kong/kubernetes-ingress-controller
tag: "2.10"
tag: "2.12"
# Optionally set a semantic version for version-gated features. This can normally
# be left unset. You only need to set this if your tag is not a semver string,
# such as when you are using a "next" tag. Set this to the effective semantic
@@ -574,6 +576,8 @@ ingressController:
service:
# Specify custom labels for the validation webhook service.
labels: {}
# Tune the default Kubernetes timeoutSeconds of 10 seconds
# timeoutSeconds: 10
ingressClass: kong
# annotations for IngressClass resource (Kubernetes 1.18+)
@@ -800,7 +804,7 @@ resources: {}
# readinessProbe for Kong pods
readinessProbe:
httpGet:
path: "/status"
path: "/status/ready"
port: status
scheme: HTTP
initialDelaySeconds: 5
@@ -1229,8 +1233,8 @@ appsec:
image:
#registry:
repository: ghcr.io/openappsec
image: agent
tag: latest
image: "agent"
tag: "1.1.0"
pullPolicy: Always
securityContext:
@@ -1243,8 +1247,8 @@ appsec:
# runAsUser: 1000
kong:
image:
repository: "ghcr.io/openappsec/kong-gateway-attachment"
tag: "latest"
repository: "ghcr.io/openappsec/kong-attachment"
tag: "1.1.0"
configMapName: appsec-settings-configmap
configMapContent:
crowdsec:

View File

@@ -5,6 +5,7 @@ CROWDSEC_INSTALLATION_SCRIPT="install-cp-crowdsec-aux.sh"
HTTP_TRANSACTION_HANDLER_SERVICE="install-cp-nano-service-http-transaction-handler.sh"
ATTACHMENT_REGISTRATION_SERVICE="install-cp-nano-attachment-registration-manager.sh"
ORCHESTRATION_INSTALLATION_SCRIPT="install-cp-nano-agent.sh"
CACHE_INSTALLATION_SCRIPT="install-cp-nano-agent-cache.sh"
var_fog_address=
var_proxy=
@@ -58,7 +59,12 @@ fi
/nano-service-installers/$ORCHESTRATION_INSTALLATION_SCRIPT --install $orchestration_service_installation_flags
if [ -f /var/run/secrets/kubernetes.io/serviceaccount/token ]; then
/etc/cp/orchestration/k8s-check-update-listener.sh &
fi
/nano-service-installers/$ATTACHMENT_REGISTRATION_SERVICE --install
/nano-service-installers/$CACHE_INSTALLATION_SCRIPT --install
/nano-service-installers/$HTTP_TRANSACTION_HANDLER_SERVICE --install
if [ ! -z $CROWDSEC_ENABLED ]; then

View File

@@ -1762,8 +1762,8 @@ private:
&did_fail_on_purpose
)) {
return genError(
"Failed to read the attachment's User ID or Group ID" +
did_fail_on_purpose ? "[Intentional Failure]" : ""
string("Failed to read the attachment's User ID or Group ID") +
(did_fail_on_purpose ? "[Intentional Failure]" : "")
);
}

View File

@@ -49,6 +49,8 @@ nginxIntakerEvent::resetAllCounters()
req_proccessing_timeout = 0;
res_proccessing_timeout = 0;
req_failed_to_reach_upstream = 0;
req_overall_size = 0;
res_overall_size = 0;
cpu_event.setCPU(0);
}
@@ -249,10 +251,22 @@ nginxIntakerEvent::addPluginMetricCounter(const ngx_http_cp_metric_data_t *recie
cpu_event.setCPU(amount);
break;
}
case ngx_http_plugin_metric_type_e::REQUEST_OVERALL_SIZE_COUNT: {
req_overall_size += amount;
static const uint64_t max_expected_res_size = 100ULL * 1024 * 1024 * 1024;
if (amount > max_expected_res_size) {
dbgWarning(D_METRICS_NGINX_ATTACHMENT) << "Requests sizes higher than expected: " << amount;
}
break;
}
case ngx_http_plugin_metric_type_e::RESPONSE_OVERALL_SIZE_COUNT: {
res_overall_size += amount;
break;
}
default:
dbgWarning(D_METRICS_NGINX_ATTACHMENT)
<< "Unsupported metric type. Type: " << static_cast<int>(metric_type);
return;
break;
}
}
}
@@ -353,6 +367,10 @@ nginxIntakerEvent::getPluginMetricCounter(ngx_http_plugin_metric_type_e metric_t
return req_failed_to_reach_upstream;
case ngx_http_plugin_metric_type_e::CPU_USAGE:
return static_cast<uint64_t>(cpu_event.getCPU());
case ngx_http_plugin_metric_type_e::REQUEST_OVERALL_SIZE_COUNT:
return req_overall_size;
case ngx_http_plugin_metric_type_e::RESPONSE_OVERALL_SIZE_COUNT:
return res_overall_size;
default:
dbgWarning(D_METRICS_NGINX_ATTACHMENT)
<< "Unsupported metric type. Type: " << static_cast<int>(metric_type);
@@ -498,5 +516,11 @@ nginxIntakerMetric::upon(const nginxIntakerEvent &event)
req_failed_to_reach_upstream.report(
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::REQ_FAILED_TO_REACH_UPSTREAM)
);
req_overall_size.report(
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::REQUEST_OVERALL_SIZE_COUNT)
);
res_overall_size.report(
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::RESPONSE_OVERALL_SIZE_COUNT)
);
event.notifyCPU();
}

View File

@@ -20,6 +20,9 @@
#include "environment/evaluator_templates.h"
#include "i_environment.h"
#include "singleton.h"
#include "debug.h"
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
using namespace std;
using namespace EnvironmentHelper;
@@ -55,6 +58,51 @@ EqualHost::evalVariable() const
return lower_host_ctx == lower_host;
}
WildcardHost::WildcardHost(const vector<string> &params)
{
if (params.size() != 1) reportWrongNumberOfParams("WildcardHost", params.size(), 1, 1);
host = params[0];
}
Maybe<bool, Context::Error>
WildcardHost::evalVariable() const
{
I_Environment *env = Singleton::Consume<I_Environment>::by<WildcardHost>();
auto host_ctx = env->get<string>(HttpTransactionData::host_name_ctx);
if (!host_ctx.ok())
{
return false;
}
string lower_host_ctx = host_ctx.unpack();
transform(lower_host_ctx.begin(), lower_host_ctx.end(), lower_host_ctx.begin(), ::tolower);
dbgTrace(D_RULEBASE_CONFIG) << "found host in current context: " << lower_host_ctx;
size_t pos = lower_host_ctx.find_first_of(".");
if (pos == string::npos) {
return false;
}
lower_host_ctx = "*" + lower_host_ctx.substr(pos, lower_host_ctx.length());
string lower_host = host;
transform(lower_host.begin(), lower_host.end(), lower_host.begin(), ::tolower);
dbgTrace(D_RULEBASE_CONFIG)
<< "trying to match host context with its corresponding wildcard address: "
<< lower_host_ctx
<< ". Matcher host: "
<< lower_host;
if (lower_host_ctx == lower_host) return true;
pos = lower_host_ctx.find_last_of(':');
if (pos == string::npos) return false;
lower_host_ctx = string(lower_host_ctx.data(), pos);
return lower_host_ctx == lower_host;
}
EqualListeningIP::EqualListeningIP(const vector<string> &params)
{
if (params.size() != 1) reportWrongNumberOfParams("EqualListeningIP", params.size(), 1, 1);

View File

@@ -75,6 +75,7 @@ GenericRulebase::Impl::preload()
addMatcher<IpProtocolMatcher>();
addMatcher<UrlMatcher>();
addMatcher<EqualHost>();
addMatcher<WildcardHost>();
addMatcher<EqualListeningIP>();
addMatcher<EqualListeningPort>();
addMatcher<BeginWithUri>();

View File

@@ -156,7 +156,7 @@ Zone::contains(const Asset &asset)
{
QueryRequest request;
for (const pair<Context::MetaDataType, string> &main_attr : asset.getAttrs()) {
for (const auto &main_attr : asset.getAttrs()) {
request.addCondition(Condition::EQUALS, contextKeyToString(main_attr.first), main_attr.second);
}

View File

@@ -83,13 +83,13 @@ public:
:
status(raw_status)
{
for (const pair<string, HealthCheckStatusReply> &single_stat : descriptions) {
for (const auto &single_stat : descriptions) {
if (single_stat.second.getStatus() == HealthCheckStatus::HEALTHY) {
dbgTrace(D_HEALTH_CHECK_MANAGER) << "Ignoring healthy status reply. Comp name: " << single_stat.first;
continue;
}
for (const pair<string, string> &status : single_stat.second.getExtendedStatus()) {
for (const auto &status : single_stat.second.getExtendedStatus()) {
errors.push_back(HealthCheckError(single_stat.first + " " + status.first, status.second));
}
}
@@ -190,7 +190,7 @@ private:
{
general_health_aggregated_status = HealthCheckStatus::HEALTHY;
for (const pair<string, HealthCheckStatusReply> &reply : all_comps_health_status) {
for (const auto &reply : all_comps_health_status) {
HealthCheckStatus status = reply.second.getStatus();
dbgTrace(D_HEALTH_CHECK_MANAGER)

View File

@@ -48,7 +48,7 @@ HttpManagerOpaque::getCurrVerdict() const
uint accepted_apps = 0;
ngx_http_cp_verdict_e verdict = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INSPECT;
for (const pair<string, ngx_http_cp_verdict_e> &app_verdic_pair : applications_verdicts) {
for (const auto &app_verdic_pair : applications_verdicts) {
switch (app_verdic_pair.second) {
case ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP:
return app_verdic_pair.second;

View File

@@ -32,6 +32,19 @@ private:
std::string host;
};
class WildcardHost : public EnvironmentEvaluator<bool>, Singleton::Consume<I_Environment>
{
public:
WildcardHost(const std::vector<std::string> &params);
static std::string getName() { return "WildcardHost"; }
Maybe<bool, Context::Error> evalVariable() const override;
private:
std::string host;
};
class EqualListeningIP : public EnvironmentEvaluator<bool>, Singleton::Consume<I_Environment>
{
public:

View File

@@ -224,5 +224,6 @@ private:
};
static const ParameterBehavior action_ignore(BehaviorKey::ACTION, BehaviorValue::IGNORE);
static const ParameterBehavior action_accept(BehaviorKey::ACTION, BehaviorValue::ACCEPT);
#endif //__PARAMETERS_CONFIG_H__

View File

@@ -11,52 +11,108 @@
// See the License for the specific language governing permissions and
// limitations under the License.
/// \file triggers_config.h
/// \brief Declaration of classes WebTriggerConf and LogTriggerConf, and related functions.
/// \author Check Point Software Technologies Ltd.
/// \date 2022
#ifndef __TRIGGERS_CONFIG_H__
#define __TRIGGERS_CONFIG_H__
#include <vector>
#include <string>
#include <vector>
#include "environment/evaluator_templates.h"
#include "cereal/archives/json.hpp"
#include "cereal/types/string.hpp"
#include "cereal/types/vector.hpp"
#include "cereal/archives/json.hpp"
#include "config.h"
#include "environment/evaluator_templates.h"
#include "generic_rulebase_utils.h"
#include "i_environment.h"
#include "i_logging.h"
#include "singleton.h"
#include "maybe_res.h"
#include "config.h"
#include "log_generator.h"
#include "generic_rulebase_utils.h"
#include "maybe_res.h"
#include "singleton.h"
/// \class WebTriggerConf
/// \brief Represents the configuration for a web trigger.
class WebTriggerConf
{
public:
/// \brief Default constructor for WebTriggerConf.
WebTriggerConf();
/// \brief Constructor for WebTriggerConf.
/// \param title The title of the trigger.
/// \param body The body of the trigger.
/// \param code The response code for the trigger.
WebTriggerConf(const std::string &title, const std::string &body, uint code);
/// \brief Preload function to register expected configuration.
static void
preload()
{
registerExpectedConfiguration<WebTriggerConf>("rulebase", "webUserResponse");
}
/// \brief Load function to deserialize configuration from JSONInputArchive.
/// \param archive_in The JSON input archive.
void load(cereal::JSONInputArchive &archive_in);
/// \brief Equality operator for WebTriggerConf.
/// \param other The WebTriggerConf to compare.
/// \return True if the two WebTriggerConf objects are equal, otherwise false.
bool operator==(const WebTriggerConf &other) const;
uint getResponseCode() const { return response_code; }
/// \brief Get the response code for the trigger.
/// \return The response code.
uint
getResponseCode() const
{
return response_code;
}
const std::string & getResponseTitle() const { return response_title; }
/// \brief Get the response title for the trigger.
/// \return The response title.
const std::string &
getResponseTitle() const
{
return response_title;
}
const std::string & getResponseBody() const { return response_body; }
/// \brief Get the response body for the trigger.
/// \return The response body.
const std::string &
getResponseBody() const
{
return response_body;
}
const std::string & getDetailsLevel() const { return details_level; }
/// \brief Get the details level for the trigger.
/// \return The details level.
const std::string &
getDetailsLevel() const
{
return details_level;
}
const std::string & getRedirectURL() const { return redirect_url; }
/// \brief Get the redirect URL for the trigger.
/// \return The redirect URL.
const std::string &
getRedirectURL() const
{
return redirect_url;
}
bool getAddEventId() const { return add_event_id_to_header; }
/// \brief Check if the trigger should add an event ID to the header.
/// \return True if the trigger should add an event ID, otherwise false.
bool
getAddEventId() const
{
return add_event_id_to_header;
}
/// \brief Default trigger configuration for WebTriggerConf.
static WebTriggerConf default_trigger_conf;
private:
@@ -64,17 +120,38 @@ private:
std::string details_level;
std::string response_body;
std::string redirect_url;
uint response_code;
bool add_event_id_to_header = false;
uint response_code;
bool add_event_id_to_header = false;
};
/// \class LogTriggerConf
/// \brief Represents the configuration for a log trigger.
class LogTriggerConf : Singleton::Consume<I_Logging>
{
public:
enum class SecurityType { AccessControl, ThreatPrevention, Compliance, COUNT };
enum class extendLoggingSeverity { None, High, Critical };
/// \enum SecurityType
/// \brief Enumerates the security types for LogTriggerConf.
enum class SecurityType
{
AccessControl,
ThreatPrevention,
Compliance,
COUNT
};
enum class WebLogFields {
/// \enum extendLoggingSeverity
/// \brief Enumerates the extended logging severity for LogTriggerConf.
enum class extendLoggingSeverity
{
None,
High,
Critical
};
/// \enum WebLogFields
/// \brief Enumerates the web log fields for LogTriggerConf.
enum class WebLogFields
{
webBody,
webHeaders,
webRequests,
@@ -85,17 +162,31 @@ public:
COUNT
};
/// \brief Default constructor for LogTriggerConf.
LogTriggerConf() {}
/// \brief Constructor for LogTriggerConf.
/// \param trigger_name The name of the trigger.
/// \param log_detect Flag indicating whether to log on detect.
/// \param log_prevent Flag indicating whether to log on prevent.
LogTriggerConf(std::string trigger_name, bool log_detect, bool log_prevent);
/// \brief Preload function to register expected configuration.
static void
preload()
{
registerExpectedConfiguration<LogTriggerConf>("rulebase", "log");
}
template <typename ...Tags>
/// \brief LogGen operator for LogTriggerConf.
/// \param title The title of the log.
/// \param security The security type of the log.
/// \param severity The severity of the log.
/// \param priority The priority of the log.
/// \param is_action_drop_or_prevent Flag indicating if the action is drop or prevent.
/// \param tags Tags for the log.
/// \return The LogGen object.
template <typename... Tags>
LogGen
operator()(
const std::string &title,
@@ -103,7 +194,8 @@ public:
ReportIS::Severity severity,
ReportIS::Priority priority,
bool is_action_drop_or_prevent,
Tags ...tags) const
Tags... tags
) const
{
return LogGen(
title,
@@ -117,11 +209,17 @@ public:
);
}
template <typename ...Tags>
/// \brief LogGen operator for LogTriggerConf.
/// \param title The title of the log.
/// \param security The security type of the log.
/// \param is_action_drop_or_prevent Flag indicating if the action is drop or prevent.
/// \param tags Tags for the log.
/// \return The LogGen object.
template <typename... Tags>
LogGen
operator()(const std::string &title, SecurityType security, bool is_action_drop_or_prevent, Tags ...tags) const
operator()(const std::string &title, SecurityType security, bool is_action_drop_or_prevent, Tags... tags) const
{
return (*this)(
return operator()(
title,
security,
getSeverity(is_action_drop_or_prevent),
@@ -131,30 +229,98 @@ public:
);
}
/// \brief Load function to deserialize configuration from JSONInputArchive.
/// \param archive_in The JSON input archive.
void load(cereal::JSONInputArchive &archive_in);
bool isWebLogFieldActive(WebLogFields log_field) const { return log_web_fields.isSet(log_field); }
/// \brief Check if the web log field is active for the trigger.
/// \param log_field The web log field to check.
/// \return True if the web log field is active, otherwise false.
bool
isWebLogFieldActive(WebLogFields log_field) const
{
return log_web_fields.isSet(log_field);
}
bool isLogStreamActive(ReportIS::StreamType stream_type) const { return active_streams.isSet(stream_type); }
/// \brief Check if the log stream is active for the trigger.
/// \param stream_type The log stream type to check.
/// \return True if the log stream is active, otherwise false.
bool
isLogStreamActive(ReportIS::StreamType stream_type) const
{
return active_streams.isSet(stream_type);
}
bool isPreventLogActive(SecurityType security_type) const { return should_log_on_prevent.isSet(security_type); }
/// \brief Check if the log is active on prevent for the given security type.
/// \param security_type The security type to check.
/// \return True if the log is active on prevent, otherwise false.
bool
isPreventLogActive(SecurityType security_type) const
{
return should_log_on_prevent.isSet(security_type);
}
bool isDetectLogActive(SecurityType security_type) const { return should_log_on_detect.isSet(security_type); }
/// \brief Check if the log is active on detect for the given security type.
/// \param security_type The security type to check.
/// \return True if the log is active on detect, otherwise false.
bool
isDetectLogActive(SecurityType security_type) const
{
return should_log_on_detect.isSet(security_type);
}
bool isLogGeoLocationActive(SecurityType security_type) const { return log_geo_location.isSet(security_type); }
/// \brief Check if the geo-location log is active for the given security type.
/// \param security_type The security type to check.
/// \return True if the geo-location log is active, otherwise false.
bool
isLogGeoLocationActive(SecurityType security_type) const
{
return log_geo_location.isSet(security_type);
}
extendLoggingSeverity getExtendLoggingSeverity() const { return extend_logging_severity; }
/// \brief Get the extended logging severity.
/// \return The extended logging severity.
extendLoggingSeverity
getExtendLoggingSeverity() const
{
return extend_logging_severity;
}
const std::string & getVerbosity() const { return verbosity; }
const std::string & getName() const { return name; }
/// \brief Get the verbosity.
/// \return The verbosity.
const std::string &
getVerbosity() const
{
return verbosity;
}
const std::string & getUrlForSyslog() const { return url_for_syslog; }
const std::string & getUrlForCef() const { return url_for_cef; }
/// \brief Get the name.
/// \return The name.
const std::string &
getName() const
{
return name;
}
/// \brief Get the URL for syslog.
/// \return The URL for syslog.
const std::string &
getUrlForSyslog() const
{
return url_for_syslog;
}
/// \brief Get the URL for CEF.
/// \return The URL for CEF.
const std::string &
getUrlForCef() const
{
return url_for_cef;
}
private:
ReportIS::Severity getSeverity(bool is_action_drop_or_prevent) const;
ReportIS::Priority getPriority(bool is_action_drop_or_prevent) const;
Flags<ReportIS::StreamType> getStreams(SecurityType security_type, bool is_action_drop_or_prevent) const;
Flags<ReportIS::Enreachments> getEnrechments(SecurityType security_type) const;

View File

@@ -18,6 +18,7 @@
#include "i_mainloop.h"
#include "i_socket_is.h"
#include "i_health_check_manager.h"
#include "i_shell_cmd.h"
#include "component.h"
class HealthChecker
@@ -25,7 +26,8 @@ class HealthChecker
public Component,
Singleton::Consume<I_MainLoop>,
Singleton::Consume<I_Socket>,
Singleton::Consume<I_Health_Check_Manager>
Singleton::Consume<I_Health_Check_Manager>,
Singleton::Consume<I_ShellCmd>
{
public:
HealthChecker();

View File

@@ -14,13 +14,15 @@
#ifndef __I_LOCAL_POLICY_MGMT_GEN_H__
#define __I_LOCAL_POLICY_MGMT_GEN_H__
#include "i_env_details.h"
class I_LocalPolicyMgmtGen
{
public:
virtual std::string parsePolicy(const std::string &policy_version) = 0;
virtual const std::string & getAgentPolicyPath(void) const = 0;
virtual const std::string & getLocalPolicyPath(void) const = 0;
virtual void setPolicyPath(const std::string &new_local_policy_path) = 0;
virtual std::string generateAppSecLocalPolicy(
EnvType env_type,
const std::string &policy_version,
const std::string &local_policy_path) = 0;
protected:
~I_LocalPolicyMgmtGen() {}

View File

@@ -106,11 +106,18 @@ public:
const std::string &profile_id = "") const = 0;
virtual bool isNonEmptyFile(const std::string &path) const = 0;
virtual std::shared_ptr<std::ifstream> fileStreamWrapper(const std::string &path) const = 0;
virtual Maybe<std::string> readFile(const std::string &path) const = 0;
virtual bool writeFile(const std::string &text, const std::string &path) const = 0;
virtual bool writeFile(const std::string &text, const std::string &path, bool append_mode = false) const = 0;
virtual bool removeFile(const std::string &path) const = 0;
virtual bool removeDirectory(const std::string &path, bool delete_content) const = 0;
virtual void deleteVirtualTenantProfileFiles(
const std::string &tenant_id,
const std::string &profile_id,
const std::string &conf_path) const = 0;
virtual bool copyFile(const std::string &src_path, const std::string &dst_path) const = 0;
virtual bool doesFileExist(const std::string &file_path) const = 0;
virtual void getClusterId() const = 0;
virtual void fillKeyInJson(
const std::string &filename,
const std::string &_key,
@@ -118,6 +125,7 @@ public:
virtual bool createDirectory(const std::string &directory_path) const = 0;
virtual bool doesDirectoryExist(const std::string &dir_path) const = 0;
virtual bool executeCmd(const std::string &cmd) const = 0;
virtual void loadTenantsFromDir(const std::string &dir_path) const = 0;
virtual std::string base64Encode(const std::string &input) const = 0;
virtual std::string base64Decode(const std::string &input) const = 0;

View File

@@ -19,6 +19,7 @@
#include <map>
#include "connkey.h"
#include "maybe_res.h"
#include "rest.h"
enum class ReconfStatus { SUCCEEDED, IN_PROGRESS, FAILED, INACTIVE };
@@ -27,9 +28,10 @@ class I_ServiceController
{
public:
virtual void refreshPendingServices() = 0;
virtual const std::string & getPolicyVersions() const = 0;
virtual const std::string & getPolicyVersion() const = 0;
virtual const std::string & getUpdatePolicyVersion() const = 0;
virtual void updateReconfStatus(int id, ReconfStatus status) = 0;
virtual void updateReconfStatus(int id, const std::string &service_name, ReconfStatus status) = 0;
virtual void startReconfStatus(
int id,
ReconfStatus status,
@@ -37,13 +39,13 @@ public:
const std::string &service_id
) = 0;
virtual bool
virtual Maybe<void>
updateServiceConfiguration(
const std::string &new_policy_path,
const std::string &new_settings_path,
const std::vector<std::string> &new_data_files = {},
const std::string &tenant_id = "",
const std::string &profile_id = "",
const std::string &child_tenant_id = "",
const std::string &child_profile_id = "",
const bool last_iteration = false
) = 0;

View File

@@ -26,9 +26,12 @@ using OrchData = Maybe<std::string>;
class I_UpdateCommunication
{
public:
virtual Maybe<void> sendPolicyVersion(
const std::string &policy_version,
const std::string &policy_versions
) const = 0;
virtual Maybe<void> authenticateAgent() = 0;
virtual Maybe<void> getUpdate(CheckUpdateRequest &request) = 0;
virtual Maybe<void> sendPolicyVersion(const std::string &policy_version) const = 0;
virtual Maybe<std::string> downloadAttributeFile(const GetResourceFile &resourse_file) = 0;
virtual void setAddressExtenesion(const std::string &extension) = 0;
};

View File

@@ -19,13 +19,19 @@
#include "i_mainloop.h"
#include "i_local_policy_mgmt_gen.h"
#include "i_env_details.h"
#include "i_shell_cmd.h"
#include "i_orchestration_tools.h"
class LocalPolicyMgmtGenerator
:
public Component,
Singleton::Provide<I_LocalPolicyMgmtGen>,
Singleton::Consume<I_MainLoop>,
Singleton::Consume<I_EnvDetails>
Singleton::Consume<I_EnvDetails>,
Singleton::Consume<I_ShellCmd>,
Singleton::Consume<I_Environment>,
Singleton::Consume<I_OrchestrationTools>,
Singleton::Consume<I_Messaging>
{
public:
LocalPolicyMgmtGenerator();

View File

@@ -81,6 +81,8 @@ private:
uint64_t req_proccessing_timeout = 0;
uint64_t res_proccessing_timeout = 0;
uint64_t req_failed_to_reach_upstream = 0;
uint64_t req_overall_size = 0;
uint64_t res_overall_size = 0;
CPUEvent cpu_event;
};
@@ -140,6 +142,8 @@ private:
Counter thread_failure{this, "attachmentThreadFailureSum"};
Counter req_proccessing_timeout{this, "httpRequestProcessingReachedTimeoutSum"};
Counter res_proccessing_timeout{this, "httpResponseProcessingReachedTimeoutSum"};
Counter req_overall_size{this, "httpRequestsSizeSum"};
Counter res_overall_size{this, "httpResponsesSizeSum"};
Counter req_failed_to_reach_upstream{this, "httpRequestFailedToReachWebServerUpstreamSum"};
};

View File

@@ -31,6 +31,7 @@
#include "i_environment.h"
#include "i_tenant_manager.h"
#include "i_package_handler.h"
#include "i_env_details.h"
#include "component.h"
class OrchestrationComp
@@ -52,7 +53,8 @@ class OrchestrationComp
Singleton::Consume<I_ServiceController>,
Singleton::Consume<I_UpdateCommunication>,
Singleton::Consume<I_Downloader>,
Singleton::Consume<I_ManifestController>
Singleton::Consume<I_ManifestController>,
Singleton::Consume<I_EnvDetails>
{
public:
OrchestrationComp();

View File

@@ -17,9 +17,26 @@
#include <fstream>
#include "i_orchestration_tools.h"
#include "i_shell_cmd.h"
#include "i_tenant_manager.h"
#include "component.h"
#include "i_env_details.h"
#include "i_messaging.h"
#include "i_environment.h"
#include "i_agent_details.h"
#include "i_mainloop.h"
class OrchestrationTools : public Component, Singleton::Provide<I_OrchestrationTools>
class OrchestrationTools
:
public Component,
Singleton::Provide<I_OrchestrationTools>,
Singleton::Consume<I_ShellCmd>,
Singleton::Consume<I_TenantManager>,
Singleton::Consume<I_EnvDetails>,
Singleton::Consume<I_Messaging>,
Singleton::Consume<I_Environment>,
Singleton::Consume<I_MainLoop>,
Singleton::Consume<I_AgentDetails>
{
public:
OrchestrationTools();

View File

@@ -106,6 +106,78 @@ public:
BOTH_LABEL_OPTIONAL_PARAM(TenantError, error, "error");
};
class UpgradeSchedule : public ClientRest
{
public:
UpgradeSchedule() = default;
UpgradeSchedule(const UpgradeSchedule &other)
{
mode = other.mode;
time = other.time;
duration_hours = other.duration_hours;
days = other.days;
}
UpgradeSchedule &
operator=(const UpgradeSchedule &other)
{
if (this != &other) {
mode = other.mode;
time = other.time;
duration_hours = other.duration_hours;
days = other.days;
}
return *this;
}
void init(const std::string &_upgrade_mode) { mode = _upgrade_mode; }
void
init(
const std::string &_upgrade_mode,
const std::string &_upgrade_time,
const uint &_upgrade_duration_hours)
{
init(_upgrade_mode);
time = _upgrade_time;
duration_hours = _upgrade_duration_hours;
}
void
init(
const std::string &_upgrade_mode,
const std::string &_upgrade_time,
const uint &_upgrade_duration_hours,
const std::vector<std::string> &_upgrade_days)
{
init(_upgrade_mode, _upgrade_time, _upgrade_duration_hours);
days = _upgrade_days;
}
private:
C2S_LABEL_PARAM(std::string, mode, "upgradeMode");
C2S_LABEL_OPTIONAL_PARAM(std::string, time, "upgradeTime");
C2S_LABEL_OPTIONAL_PARAM(uint, duration_hours, "upgradeDurationHours");
C2S_LABEL_OPTIONAL_PARAM(std::vector<std::string>, days, "upgradeDay");
};
class LocalConfigurationSettings : public ClientRest
{
public:
LocalConfigurationSettings() = default;
void
setUpgradeSchedule(const UpgradeSchedule &schedule)
{
upgrade_schedule.setActive(true);
upgrade_schedule.get() = schedule;
}
private:
C2S_LABEL_OPTIONAL_PARAM(UpgradeSchedule, upgrade_schedule, "upgradeSchedule");
};
CheckUpdateRequest(
const std::string &_manifest,
const std::string &_policy,
@@ -185,6 +257,32 @@ public:
void setGreedyMode() { check_all_tenants = true; }
void
setUpgradeFields(const std::string &_upgrade_mode)
{
UpgradeSchedule upgrade_schedule;
upgrade_schedule.init(_upgrade_mode);
local_configuration_settings.setActive(true);
local_configuration_settings.get().setUpgradeSchedule(upgrade_schedule);
}
void
setUpgradeFields(
const std::string &_upgrade_mode,
const std::string &_upgrade_time,
const uint &_upgrade_duration_hours,
const std::vector<std::string> &_upgrade_days)
{
UpgradeSchedule upgrade_schedule;
if (!_upgrade_days.empty()) {
upgrade_schedule.init(_upgrade_mode, _upgrade_time, _upgrade_duration_hours, _upgrade_days);
} else {
upgrade_schedule.init(_upgrade_mode, _upgrade_time, _upgrade_duration_hours);
}
local_configuration_settings.setActive(true);
local_configuration_settings.get().setUpgradeSchedule(upgrade_schedule);
}
private:
class VirtualConfig : public ClientRest
{
@@ -239,6 +337,8 @@ private:
C2S_LABEL_PARAM(std::string, checksum_type, "checksum-type");
C2S_LABEL_PARAM(std::string, policy_version, "policyVersion");
C2S_LABEL_OPTIONAL_PARAM(LocalConfigurationSettings, local_configuration_settings, "localConfigurationSettings");
S2C_LABEL_OPTIONAL_PARAM(VirtualConfig, in_virtual_policy, "virtualPolicy");
S2C_LABEL_OPTIONAL_PARAM(VirtualConfig, in_virtual_settings, "virtualSettings");
};

34
components/include/rate_limit.h Executable file
View File

@@ -0,0 +1,34 @@
#ifndef __RATE_LIMIT_H_
#define __RATE_LIMIT_H_
#include <string>
#include "component.h"
#include "singleton.h"
#include "i_mainloop.h"
#include "i_environment.h"
#include "i_generic_rulebase.h"
class RateLimit
:
public Component,
Singleton::Consume<I_MainLoop>,
Singleton::Consume<I_TimeGet>,
Singleton::Consume<I_Environment>,
Singleton::Consume<I_GenericRulebase>
{
public:
RateLimit();
~RateLimit();
void preload() override;
void init() override;
void fini() override;
private:
class Impl;
std::unique_ptr<Impl> pimpl;
};
#endif // __RATE_LIMIT_H_

View File

@@ -0,0 +1,142 @@
#ifndef __RATE_LIMIT_CONFIG_H__
#define __RATE_LIMIT_CONFIG_H__
#include <string>
#include <vector>
#include <algorithm>
#include <cereal/archives/json.hpp>
#include "debug.h"
#include "generic_rulebase/rulebase_config.h"
#include "generic_rulebase/triggers_config.h"
#include "generic_rulebase/evaluators/trigger_eval.h"
USE_DEBUG_FLAG(D_REVERSE_PROXY);
class RateLimitTrigger
{
public:
void
load(cereal::JSONInputArchive &ar);
const std::string & getTriggerId() const { return id; }
private:
std::string id;
};
class RateLimitRule
{
public:
void load(cereal::JSONInputArchive &ar);
void prepare(const std::string &asset_id, int zone_id);
operator bool() const
{
if (uri.empty()) {
dbgTrace(D_REVERSE_PROXY) << "Recived empty URI in rate-limit rule";
return false;
}
if (uri.at(0) != '/') {
dbgWarning(D_REVERSE_PROXY)
<< "Recived invalid rate-limit URI in rate-limit rule: "
<< uri
<< " rate-limit URI must start with /";
return false;
}
if (limit <= 0) {
dbgWarning(D_REVERSE_PROXY)
<< "Recived invalid rate-limit limit in rate-limit rule: "
<< limit
<< " rate-limit rule limit must be positive";
return false;
}
return true;
}
friend std::ostream &
operator<<(std::ostream &os, const RateLimitRule &rule)
{
os << "Uri: " << rule.uri << ", Rate scope: " << rule.scope << ", Limit: " << rule.limit;
return os;
}
int getRateLimit() const { return limit; }
const std::string & getRateLimitZone() const { return limit_req_zone_template_value; }
const std::string & getRateLimitReq() const { return limit_req_template_value; }
const std::string & getRateLimitUri() const { return uri; }
const std::string & getRateLimitScope() const { return scope; }
const LogTriggerConf & getRateLimitTrigger() const { return trigger; }
const std::vector<RateLimitTrigger> & getRateLimitTriggers() const { return rate_limit_triggers; }
bool isRootLocation() const;
bool operator==(const RateLimitRule &rhs) { return uri == rhs.uri; }
bool operator<(const RateLimitRule &rhs) { return uri < rhs.uri; }
bool isExactMatch() const { return exact_match || (!uri.empty() && uri.back() != '/'); }
void setExactMatch() { exact_match = true; }
void appendSlash() { uri += '/'; }
private:
std::string uri;
std::string scope;
std::string limit_req_template_value;
std::string limit_req_zone_template_value;
std::string cache_size = "5m";
std::vector<RateLimitTrigger> rate_limit_triggers;
LogTriggerConf trigger;
int limit;
bool exact_match = false;
};
class RateLimitConfig
{
public:
void load(cereal::JSONInputArchive &ar);
void addSiblingRateLimitRule(RateLimitRule &rule);
void prepare();
const std::vector<RateLimitRule> & getRateLimitRules() const { return rate_limit_rules; }
const std::string & getRateLimitMode() const { return mode; }
const LogTriggerConf
getRateLimitTrigger(const std::string &nginx_uri) const
{
const RateLimitRule rule = findLongestMatchingRule(nginx_uri);
std::set<std::string> rate_limit_triggers_set;
for (const RateLimitTrigger &rate_limit_trigger : rule.getRateLimitTriggers()) {
dbgTrace(D_REVERSE_PROXY)
<< "Adding trigger ID: "
<< rate_limit_trigger.getTriggerId()
<< " of rule URI: "
<< rule.getRateLimitUri()
<< " to the context set";
rate_limit_triggers_set.insert(rate_limit_trigger.getTriggerId());
}
ScopedContext ctx;
ctx.registerValue<std::set<GenericConfigId>>(TriggerMatcher::ctx_key, rate_limit_triggers_set);
return getConfigurationWithDefault(LogTriggerConf(), "rulebase", "log");
}
static void setIsActive(bool _is_active) { is_active |= _is_active; }
static void resetIsActive() { is_active = false; }
static bool isActive() { return is_active; }
private:
const RateLimitRule
findLongestMatchingRule(const std::string &nginx_uri) const;
static bool is_active;
std::string mode;
std::vector<RateLimitRule> rate_limit_rules;
};
#endif // __RATE_LIMIT_CONFIG_H__

View File

@@ -1,4 +1,6 @@
add_subdirectory(ips)
add_subdirectory(layer_7_access_control)
add_subdirectory(local_policy_mgmt_gen)
add_subdirectory(orchestration)
add_subdirectory(rate_limit)
add_subdirectory(waap)

View File

@@ -1,54 +1,176 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/// \file ips_signatures.h
/// \brief Declaration of classes IPSSignatureSubTypes, IPSSignaturesPerContext, IPSSignatures, SnortSignatures, and
/// related functions. \author Check Point Software Technologies Ltd. \date 2022
#ifndef __IPS_SIGNATURES_H__
#define __IPS_SIGNATURES_H__
#include <vector>
#include "config.h"
#include "parsed_context.h"
#include "log_generator.h"
#include "pm_hook.h"
#include "ips_enums.h"
#include "ips_entry.h"
#include "i_first_tier_agg.h"
#include "ips_entry.h"
#include "ips_enums.h"
#include "log_generator.h"
#include "parsed_context.h"
#include "pm_hook.h"
/// \namespace IPSSignatureSubTypes
/// \brief Namespace containing subtypes for IPS signatures.
namespace IPSSignatureSubTypes
{
using ActionResults = std::tuple<IPSSignatureSubTypes::SignatureAction, std::string, std::vector<std::string>>;
/// \class BaseSignature
/// \brief Represents the base signature class.
class BaseSignature
{
public:
enum class MatchType { NO_MATCH, CACHE_MATCH, MATCH };
/// \enum MatchType
/// \brief Enumerates the types of matches for BaseSignature.
enum class MatchType
{
NO_MATCH,
CACHE_MATCH,
MATCH
};
virtual const std::string & getSigId() const = 0;
/// \brief Get the ID of the signature.
virtual const std::string &getSigId() const = 0;
/// \brief Get the match type for the signature.
/// \param matched The set of patterns that matched.
virtual MatchType getMatch(const std::set<PMPattern> &matched) const = 0;
/// \brief Get the set of patterns in the signature.
virtual std::set<PMPattern> patternsInSignature() const = 0;
virtual const std::vector<std::string> & getContext() const = 0;
/// \brief Get the context of the signature.
virtual const std::vector<std::string> &getContext() const = 0;
};
/// \class IPSSignatureMetaData
/// \brief Represents the metadata for an IPS signature.
class IPSSignatureMetaData
{
public:
/// \brief Load the metadata from a JSON archive.
/// \param ar The JSON input archive.
void load(cereal::JSONInputArchive &ar);
/// \brief Set the indicators for the metadata.
/// \param source The source indicator.
/// \param version The version indicator.
void setIndicators(const std::string &source, const std::string &version);
const std::string & getId() const { return protection_id; }
const std::string & getName() const { return sig_name; }
const std::string & getUpdateVersion() const { return update; }
const std::string & getLogTitle() const { return event_log; }
const std::string & getSource() const { return source; }
const std::string & getFeedVersion() const { return version; }
const std::vector<std::string> & getCveList() const { return cve_list; }
IPSLevel getSeverity() const { return severity; }
std::string getSeverityString() const;
IPSLevel getConfidence() const { return confidence; }
std::string getConfidenceString() const;
IPSLevel getPerformance() const { return performance; }
std::string getPerformanceString() const;
bool isSilent() const { return is_silent; }
std::string getIncidentType() const;
bool isYearAtLeast(const Maybe<int> &year) const;
Maybe<int> getYear() const;
/// \brief Get the ID of the signature.
const std::string &
getId() const
{
return protection_id;
}
/// \brief Get the name of the signature.
const std::string &
getName() const
{
return sig_name;
}
/// \brief Get the update version of the signature.
const std::string &
getUpdateVersion() const
{
return update;
}
/// \brief Get the log title of the signature.
const std::string &
getLogTitle() const
{
return event_log;
}
/// \brief Get the source indicator of the signature.
const std::string &
getSource() const
{
return source;
}
/// \brief Get the feed version of the signature.
const std::string &
getFeedVersion() const
{
return version;
}
/// \brief Get the CVE list of the signature.
const std::vector<std::string> &
getCveList() const
{
return cve_list;
}
/// \brief Get the severity level of the signature.
IPSLevel
getSeverity() const
{
return severity;
}
/// \brief Get the severity level as a string of the signature.
std::string getSeverityString() const;
/// \brief Get the confidence level of the signature.
IPSLevel
getConfidence() const
{
return confidence;
}
/// \brief Get the confidence level as a string of the signature.
std::string getConfidenceString() const;
/// \brief Get the performance level of the signature.
IPSLevel
getPerformance() const
{
return performance;
}
/// \brief Get the performance level as a string of the signature.
std::string getPerformanceString() const;
/// \brief Check if the signature is silent.
bool
isSilent() const
{
return is_silent;
}
/// \brief Get the incident type of the signature.
std::string getIncidentType() const;
/// \brief Check if the signature is from a specific year or later.
/// \param year The year to compare with.
bool isYearAtLeast(const Maybe<int> &year) const;
/// \brief Get the year of the signature.
Maybe<int> getYear() const;
private:
std::string protection_id;
@@ -65,69 +187,224 @@ private:
bool is_silent = false;
};
/// \class CompleteSignature
/// \brief Represents a complete signature.
class CompleteSignature
{
public:
/// \brief Load the complete signature from a JSON archive.
/// \param ar The JSON input archive.
void load(cereal::JSONInputArchive &ar);
/// \brief Get the match type for the signature.
/// \param matches The set of patterns that matched.
BaseSignature::MatchType getMatch(const std::set<PMPattern> &matches) const;
/// \brief Get the set of patterns in the signature.
std::set<PMPattern> patternsInSignature() const;
/// \brief Set the indicators for the complete signature.
/// \param source The source indicator.
/// \param version The version indicator.
void setIndicators(const std::string &source, const std::string &version);
const std::vector<std::string> & getContext() const { return rule->getContext(); }
const std::string & getId() const { return metadata.getId(); }
const std::string & getLogTitle() const { return metadata.getLogTitle(); }
const std::string & getName() const { return metadata.getName(); }
const std::string & getUpdateVersion() const { return metadata.getUpdateVersion(); }
const std::string & getSource() const { return metadata.getSource(); }
const std::string & getFeedVersion() const { return metadata.getFeedVersion(); }
const std::vector<std::string> & getCveList() const { return metadata.getCveList(); }
IPSLevel getSeverity() const { return metadata.getSeverity(); }
std::string getSeverityString() const { return metadata.getSeverityString(); }
IPSLevel getConfidence() const { return metadata.getConfidence(); }
std::string getConfidenceString() const { return metadata.getConfidenceString(); }
IPSLevel getPerformance() const { return metadata.getPerformance(); }
std::string getPerformanceString() const { return metadata.getPerformanceString(); }
bool isSilent() const { return metadata.isSilent(); }
std::string getIncidentType() const { return metadata.getIncidentType(); }
/// \brief Get the context of the signature.
const std::vector<std::string> &
getContext() const
{
return rule->getContext();
}
bool isYearAtLeast(const Maybe<int> &year) const { return metadata.isYearAtLeast(year); }
Maybe<int> getYear() const { return metadata.getYear(); }
/// \brief Get the ID of the signature.
const std::string &
getId() const
{
return metadata.getId();
}
/// \brief Get the log title of the signature.
const std::string &
getLogTitle() const
{
return metadata.getLogTitle();
}
/// \brief Get the name of the signature.
const std::string &
getName() const
{
return metadata.getName();
}
/// \brief Get the update version of the signature.
const std::string &
getUpdateVersion() const
{
return metadata.getUpdateVersion();
}
/// \brief Get the source indicator of the signature.
const std::string &
getSource() const
{
return metadata.getSource();
}
/// \brief Get the feed version of the signature.
const std::string &
getFeedVersion() const
{
return metadata.getFeedVersion();
}
/// \brief Get the CVE list of the signature.
const std::vector<std::string> &
getCveList() const
{
return metadata.getCveList();
}
/// \brief Get the severity level of the signature.
IPSLevel
getSeverity() const
{
return metadata.getSeverity();
}
/// \brief Get the severity level as a string of the signature.
std::string
getSeverityString() const
{
return metadata.getSeverityString();
}
/// \brief Get the confidence level of the signature.
IPSLevel
getConfidence() const
{
return metadata.getConfidence();
}
/// \brief Get the confidence level as a string of the signature.
std::string
getConfidenceString() const
{
return metadata.getConfidenceString();
}
/// \brief Get the performance level of the signature.
IPSLevel
getPerformance() const
{
return metadata.getPerformance();
}
/// \brief Get the performance level as a string of the signature.
std::string
getPerformanceString() const
{
return metadata.getPerformanceString();
}
/// \brief Check if the signature is silent.
bool
isSilent() const
{
return metadata.isSilent();
}
/// \brief Get the incident type of the signature.
std::string
getIncidentType() const
{
return metadata.getIncidentType();
}
/// \brief Check if the signature is from a specific year or later.
/// \param year The year to compare with.
bool
isYearAtLeast(const Maybe<int> &year) const
{
return metadata.isYearAtLeast(year);
}
/// \brief Get the year of the signature.
Maybe<int>
getYear() const
{
return metadata.getYear();
}
private:
IPSSignatureMetaData metadata;
std::shared_ptr<BaseSignature> rule;
};
/// \class SignatureAndAction
/// \brief Represents a signature and its associated action.
class SignatureAndAction
{
public:
SignatureAndAction(std::shared_ptr<CompleteSignature> _signature, SignatureAction _action)
:
signature(_signature),
action(_action)
/// \brief Construct a SignatureAndAction object.
/// \param _signature The complete signature.
/// \param _action The signature action.
SignatureAndAction(std::shared_ptr<CompleteSignature> _signature, SignatureAction _action) :
signature(_signature), action(_action)
{}
/// \brief Check if the signature is matched for prevention.
/// \param context_buffer The context buffer.
/// \param pattern The set of patterns to match.
bool isMatchedPrevent(const Buffer &context_buffer, const std::set<PMPattern> &pattern) const;
/// \brief Check if the signature is matched silently.
/// \param context_buffer The context buffer.
bool matchSilent(const Buffer &context_buffer) const;
/// \brief Get the set of patterns in the signature.
std::set<PMPattern>
patternsInSignature() const
{
return signature->patternsInSignature();
}
bool isMatchedPrevent(const Buffer &context_buffer, const std::set<PMPattern> &pattern) const;
bool matchSilent(const Buffer &context_buffer) const;
std::set<PMPattern> patternsInSignature() const { return signature->patternsInSignature(); }
const std::vector<std::string> & getContext() const { return signature->getContext(); }
/// \brief Get the context of the signature.
const std::vector<std::string> &
getContext() const
{
return signature->getContext();
}
private:
/// \brief Get the action results for the IPS state.
/// \param ips_state The IPS entry.
ActionResults getAction(const IPSEntry &ips_state) const;
std::shared_ptr<CompleteSignature> signature;
SignatureAction action;
};
} // IPSSignatureSubTypes
} // namespace IPSSignatureSubTypes
/// \class IPSSignaturesPerContext
/// \brief Represents IPS signatures per context.
class IPSSignaturesPerContext : public Singleton::Consume<I_FirstTierAgg>
{
public:
/// \brief Add a signature to the context.
/// \param sig The signature and its associated action.
void addSignature(const IPSSignatureSubTypes::SignatureAndAction &sig);
/// \brief Check if the context is matched for prevention.
/// \param context_buffer The context buffer.
bool isMatchedPrevent(const Buffer &context_buffer) const;
/// \brief Calculate the first tier for the given context name.
/// \param ctx_name The context name.
void calcFirstTier(const std::string &ctx_name);
private:
/// \brief Get the first tier matches for the buffer.
/// \param buffer The buffer to match.
std::set<PMPattern> getFirstTierMatches(const Buffer &buffer) const;
std::map<PMPattern, std::vector<IPSSignatureSubTypes::SignatureAndAction>> signatures_per_lss;
@@ -135,11 +412,17 @@ private:
std::shared_ptr<PMHook> first_tier;
};
/// \class IPSSignaturesResource
/// \brief Represents IPS signatures resource.
class IPSSignaturesResource
{
public:
/// \brief Load the IPS signatures resource from a JSON archive.
/// \param ar The JSON input archive.
void load(cereal::JSONInputArchive &ar);
/// \brief Get all the signatures.
/// \return A vector of shared pointers to CompleteSignature.
const std::vector<std::shared_ptr<IPSSignatureSubTypes::CompleteSignature>> &
getSignatures() const
{
@@ -150,11 +433,26 @@ private:
std::vector<std::shared_ptr<IPSSignatureSubTypes::CompleteSignature>> all_signatures;
};
/// \class SnortSignaturesResourceFile
/// \brief Represents Snort signatures resource file.
class SnortSignaturesResourceFile
{
public:
/// \brief Load the Snort signatures resource file from a JSON archive.
/// \param ar The JSON input archive.
void load(cereal::JSONInputArchive &ar);
bool isFile(const std::string &file_name) const { return file_name == name; }
/// \brief Check if the file name matches.
/// \param file_name The name of the file.
/// \return True if the file name matches, otherwise false.
bool
isFile(const std::string &file_name) const
{
return file_name == name;
}
/// \brief Get all the signatures.
/// \return A vector of shared pointers to CompleteSignature.
const std::vector<std::shared_ptr<IPSSignatureSubTypes::CompleteSignature>> &
getSignatures() const
{
@@ -166,11 +464,18 @@ private:
std::vector<std::shared_ptr<IPSSignatureSubTypes::CompleteSignature>> all_signatures;
};
/// \class SnortSignaturesResource
/// \brief Represents Snort signatures resource.
class SnortSignaturesResource
{
public:
/// \brief Load the Snort signatures resource from a JSON archive.
/// \param ar The JSON input archive.
void load(cereal::JSONInputArchive &ar);
/// \brief Get all the signatures for the given file name.
/// \param file_name The name of the file.
/// \return A vector of shared pointers to CompleteSignature.
const std::vector<std::shared_ptr<IPSSignatureSubTypes::CompleteSignature>> &
getSignatures(const std::string &file_name) const
{
@@ -185,21 +490,74 @@ private:
std::vector<SnortSignaturesResourceFile> files;
};
/// \class IPSSignatures
/// \brief Represents IPS signatures.
class IPSSignatures
{
std::set<PMPattern> getFirstTier(const ParsedContext &context);
public:
/// \brief Load the IPS signatures from a JSON archive.
/// \param ar The JSON input archive.
void load(cereal::JSONInputArchive &ar);
/// \brief Check if the context is matched for prevention.
/// \param context_name The name of the context.
/// \param context_buffer The context buffer.
bool isMatchedPrevent(const std::string &context_name, const Buffer &context_buffer) const;
bool isEmpty() const { return signatures_per_context.empty(); }
/// \brief Check if the IPS signatures are empty.
/// \return True if the signatures are empty, otherwise false.
bool
isEmpty() const
{
return signatures_per_context.empty();
}
/// \brief Check if the IPS signatures for the given context are empty.
/// \param context The name of the context.
/// \return True if the signatures for the context are empty, otherwise false.
bool isEmpty(const std::string &context) const;
const std::string & getAsset() const { return asset_name; }
const std::string & getAssetId() const { return asset_id; }
const std::string & getPractice() const { return practice_name; }
const std::string & getPracticeId() const { return practice_id; }
const std::string & getSourceIdentifier() const { return source_id; }
/// \brief Get the asset name.
/// \return The asset name.
const std::string &
getAsset() const
{
return asset_name;
}
/// \brief Get the asset ID.
/// \return The asset ID.
const std::string &
getAssetId() const
{
return asset_id;
}
/// \brief Get the practice name.
/// \return The practice name.
const std::string &
getPractice() const
{
return practice_name;
}
/// \brief Get the practice ID.
/// \return The practice ID.
const std::string &
getPracticeId() const
{
return practice_id;
}
/// \brief Get the source identifier.
/// \return The source identifier.
const std::string &
getSourceIdentifier() const
{
return source_id;
}
private:
std::map<std::string, IPSSignaturesPerContext> signatures_per_context;
@@ -210,21 +568,74 @@ private:
std::string source_id;
};
/// \class SnortSignatures
/// \brief Represents Snort signatures.
class SnortSignatures
{
std::set<PMPattern> getFirstTier(const ParsedContext &context);
public:
/// \brief Load the Snort signatures from a JSON archive.
/// \param ar The JSON input archive.
void load(cereal::JSONInputArchive &ar);
/// \brief Check if the context is matched for prevention.
/// \param context_name The name of the context.
/// \param context_buffer The context buffer.
bool isMatchedPrevent(const std::string &context_name, const Buffer &context_buffer) const;
bool isEmpty() const { return signatures_per_context.empty(); }
/// \brief Check if the Snort signatures are empty.
/// \return True if the signatures are empty, otherwise false.
bool
isEmpty() const
{
return signatures_per_context.empty();
}
/// \brief Check if the Snort signatures for the given context are empty.
/// \param context The name of the context.
/// \return True if the signatures for the context are empty, otherwise false.
bool isEmpty(const std::string &context) const;
const std::string & getAsset() const { return asset_name; }
const std::string & getAssetId() const { return asset_id; }
const std::string & getPractice() const { return practice_name; }
const std::string & getPracticeId() const { return practice_id; }
const std::string & getSourceIdentifier() const { return source_id; }
/// \brief Get the asset name.
/// \return The asset name.
const std::string &
getAsset() const
{
return asset_name;
}
/// \brief Get the asset ID.
/// \return The asset ID.
const std::string &
getAssetId() const
{
return asset_id;
}
/// \brief Get the practice name.
/// \return The practice name.
const std::string &
getPractice() const
{
return practice_name;
}
/// \brief Get the practice ID.
/// \return The practice ID.
const std::string &
getPracticeId() const
{
return practice_id;
}
/// \brief Get the source identifier.
/// \return The source identifier.
const std::string &
getSourceIdentifier() const
{
return source_id;
}
private:
std::map<std::string, IPSSignaturesPerContext> signatures_per_context;

View File

@@ -23,6 +23,8 @@ using namespace ReportIS;
using namespace std;
using MatchType = BaseSignature::MatchType;
static const LogTriggerConf default_triger;
static const map<IPSLevel, Severity> severities = {
{ IPSLevel::CRITICAL, Severity::CRITICAL },
{ IPSLevel::HIGH, Severity::HIGH },
@@ -396,7 +398,7 @@ SignatureAndAction::isMatchedPrevent(const Buffer &context_buffer, const set<PMP
dbgDebug(D_IPS) << "Signature matched - sending log";
auto &trigger = getConfigurationWithDefault(LogTriggerConf(), "rulebase", "log");
auto &trigger = getConfigurationWithDefault(default_triger, "rulebase", "log");
bool is_prevent = get<0>(override_action) == IPSSignatureSubTypes::SignatureAction::PREVENT;
auto severity = signature->getSeverity() < IPSLevel::HIGH ? Severity::HIGH : Severity::CRITICAL;

View File

@@ -1,16 +1,14 @@
#include "layer_7_access_control.h"
#include <string>
#include <unordered_set>
#include <boost/algorithm/string/case_conv.hpp>
#include <unordered_set>
#include "config.h"
#include "cache.h"
#include "http_inspection_events.h"
#include "http_transaction_common.h"
#include "nginx_attachment_common.h"
#include "intelligence_comp_v2.h"
#include "intelligence_is_v2/intelligence_query_v2.h"
#include "intelligence_is_v2/query_request_v2.h"
#include "log_generator.h"
@@ -74,7 +72,7 @@ public:
getCrowdsecEventId() const
{
if (!crowdsec_event_id) return genError("Empty ID");
return LogField("externalVendorRecommendationId", crowdsec_event_id);
return LogField("externalVendorRecommendationId", to_string(crowdsec_event_id));
}
bool isMalicious() const { return type == "ban"; }
@@ -103,7 +101,7 @@ private:
unsigned int crowdsec_event_id;
};
class Layer7AccessControl::Impl : public Listener<HttpRequestHeaderEvent>
class Layer7AccessControl::Impl : public Listener<HttpRequestHeaderEvent>, Listener<WaitTransactionEvent>
{
public:
void init();
@@ -126,27 +124,25 @@ public:
return ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INSPECT;
}
auto source_identifier = i_env->get<string>(HttpTransactionData::source_identifier);
if (source_identifier.ok() && IPAddr::createIPAddr(source_identifier.unpack()).ok()) {
dbgTrace(D_L7_ACCESS_CONTROL) << "Found a valid source identifier value: " << source_identifier.unpack();
return checkReputation(source_identifier.unpack());
}
return handleEvent();
}
auto orig_source_ip = i_env->get<IPAddr>(HttpTransactionData::client_ip_ctx);
if (!orig_source_ip.ok()) {
dbgWarning(D_L7_ACCESS_CONTROL) << "Could not extract the Client IP address from context";
return ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT;
}
EventVerdict
respond(const WaitTransactionEvent &) override
{
dbgFlow(D_L7_ACCESS_CONTROL) << "Handling wait verdict";
stringstream ss_client_ip;
ss_client_ip << orig_source_ip.unpack();
return checkReputation(ss_client_ip.str());
return handleEvent();
}
private:
void queryIntelligence();
void scheduleIntelligenceQuery(const string &ip);
void processIntelligenceResponse(const string &ip, const vector<AssetReply<IntelligenceIpReputation>> &response);
Maybe<IntelligenceIpReputation> getIpReputation(const string &ip);
ngx_http_cp_verdict_e checkReputation(const string &source_ip);
void generateLog(const string &source_ip, const IntelligenceIpReputation &ip_reputation) const;
EventVerdict generateLog(const string &source_ip, const IntelligenceIpReputation &ip_reputation) const;
EventVerdict queryIpReputation(const string &source_ip);
EventVerdict handleEvent();
bool isAppEnabled() const;
bool isPrevent() const;
@@ -154,9 +150,12 @@ private:
Maybe<LogField, Context::Error> genLogField(const string &log_key, const string &env_key) const;
Maybe<LogField, Context::Error> genLogIPField(const string &log_key, const string &env_key) const;
bool is_intelligence_routine_running = false;
I_Environment *i_env = nullptr;
I_Intelligence_IS_V2 *i_intelligence = nullptr;
I_MainLoop *i_mainloop = nullptr;
TemporaryCache<string, IntelligenceIpReputation> ip_reputation_cache;
unordered_set<string> pending_ips;
};
bool
@@ -177,79 +176,139 @@ Layer7AccessControl::Impl::isPrevent() const
return mode == "prevent";
}
void
Layer7AccessControl::Impl::scheduleIntelligenceQuery(const string &ip)
{
dbgFlow(D_L7_ACCESS_CONTROL) << "Scheduling intelligence query about reputation of IP: " << ip;
pending_ips.emplace(ip);
if (!is_intelligence_routine_running) {
dbgTrace(D_L7_ACCESS_CONTROL) << "Starting intelligence routine";
is_intelligence_routine_running = true;
i_mainloop->addOneTimeRoutine(
I_MainLoop::RoutineType::System,
[&] () { queryIntelligence(); },
"Check IP reputation"
);
}
}
Maybe<IntelligenceIpReputation>
Layer7AccessControl::Impl::getIpReputation(const string &ip)
{
dbgFlow(D_L7_ACCESS_CONTROL) << "Getting reputation of IP " << ip;
if (ip_reputation_cache.doesKeyExists(ip)) return ip_reputation_cache.getEntry(ip);
dbgTrace(D_L7_ACCESS_CONTROL) << "Not found in cache - about to query intelligence";
dbgTrace(D_L7_ACCESS_CONTROL) << ip << " reputation was not found in cache";
QueryRequest request = QueryRequest(
Condition::EQUALS,
"ipv4Addresses",
ip,
true,
AttributeKeyType::REGULAR
);
auto response = i_intelligence->queryIntelligence<IntelligenceIpReputation>(request);
if (!response.ok()) {
dbgWarning(D_L7_ACCESS_CONTROL) << "Failed to query intelligence about reputation of IP: " << ip;
return genError("Failed to query intelligence");
}
auto &unpacked_response = response.unpack();
if (unpacked_response.empty()) {
dbgTrace(D_L7_ACCESS_CONTROL) << "Intelligence reputation response collection is empty. IP is clean.";
return IntelligenceIpReputation();
}
for (const auto &intelligence_reply : unpacked_response) {
if (intelligence_reply.getAssetType() == crowdsec_asset_type && !intelligence_reply.getData().empty()){
dbgTrace(D_L7_ACCESS_CONTROL) << intelligence_reply.getData().front();
return intelligence_reply.getData().front();
}
}
return IntelligenceIpReputation();
return genError("Intelligence needed");
}
ngx_http_cp_verdict_e
Layer7AccessControl::Impl::checkReputation(const string &source_ip)
EventVerdict
Layer7AccessControl::Impl::queryIpReputation(const string &source_ip)
{
auto ip_reputation = getIpReputation(source_ip);
if (!ip_reputation.ok()) {
dbgWarning(D_L7_ACCESS_CONTROL) << "Could not query intelligence. Retruning default verdict";
bool is_drop_by_default = getProfileAgentSettingWithDefault<bool>(false, "layer7AccessControl.dropByDefault");
if (!(is_drop_by_default && isPrevent())) return ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT;
generateLog(source_ip, IntelligenceIpReputation());
return ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP;
dbgTrace(D_L7_ACCESS_CONTROL) << "Scheduling Intelligence query - returning Wait verdict";
scheduleIntelligenceQuery(source_ip);
return ngx_http_cp_verdict_e::TRAFFIC_VERDICT_WAIT;
}
if (!ip_reputation.unpack().isMalicious()) {
dbgTrace(D_L7_ACCESS_CONTROL) << "Accepting IP: " << source_ip;
ip_reputation_cache.deleteEntry(source_ip);
return ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT;
}
ip_reputation_cache.emplaceEntry(source_ip, ip_reputation.unpack());
return generateLog(source_ip, ip_reputation.unpack());
}
if (isPrevent()) {
dbgTrace(D_L7_ACCESS_CONTROL) << "Dropping IP: " << source_ip;
generateLog(source_ip, ip_reputation.unpack());
return ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP;
EventVerdict
Layer7AccessControl::Impl::handleEvent()
{
auto source_identifier = i_env->get<string>(HttpTransactionData::source_identifier);
if (source_identifier.ok() && IPAddr::createIPAddr(source_identifier.unpack()).ok()) {
dbgTrace(D_L7_ACCESS_CONTROL) << "Found a valid source identifier value: " << source_identifier.unpack();
return queryIpReputation(source_identifier.unpack());
}
dbgTrace(D_L7_ACCESS_CONTROL) << "Detecting IP: " << source_ip;
generateLog(source_ip, ip_reputation.unpack());
auto orig_source_ip = i_env->get<IPAddr>(HttpTransactionData::client_ip_ctx);
if (orig_source_ip.ok()) {
stringstream ss_client_ip;
ss_client_ip << orig_source_ip.unpack();
return queryIpReputation(ss_client_ip.str());
}
dbgWarning(D_L7_ACCESS_CONTROL) << "Could not extract the Client IP address from context";
return ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT;
}
void
Layer7AccessControl::Impl::processIntelligenceResponse(
const string &ip,
const vector<AssetReply<IntelligenceIpReputation>> &response)
{
if (response.empty()) {
dbgTrace(D_L7_ACCESS_CONTROL) << "Intelligence reputation response collection is empty. IP is clean.";
ip_reputation_cache.emplaceEntry(ip, IntelligenceIpReputation());
return;
}
for (const auto &intelligence_reply : response) {
if (intelligence_reply.getAssetType() == crowdsec_asset_type && !intelligence_reply.getData().empty()) {
dbgTrace(D_L7_ACCESS_CONTROL) << intelligence_reply.getData().front();
ip_reputation_cache.emplaceEntry(ip, intelligence_reply.getData().front());
return;
}
}
dbgTrace(D_L7_ACCESS_CONTROL) << "Could not find a matching intelligence asset type for IP: " << ip;
ip_reputation_cache.emplaceEntry(ip, IntelligenceIpReputation());
}
void
Layer7AccessControl::Impl::queryIntelligence()
{
dbgFlow(D_L7_ACCESS_CONTROL) << "Started IP reputation intelligence routine";
while (!pending_ips.empty()) {
i_mainloop->yield();
auto ip = *(pending_ips.begin());
pending_ips.erase(pending_ips.begin());
if (ip_reputation_cache.doesKeyExists(ip)) continue;
dbgTrace(D_L7_ACCESS_CONTROL) << "Querying intelligence about reputation of IP: " << ip;
QueryRequest request = QueryRequest(
Condition::EQUALS,
"ipv4Addresses",
ip,
true,
AttributeKeyType::REGULAR
);
auto response = i_intelligence->queryIntelligence<IntelligenceIpReputation>(request);
if (!response.ok()) {
dbgWarning(D_L7_ACCESS_CONTROL)
<< "Failed to query intelligence about reputation of IP: "
<< ip
<< ", error: "
<< response.getErr();
ip_reputation_cache.emplaceEntry(ip, IntelligenceIpReputation());
continue;
}
processIntelligenceResponse(ip, response.unpack());
}
is_intelligence_routine_running = false;
}
EventVerdict
Layer7AccessControl::Impl::generateLog(const string &source_ip, const IntelligenceIpReputation &ip_reputation) const
{
dbgFlow(D_L7_ACCESS_CONTROL) << "About to generate Layer-7 Access Control log";
@@ -280,11 +339,21 @@ Layer7AccessControl::Impl::generateLog(const string &source_ip, const Intelligen
<< LogField("sourceIP", source_ip)
<< LogField("externalVendorName", "CrowdSec")
<< LogField("waapIncidentType", "CrowdSec")
<< LogField("practiceSubType", "Web Access Control")
<< LogField("practiceType", "Access Control")
<< ip_reputation.getCrowdsecEventId()
<< ip_reputation.getType()
<< ip_reputation.getOrigin()
<< ip_reputation.getIpv4Address()
<< ip_reputation.getScenario();
if (isPrevent()) {
dbgTrace(D_L7_ACCESS_CONTROL) << "Dropping IP: " << source_ip;
return ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP;
}
dbgTrace(D_L7_ACCESS_CONTROL) << "Detecting IP: " << source_ip;
return ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT;
}
Maybe<LogField, Context::Error>
@@ -313,6 +382,7 @@ Layer7AccessControl::Impl::init()
registerListener();
i_env = Singleton::Consume<I_Environment>::by<Layer7AccessControl>();
i_intelligence = Singleton::Consume<I_Intelligence_IS_V2>::by<Layer7AccessControl>();
i_mainloop = Singleton::Consume<I_MainLoop>::by<Layer7AccessControl>();
chrono::minutes expiration(
getProfileAgentSettingWithDefault<uint>(60u, "layer7AccessControl.crowdsec.cacheExpiration")
@@ -320,7 +390,7 @@ Layer7AccessControl::Impl::init()
ip_reputation_cache.startExpiration(
expiration,
Singleton::Consume<I_MainLoop>::by<Layer7AccessControl>(),
i_mainloop,
Singleton::Consume<I_TimeGet>::by<Layer7AccessControl>()
);
}

View File

@@ -52,6 +52,7 @@ public:
const EventVerdict drop_verdict = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP;
const EventVerdict accept_verdict = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT;
const EventVerdict inspect_verdict = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INSPECT;
const EventVerdict wait_verdict = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_WAIT;
Layer7AccessControl l7_access_control;
::Environment env;
ConfigComponent config;
@@ -62,6 +63,7 @@ public:
NiceMock<MockRestApi> mock_rest;
AgentDetails agent_details;
IntelligenceComponentV2 intelligence_comp;
I_MainLoop::Routine query_intelligence_routine;
Context ctx;
};
@@ -248,7 +250,7 @@ Layer7AccessControlTest::verifyReport(
EXPECT_THAT(log, HasSubstr("\"destinationIP\": \"5.6.7.8\""));
EXPECT_THAT(log, HasSubstr("\"externalVendorName\": \"CrowdSec\""));
EXPECT_THAT(log, HasSubstr("\"waapIncidentType\": \"CrowdSec\""));
EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendationId\": 2253734"));
EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendationId\": \"2253734\""));
EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendedAction\": \"ban\""));
EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendationOrigin\": \"cscli\""));
EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendedAffectedScope\": \"1.2.3.4\""));
@@ -273,6 +275,13 @@ TEST_F(Layer7AccessControlTest, ReturnAcceptVerdict)
const HttpHeader header2{ Buffer("date"), Buffer("Sun, 26 Mar 2023 18:45:22 GMT"), 1 };
const HttpHeader header3{ Buffer("x-forwarded-for"), Buffer("1.2.3.4"), 2, true};
EXPECT_CALL(
mock_ml,
addOneTimeRoutine(_, _, "Check IP reputation", _))
.WillOnce(DoAll(SaveArg<1>(&query_intelligence_routine), Return(0))
);
EXPECT_CALL(mock_ml, yield(A<bool>())).Times(1);
EXPECT_THAT(
HttpRequestHeaderEvent(header1).performNamedQuery(),
ElementsAre(Pair("Layer-7 Access Control app", inspect_verdict))
@@ -283,6 +292,13 @@ TEST_F(Layer7AccessControlTest, ReturnAcceptVerdict)
);
EXPECT_THAT(
HttpRequestHeaderEvent(header3).performNamedQuery(),
ElementsAre(Pair("Layer-7 Access Control app", wait_verdict))
);
query_intelligence_routine();
EXPECT_THAT(
WaitTransactionEvent().performNamedQuery(),
ElementsAre(Pair("Layer-7 Access Control app", accept_verdict))
);
}
@@ -299,6 +315,13 @@ TEST_F(Layer7AccessControlTest, ReturnDropVerdictOnMaliciousReputation)
sendMessage(true, _, _, _, _, _, _, MessageTypeTag::INTELLIGENCE)
).WillOnce(Return(malicious_intelligence_response));
EXPECT_CALL(
mock_ml,
addOneTimeRoutine(_, _, "Check IP reputation", _))
.WillOnce(DoAll(SaveArg<1>(&query_intelligence_routine), Return(0))
);
EXPECT_CALL(mock_ml, yield(A<bool>())).Times(1);
registerTransactionData();
ctx.registerValue<string>(HttpTransactionData::source_identifier, "1.2.3.4");
const HttpHeader header1{ Buffer("Content-Type"), Buffer("application/json"), 0 };
@@ -310,7 +333,18 @@ TEST_F(Layer7AccessControlTest, ReturnDropVerdictOnMaliciousReputation)
EXPECT_THAT(HttpRequestHeaderEvent(header1).query(), ElementsAre(inspect_verdict));
EXPECT_THAT(HttpRequestHeaderEvent(header2).query(), ElementsAre(inspect_verdict));
EXPECT_THAT(HttpRequestHeaderEvent(header3).query(), ElementsAre(drop_verdict));
EXPECT_THAT(
HttpRequestHeaderEvent(header3).performNamedQuery(),
ElementsAre(Pair("Layer-7 Access Control app", wait_verdict))
);
query_intelligence_routine();
EXPECT_THAT(
WaitTransactionEvent().performNamedQuery(),
ElementsAre(Pair("Layer-7 Access Control app", drop_verdict))
);
verifyReport(report, "1.2.3.4", "Prevent");
}
@@ -327,6 +361,13 @@ TEST_F(Layer7AccessControlTest, ReturnDropVerdictCacheBased)
sendMessage(true, _, _, _, _, _, _, MessageTypeTag::INTELLIGENCE)
).WillOnce(Return(malicious_intelligence_response));
EXPECT_CALL(
mock_ml,
addOneTimeRoutine(_, _, "Check IP reputation", _))
.WillOnce(DoAll(SaveArg<1>(&query_intelligence_routine), Return(0))
);
EXPECT_CALL(mock_ml, yield(A<bool>())).Times(1);
registerTransactionData();
ctx.registerValue<string>(HttpTransactionData::source_identifier, "1.2.3.4");
const HttpHeader header1{ Buffer("Content-Type"), Buffer("application/json"), 0 };
@@ -338,7 +379,18 @@ TEST_F(Layer7AccessControlTest, ReturnDropVerdictCacheBased)
EXPECT_THAT(HttpRequestHeaderEvent(header1).query(), ElementsAre(inspect_verdict));
EXPECT_THAT(HttpRequestHeaderEvent(header2).query(), ElementsAre(inspect_verdict));
EXPECT_THAT(HttpRequestHeaderEvent(header3).query(), ElementsAre(drop_verdict));
EXPECT_THAT(
HttpRequestHeaderEvent(header3).performNamedQuery(),
ElementsAre(Pair("Layer-7 Access Control app", wait_verdict))
);
query_intelligence_routine();
EXPECT_THAT(
WaitTransactionEvent().performNamedQuery(),
ElementsAre(Pair("Layer-7 Access Control app", drop_verdict))
);
verifyReport(report, "1.2.3.4", "Prevent");
@@ -361,6 +413,13 @@ TEST_F(Layer7AccessControlTest, AcceptOnDetect)
sendMessage(true, _, _, _, _, _, _, MessageTypeTag::INTELLIGENCE)
).WillOnce(Return(malicious_intelligence_response));
EXPECT_CALL(
mock_ml,
addOneTimeRoutine(_, _, "Check IP reputation", _))
.WillOnce(DoAll(SaveArg<1>(&query_intelligence_routine), Return(0))
);
EXPECT_CALL(mock_ml, yield(A<bool>())).Times(1);
registerTransactionData();
ctx.registerValue<string>(HttpTransactionData::source_identifier, "1.2.3.4");
const HttpHeader header1{ Buffer("Content-Type"), Buffer("application/json"), 0 };
@@ -372,7 +431,18 @@ TEST_F(Layer7AccessControlTest, AcceptOnDetect)
EXPECT_THAT(HttpRequestHeaderEvent(header1).query(), ElementsAre(inspect_verdict));
EXPECT_THAT(HttpRequestHeaderEvent(header2).query(), ElementsAre(inspect_verdict));
EXPECT_THAT(HttpRequestHeaderEvent(header3).query(), ElementsAre(accept_verdict));
EXPECT_THAT(
HttpRequestHeaderEvent(header3).performNamedQuery(),
ElementsAre(Pair("Layer-7 Access Control app", wait_verdict))
);
query_intelligence_routine();
EXPECT_THAT(
WaitTransactionEvent().performNamedQuery(),
ElementsAre(Pair("Layer-7 Access Control app", accept_verdict))
);
verifyReport(report, "1.2.3.4", "Detect");
}
@@ -389,6 +459,13 @@ TEST_F(Layer7AccessControlTest, FallbackToSourceIPAndDrop)
sendMessage(true, _, _, _, _, _, _, MessageTypeTag::INTELLIGENCE)
).WillOnce(Return(malicious_intelligence_response));
EXPECT_CALL(
mock_ml,
addOneTimeRoutine(_, _, "Check IP reputation", _))
.WillOnce(DoAll(SaveArg<1>(&query_intelligence_routine), Return(0))
);
EXPECT_CALL(mock_ml, yield(A<bool>())).Times(1);
registerTransactionData();
const HttpHeader header1{ Buffer("Content-Type"), Buffer("application/json"), 0 };
const HttpHeader header2{ Buffer("date"), Buffer("Sun, 26 Mar 2023 18:45:22 GMT"), 1, true };
@@ -397,7 +474,18 @@ TEST_F(Layer7AccessControlTest, FallbackToSourceIPAndDrop)
EXPECT_CALL(mock_logging, sendLog(_)).WillOnce(SaveArg<0>(&report));
EXPECT_THAT(HttpRequestHeaderEvent(header1).query(), ElementsAre(inspect_verdict));
EXPECT_THAT(HttpRequestHeaderEvent(header2).query(), ElementsAre(drop_verdict));
EXPECT_THAT(
HttpRequestHeaderEvent(header2).performNamedQuery(),
ElementsAre(Pair("Layer-7 Access Control app", wait_verdict))
);
query_intelligence_routine();
EXPECT_THAT(
WaitTransactionEvent().performNamedQuery(),
ElementsAre(Pair("Layer-7 Access Control app", drop_verdict))
);
verifyReport(report, "", "Prevent");
}

View File

@@ -0,0 +1,24 @@
include_directories(include)
add_library(local_policy_mgmt_gen
appsec_practice_section.cc
exceptions_section.cc
ingress_data.cc
rules_config_section.cc
settings_section.cc
snort_section.cc
triggers_section.cc
trusted_sources_section.cc
policy_maker_utils.cc
k8s_policy_utils.cc
local_policy_mgmt_gen.cc
new_appsec_policy_crd_parser.cc
new_appsec_linux_policy.cc
new_custom_response.cc
new_trusted_sources.cc
new_log_trigger.cc
new_practice.cc
new_exceptions.cc
access_control_practice.cc
configmaps.cc
reverse_proxy_section.cc
)

View File

@@ -0,0 +1,245 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "access_control_practice.h"
using namespace std;
USE_DEBUG_FLAG(D_LOCAL_POLICY);
// LCOV_EXCL_START Reason: no test exist
static const set<string> valid_modes = {"prevent", "detect", "inactive"};
static const set<string> valid_units = {"minute", "second"};
static const std::unordered_map<std::string, std::string> key_to_mode_val = {
{ "prevent-learn", "Prevent"},
{ "detect-learn", "Detect"},
{ "prevent", "Prevent"},
{ "detect", "Detect"},
{ "inactive", "Inactive"}
};
static const std::unordered_map<std::string, std::string> key_to_units_val = {
{ "second", "Second"},
{ "minute", "Minute"}
};
void
RateLimitRulesTriggerSection::save(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("id", id),
cereal::make_nvp("name", name),
cereal::make_nvp("type", type)
);
}
const string &
RateLimitRulesTriggerSection::getName() const
{
return name;
}
void
RateLimitRulesSection::save(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("id", id),
cereal::make_nvp("URI", uri),
cereal::make_nvp("scope", key_to_units_val.at(scope)),
cereal::make_nvp("triggers", triggers),
cereal::make_nvp("limit", limit)
);
}
RateLimitSection::RateLimitSection(
const string &asset_name,
const string &url,
const string &uri,
const std::string &_mode,
const std::string &_practice_id,
const std::string &_name,
const std::vector<RateLimitRulesSection> &_rules)
:
mode(_mode),
practice_id(_practice_id),
name(_name),
rules(_rules)
{
bool any = asset_name == "Any" && url == "Any" && uri == "Any";
string asset_id = any ? "Any" : url+uri;
context = "assetId(" + asset_id + ")";
}
void
RateLimitSection::save(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("context", context),
cereal::make_nvp("mode", key_to_mode_val.at(mode)),
cereal::make_nvp("practiceId", practice_id),
cereal::make_nvp("name", name),
cereal::make_nvp("rules", rules)
);
}
const string &
RateLimitSection::getId() const
{
return practice_id;
}
const string &
RateLimitSection::getName() const
{
return name;
}
const string &
RateLimitSection::getMode() const
{
return mode;
}
void
AccessControlRulebaseSection::save(cereal::JSONOutputArchive &out_ar) const
{
vector<string> empty;
out_ar(
cereal::make_nvp("accessControl", empty),
cereal::make_nvp("traditionalFirewall", empty),
cereal::make_nvp("l4firewall", empty),
cereal::make_nvp("rateLimit", rate_limit)
);
}
void
AccessControlRulebaseWrapper::save(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("rulebase", rule_base)
);
}
void
AccessControlRateLimiteRules::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading Access control rate limite rules";
parseAppsecJSONKey<int>("limit", limit, archive_in);
parseAppsecJSONKey<string>("uri", uri, archive_in);
parseAppsecJSONKey<string>("unit", unit, archive_in);
if (valid_units.count(unit) == 0) {
dbgWarning(D_LOCAL_POLICY)
<< "Access control rate limite rules units invalid: "
<< unit;
}
parseAppsecJSONKey<string>("comment", comment, archive_in);
parseAppsecJSONKey<vector<string>>("triggers", triggers, archive_in);
}
const vector<string>
AccessControlRateLimiteRules::getTriggers() const
{
return triggers;
}
RateLimitRulesSection
AccessControlRateLimiteRules::createRateLimitRulesSection(const RateLimitRulesTriggerSection &trigger) const
{
string id = "";
try {
id = to_string(boost::uuids::random_generator()());
} catch (const boost::uuids::entropy_error &e) {
dbgWarning(D_LOCAL_POLICY) << "Failed to create random id";
}
vector<RateLimitRulesTriggerSection> triggers_section;
string trigger_name = trigger.getName().substr(trigger.getName().find("/") + 1);
if (find(triggers.begin(), triggers.end(), trigger_name) != triggers.end()) {
triggers_section.push_back(trigger);
}
return RateLimitRulesSection(
limit,
id,
uri,
unit,
triggers_section
);
}
void
AccessControlRateLimit::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading Access control rate limit";
parseAppsecJSONKey<string>("overrideMode", mode, archive_in, "Inactive");
if (valid_modes.count(mode) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec access control rate limit override mode invalid: " << mode;
}
parseAppsecJSONKey<std::vector<AccessControlRateLimiteRules>>("rules", rules, archive_in);
}
vector<RateLimitRulesSection>
AccessControlRateLimit::createRateLimitRulesSection(const RateLimitRulesTriggerSection &trigger) const
{
vector<RateLimitRulesSection> rules_section;
for (const AccessControlRateLimiteRules &rule : rules) {
rules_section.push_back(rule.createRateLimitRulesSection(trigger));
}
return rules_section;
}
const vector<AccessControlRateLimiteRules> &
AccessControlRateLimit::getRules() const
{
return rules;
}
const string &
AccessControlRateLimit::getMode() const
{
return mode;
}
void
AccessControlPracticeSpec::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec practice spec";
parseAppsecJSONKey<string>("name", practice_name, archive_in);
parseAppsecJSONKey<string>("appsecClassName", appsec_class_name, archive_in);
parseAppsecJSONKey<AccessControlRateLimit>("rateLimit", rate_limit, archive_in);
}
void
AccessControlPracticeSpec::setName(const string &_name)
{
practice_name = _name;
}
const AccessControlRateLimit &
AccessControlPracticeSpec::geRateLimit() const
{
return rate_limit;
}
const string &
AccessControlPracticeSpec::getAppSecClassName() const
{
return appsec_class_name;
}
const string &
AccessControlPracticeSpec::getName() const
{
return practice_name;
}
// LCOV_EXCL_STOP

View File

@@ -34,6 +34,26 @@ AppSecWebBotsURI::getURI() const
return uri;
}
vector<string>
AppSecPracticeAntiBot::getIjectedUris() const
{
vector<string> injected;
for (const AppSecWebBotsURI &uri : injected_uris) {
injected.push_back(uri.getURI());
}
return injected;
}
vector<string>
AppSecPracticeAntiBot::getValidatedUris() const
{
vector<string> validated;
for (const AppSecWebBotsURI &uri : validated_uris) {
validated.push_back(uri.getURI());
}
return validated;
}
void
AppSecPracticeAntiBot::load(cereal::JSONInputArchive &archive_in)
{
@@ -52,7 +72,7 @@ AppSecPracticeAntiBot::save(cereal::JSONOutputArchive &out_ar) const
vector<string> injected;
vector<string> validated;
for (const AppSecWebBotsURI &uri : injected_uris) injected.push_back(uri.getURI());
for (const AppSecWebBotsURI &uri : validated_uris) injected.push_back(uri.getURI());
for (const AppSecWebBotsURI &uri : validated_uris) validated.push_back(uri.getURI());
out_ar(
cereal::make_nvp("injected", injected),
cereal::make_nvp("validated", validated)
@@ -295,24 +315,90 @@ TriggersInWaapSection::save(cereal::JSONOutputArchive &out_ar) const
);
}
ParsedMatch::ParsedMatch(const string &_operator, const string &_tag, const string &_value)
:
operator_type(_operator),
tag(_tag),
value(_value)
{
}
// LCOV_EXCL_START Reason: no test exist
ParsedMatch::ParsedMatch(const ExceptionMatch &exceptions)
{
if (exceptions.getOperator() == "equals") {
operator_type = "basic";
tag = exceptions.getKey();
value = exceptions.getValue();
} else {
operator_type = exceptions.getOperator();
}
for (const ExceptionMatch &exception_match : exceptions.getMatch()) {
parsed_match.push_back(ParsedMatch(exception_match));
}
}
// LCOV_EXCL_STOP
void
ParsedMatch::save(cereal::JSONOutputArchive &out_ar) const
{
if (parsed_match.size() > 0) {
out_ar(cereal::make_nvp("operator", operator_type));
int i = 0;
for (const ParsedMatch &operand : parsed_match) {
i++;
out_ar(cereal::make_nvp("operand" + to_string(i), operand));
}
} else {
out_ar(
cereal::make_nvp("operator", operator_type),
cereal::make_nvp("tag", tag),
cereal::make_nvp("value", value)
);
}
}
AppSecOverride::AppSecOverride(const SourcesIdentifiers &parsed_trusted_sources)
{
string source_ident = parsed_trusted_sources.getSourceIdent();
map<string, string> behavior = {{"httpSourceId", source_ident}};
parsed_behavior.push_back(behavior);
parsed_match = {{"operator", "BASIC"}, {"tag", "sourceip"}, {"value", "0.0.0.0/0"}};
parsed_match = ParsedMatch("BASIC", "sourceip", "0.0.0.0/0");
}
// LCOV_EXCL_START Reason: no test exist
AppSecOverride::AppSecOverride(const InnerException &parsed_exceptions)
:
id(parsed_exceptions.getBehaviorId()),
parsed_match(parsed_exceptions.getMatch())
{
map<string, string> behavior = {{parsed_exceptions.getBehaviorKey(), parsed_exceptions.getBehaviorValue()}};
parsed_behavior.push_back(behavior);
}
// LCOV_EXCL_STOP
void
AppSecOverride::save(cereal::JSONOutputArchive &out_ar) const
{
string parameter_type = "TrustedSource";
if (!id.empty()) {
out_ar(cereal::make_nvp("id", id));
}
out_ar(
cereal::make_nvp("parsedBehavior", parsed_behavior),
cereal::make_nvp("parsedMatch", parsed_match)
);
}
void
AppsecPracticeAntiBotSection::save(cereal::JSONOutputArchive &out_ar) const
{
out_ar(
cereal::make_nvp("injected", injected_uris),
cereal::make_nvp("validated", validated_uris)
);
}
// LCOV_EXCL_START Reason: no test exist
WebAppSection::WebAppSection(
const string &_application_urls,
const string &_asset_id,
@@ -321,11 +407,13 @@ WebAppSection::WebAppSection(
const string &_rule_name,
const string &_practice_id,
const string &_practice_name,
const string &_context,
const AppSecPracticeSpec &parsed_appsec_spec,
const LogTriggerSection &parsed_log_trigger,
const string &default_mode,
const AppSecTrustedSources &parsed_trusted_sources)
:
const AppSecTrustedSources &parsed_trusted_sources,
const vector<InnerException> &parsed_exceptions)
:
application_urls(_application_urls),
asset_id(_asset_id),
asset_name(_asset_name),
@@ -333,7 +421,7 @@ WebAppSection::WebAppSection(
rule_name(_rule_name),
practice_id(_practice_id),
practice_name(_practice_name),
context("practiceId(" + practice_id +")"),
context(_context),
web_attack_mitigation_severity(parsed_appsec_spec.getWebAttacks().getMinimumConfidence()),
web_attack_mitigation_mode(parsed_appsec_spec.getWebAttacks().getMode(default_mode)),
practice_advanced_config(parsed_appsec_spec),
@@ -351,8 +439,57 @@ WebAppSection::WebAppSection(
for (const SourcesIdentifiers &source_ident : parsed_trusted_sources.getSourcesIdentifiers()) {
overrides.push_back(AppSecOverride(source_ident));
}
for (const InnerException &exception : parsed_exceptions) {
overrides.push_back(AppSecOverride(exception));
}
}
WebAppSection::WebAppSection(
const string &_application_urls,
const string &_asset_id,
const string &_asset_name,
const string &_rule_id,
const string &_rule_name,
const string &_practice_id,
const string &_practice_name,
const string &_context,
const string &_web_attack_mitigation_severity,
const string &_web_attack_mitigation_mode,
const PracticeAdvancedConfig &_practice_advanced_config,
const AppsecPracticeAntiBotSection &_anti_bots,
const LogTriggerSection &parsed_log_trigger,
const AppSecTrustedSources &parsed_trusted_sources)
:
application_urls(_application_urls),
asset_id(_asset_id),
asset_name(_asset_name),
rule_id(_rule_id),
rule_name(_rule_name),
practice_id(_practice_id),
practice_name(_practice_name),
context(_context),
web_attack_mitigation_severity(_web_attack_mitigation_severity),
web_attack_mitigation_mode(_web_attack_mitigation_mode),
practice_advanced_config(_practice_advanced_config),
anti_bots(_anti_bots),
trusted_sources({parsed_trusted_sources})
{
web_attack_mitigation = true;
web_attack_mitigation_action =
web_attack_mitigation_mode != "Prevent" ? "Transparent" :
web_attack_mitigation_severity == "critical" ? "low" :
web_attack_mitigation_severity == "high" ? "balanced" :
web_attack_mitigation_severity == "medium" ? "high" :
"Error";
triggers.push_back(TriggersInWaapSection(parsed_log_trigger));
for (const SourcesIdentifiers &source_ident : parsed_trusted_sources.getSourcesIdentifiers()) {
overrides.push_back(AppSecOverride(source_ident));
}
}
// LCOV_EXCL_STOP
void
WebAppSection::save(cereal::JSONOutputArchive &out_ar) const
{
@@ -448,6 +585,9 @@ ParsedRule::load(cereal::JSONInputArchive &archive_in)
parseAppsecJSONKey<string>("custom-response", custom_response, archive_in);
parseAppsecJSONKey<string>("source-identifiers", source_identifiers, archive_in);
parseAppsecJSONKey<string>("trusted-sources", trusted_sources, archive_in);
parseAppsecJSONKey<string>("upstream", rpm_upstream, archive_in);
parseAppsecJSONKey<string>("rp-settings", rpm_settings, archive_in);
parseAppsecJSONKey<bool>("ssl", rpm_is_ssl, archive_in);
try {
archive_in(cereal::make_nvp("host", host));
} catch (const cereal::Exception &e)
@@ -484,6 +624,24 @@ ParsedRule::getMode() const
return mode;
}
const string &
ParsedRule::rpmGetUpstream() const
{
return rpm_upstream;
}
const std::string &
ParsedRule::rpmGetRPSettings() const
{
return rpm_settings;
}
bool
ParsedRule::rpmIsHttps() const
{
return rpm_is_ssl;
}
void
ParsedRule::setHost(const string &_host)
{
@@ -536,7 +694,7 @@ AppsecPolicySpec::getSpecificRules() const
}
bool
AppsecPolicySpec::isAssetHostExist(const std::string &full_url) const
AppsecPolicySpec::isAssetHostExist(const string &full_url) const
{
for (const ParsedRule &rule : specific_rules) {
if (rule.getHost() == full_url) return true;
@@ -555,10 +713,11 @@ AppsecLinuxPolicy::serialize(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading Appsec Linux Policy";
parseAppsecJSONKey<AppsecPolicySpec>("policies", policies, archive_in);
parseAppsecJSONKey<vector<RPMSettings>>("rp-settings", rpm_settings, archive_in);
parseAppsecJSONKey<vector<AppSecPracticeSpec>>("practices", practices, archive_in);
parseAppsecJSONKey<vector<AppsecTriggerSpec>>("log-triggers", log_triggers, archive_in);
parseAppsecJSONKey<vector<AppSecCustomResponseSpec>>("custom-responses", custom_responses, archive_in);
parseAppsecJSONKey<vector<AppsecExceptionSpec>>("exceptions", exceptions, archive_in);
parseAppsecJSONKey<vector<AppsecException>>("exceptions", exceptions, archive_in);
parseAppsecJSONKey<vector<TrustedSourcesSpec>>("trusted-sources", trusted_sources, archive_in);
parseAppsecJSONKey<vector<SourceIdentifierSpecWrapper>>(
"source-identifiers",
@@ -591,8 +750,8 @@ AppsecLinuxPolicy::getAppSecCustomResponseSpecs() const
return custom_responses;
}
const vector<AppsecExceptionSpec> &
AppsecLinuxPolicy::getAppsecExceptionSpecs() const
const vector<AppsecException> &
AppsecLinuxPolicy::getAppsecExceptions() const
{
return exceptions;
}
@@ -609,6 +768,13 @@ AppsecLinuxPolicy::getAppsecSourceIdentifierSpecs() const
return sources_identifiers;
}
const vector<RPMSettings> &
AppsecLinuxPolicy::rpmGetRPSettings() const
{
return rpm_settings;
}
void
AppsecLinuxPolicy::addSpecificRule(const ParsedRule &_rule)
{

View File

@@ -0,0 +1,58 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "configmaps.h"
using namespace std;
USE_DEBUG_FLAG(D_LOCAL_POLICY);
// LCOV_EXCL_START Reason: no test exist
bool
ConfigMaps::loadJson(const std::string &json)
{
string modified_json = json;
modified_json.pop_back();
stringstream in;
in.str(modified_json);
dbgTrace(D_LOCAL_POLICY) << "Loading ConfigMaps data";
try {
cereal::JSONInputArchive in_ar(in);
in_ar(
cereal::make_nvp("data", data)
);
} catch (cereal::Exception &e) {
dbgError(D_LOCAL_POLICY) << "Failed to load ConfigMaps JSON. Error: " << e.what();
return false;
}
return true;
}
string
ConfigMaps::getFileContent() const
{
if (data.size()) {
return data.begin()->second;
}
return string();
}
string
ConfigMaps::getFileName() const
{
if (data.size()) {
return data.begin()->first;
}
return string();
}
// LCOV_EXCL_STOP

View File

@@ -18,39 +18,61 @@ using namespace std;
USE_DEBUG_FLAG(D_LOCAL_POLICY);
// LCOV_EXCL_START Reason: no test exist
using AttributeGetter = function<vector<string>(const AppsecExceptionSpec&)>;
static const vector<pair<string, AttributeGetter>> attributes = {
{"countryCode", [](const AppsecExceptionSpec& e){ return e.getCountryCode(); }},
{"countryName", [](const AppsecExceptionSpec& e){ return e.getCountryName(); }},
{"hostName", [](const AppsecExceptionSpec& e){ return e.getHostName(); }},
{"paramName", [](const AppsecExceptionSpec& e){ return e.getParamName(); }},
{"paramValue", [](const AppsecExceptionSpec& e){ return e.getParamValue(); }},
{"protectionName", [](const AppsecExceptionSpec& e){ return e.getProtectionName(); }},
{"sourceIdentifier", [](const AppsecExceptionSpec& e){ return e.getSourceIdentifier(); }},
{"sourceIp", [](const AppsecExceptionSpec& e){ return e.getSourceIp(); }},
{"url", [](const AppsecExceptionSpec& e){ return e.getUrl(); }}
};
static const set<string> valid_actions = {"skip", "accept", "drop", "suppressLog"};
static const unordered_map<string, string> key_to_action = {
{ "accept", "accept"},
{ "drop", "reject"},
{ "skip", "ignore"},
{ "suppressLog", "ignore"}
};
void
AppsecExceptionSpec::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec exception spec";
parseAppsecJSONKey<string>("name", name, archive_in);
parseAppsecJSONKey<string>("action", action, archive_in);
parseAppsecJSONKey<string>("action", action, archive_in, "skip");
if (valid_actions.count(action) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec exception action invalid: " << action;
}
parseAppsecJSONKey<vector<string>>("countryCode", country_code, archive_in);
if (!country_code.empty()) conditions_number++;
parseAppsecJSONKey<vector<string>>("countryName", country_name, archive_in);
if (!country_name.empty()) conditions_number++;
parseAppsecJSONKey<vector<string>>("hostName", host_name, archive_in);
if (!host_name.empty()) conditions_number++;
parseAppsecJSONKey<vector<string>>("paramName", param_name, archive_in);
if (!param_name.empty()) conditions_number++;
parseAppsecJSONKey<vector<string>>("paramValue", param_value, archive_in);
if (!param_value.empty()) conditions_number++;
parseAppsecJSONKey<vector<string>>("protectionName", protection_name, archive_in);
if (!protection_name.empty()) conditions_number++;
parseAppsecJSONKey<vector<string>>("sourceIdentifier", source_identifier, archive_in);
if (!source_identifier.empty()) conditions_number++;
parseAppsecJSONKey<vector<string>>("sourceIp", source_ip, archive_in);
if (!source_ip.empty()) conditions_number++;
parseAppsecJSONKey<vector<string>>("url", url, archive_in);
}
void
AppsecExceptionSpec::setName(const string &_name)
{
name = _name;
}
const string &
AppsecExceptionSpec::getName() const
{
return name;
if (!url.empty()) conditions_number++;
}
const string &
@@ -113,10 +135,89 @@ AppsecExceptionSpec::getUrl() const
return url;
}
bool
AppsecExceptionSpec::isOneCondition() const
{
return conditions_number == 1;
}
void
AppsecException::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec exception";
parseAppsecJSONKey<string>("name", name, archive_in);
archive_in(CEREAL_NVP(exception_spec));
}
void
AppsecException::setName(const string &_name)
{
name = _name;
}
const string &
AppsecException::getName() const
{
return name;
}
const vector<AppsecExceptionSpec> &
AppsecException::getExceptions() const
{
return exception_spec;
}
ExceptionMatch::ExceptionMatch(const AppsecExceptionSpec &parsed_exception)
:
match_type(MatchType::Operator),
op("and")
{
bool single_condition = parsed_exception.isOneCondition();
for (auto &attrib : attributes) {
auto &attrib_name = attrib.first;
auto &attrib_getter = attrib.second;
auto exceptions_value = attrib_getter(parsed_exception);
if (exceptions_value.empty()) continue;
if (single_condition) {
if (exceptions_value.size() == 1) {
match_type = MatchType::Condition;
op = "equals";
key = attrib_name;
value = exceptions_value;
return;
} else {
match_type = MatchType::Operator;
op = "or";
for (auto new_value : exceptions_value) {
items.push_back(ExceptionMatch(attrib_name, {new_value}));
}
return;
}
}
items.push_back(ExceptionMatch(attrib_name, exceptions_value));
}
}
ExceptionMatch::ExceptionMatch(const std::string &_key, const std::vector<std::string> &values)
{
if (values.size() == 1) {
match_type = MatchType::Condition;
op = "equals";
key = _key;
value = values;
} else {
match_type = MatchType::Operator;
op = "or";
for (auto new_value : values) {
items.push_back(ExceptionMatch(_key, {new_value}));
}
}
}
ExceptionMatch::ExceptionMatch(const NewAppsecException &parsed_exception)
:
match_type(MatchType::Operator),
op("and")
{
if (!parsed_exception.getCountryCode().empty()) {
items.push_back(ExceptionMatch("countryCode", parsed_exception.getCountryCode()));
@@ -176,17 +277,40 @@ ExceptionMatch::save(cereal::JSONOutputArchive &out_ar) const
}
}
ExceptionBehavior::ExceptionBehavior(
const string &_key,
const string &_value)
:
key(_key),
value(_value)
const string &
ExceptionMatch::getOperator() const
{
return op;
}
const string &
ExceptionMatch::getKey() const
{
return key;
}
const string &
ExceptionMatch::getValue() const
{
return value[0];
}
const vector<ExceptionMatch> &
ExceptionMatch::getMatch() const
{
return items;
}
ExceptionBehavior::ExceptionBehavior(const string &_value)
{
key = _value == "suppressLog" ? "log" : "action";
try {
value = key_to_action.at(_value);
id = to_string(boost::uuids::random_generator()());
} catch (const boost::uuids::entropy_error &e) {
dbgWarning(D_LOCAL_POLICY) << "Failed to generate exception behavior UUID. Error: " << e.what();
} catch (std::exception &e) {
dbgWarning(D_LOCAL_POLICY) << "Failed to find exception name: " << _value << ". Error: " << e.what();
}
}
@@ -200,12 +324,31 @@ ExceptionBehavior::save(cereal::JSONOutputArchive &out_ar) const
);
}
const string
const string &
ExceptionBehavior::getBehaviorId() const
{
return id;
}
const string &
ExceptionBehavior::getBehaviorKey() const
{
return key;
}
const string &
ExceptionBehavior::getBehaviorValue() const
{
return value;
}
InnerException::InnerException(ExceptionBehavior _behavior, ExceptionMatch _match)
:
behavior(_behavior),
match(_match)
{
}
void
InnerException::save(cereal::JSONOutputArchive &out_ar) const
{
@@ -215,12 +358,30 @@ InnerException::save(cereal::JSONOutputArchive &out_ar) const
);
}
const string
const string &
InnerException::getBehaviorId() const
{
return behavior.getBehaviorId();
}
const string &
InnerException::getBehaviorKey() const
{
return behavior.getBehaviorKey();
}
const string &
InnerException::getBehaviorValue() const
{
return behavior.getBehaviorValue();
}
const ExceptionMatch &
InnerException::getMatch() const
{
return match;
}
ExceptionsRulebase::ExceptionsRulebase(
vector<InnerException> _exceptions)
:

View File

@@ -0,0 +1,192 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __ACCESS_CONTROL_PRACTICE_H__
#define __ACCESS_CONTROL_PRACTICE_H__
#include <string>
#include <cereal/archives/json.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include "config.h"
#include "debug.h"
#include "local_policy_common.h"
class RateLimitRulesTriggerSection
{
public:
// LCOV_EXCL_START Reason: no test exist
RateLimitRulesTriggerSection() {};
RateLimitRulesTriggerSection(
const std::string &_id,
const std::string &_name,
const std::string &_type
)
:
id(_id),
name(_name),
type(_type)
{};
// LCOV_EXCL_STOP
void save(cereal::JSONOutputArchive &out_ar) const;
const std::string & getName() const;
private:
std::string id;
std::string name;
std::string type;;
};
class RateLimitRulesSection
{
public:
RateLimitRulesSection() {};
// LCOV_EXCL_START Reason: no test exist
RateLimitRulesSection(
const int _limit,
const std::string &_id,
const std::string &_uri,
const std::string &_scope,
const std::vector<RateLimitRulesTriggerSection> &_triggers
)
:
limit(_limit),
id(_id),
uri(_uri),
scope(_scope),
triggers(_triggers)
{};
// LCOV_EXCL_STOP
void save(cereal::JSONOutputArchive &out_ar) const;
private:
int limit;
std::string id;
std::string uri;
std::string scope;
std::vector<RateLimitRulesTriggerSection> triggers;
};
class RateLimitSection
{
public:
// LCOV_EXCL_START Reason: no test exist
RateLimitSection() {};
// LCOV_EXCL_STOP
RateLimitSection(
const std::string &asset_name,
const std::string &url,
const std::string &uri,
const std::string &_mode,
const std::string &_practice_id,
const std::string &_name,
const std::vector<RateLimitRulesSection> &_rules);
void save(cereal::JSONOutputArchive &out_ar) const;
const std::string & getId() const;
const std::string & getName() const;
const std::string & getMode() const;
private:
std::string context;
std::string mode;
std::string practice_id;
std::string name;
std::vector<RateLimitRulesSection> rules;
};
class AccessControlRulebaseSection
{
public:
AccessControlRulebaseSection() {};
AccessControlRulebaseSection(const std::vector<RateLimitSection> &_rate_limit) : rate_limit(_rate_limit) {};
void save(cereal::JSONOutputArchive &out_ar) const;
private:
std::vector<RateLimitSection> rate_limit;
};
class AccessControlRulebaseWrapper
{
public:
AccessControlRulebaseWrapper() {};
AccessControlRulebaseWrapper(
const std::vector<RateLimitSection> &rate_limits
)
:
rule_base(AccessControlRulebaseSection(rate_limits))
{};
void save(cereal::JSONOutputArchive &out_ar) const;
private:
AccessControlRulebaseSection rule_base;
};
class AccessControlRateLimiteRules
{
public:
void load(cereal::JSONInputArchive &archive_in);
const std::vector<std::string> getTriggers() const;
RateLimitRulesSection createRateLimitRulesSection(const RateLimitRulesTriggerSection &trigger) const;
private:
int limit;
std::string uri;
std::string unit;
std::string comment;
std::vector<std::string> triggers;
};
class AccessControlRateLimit
{
public:
void load(cereal::JSONInputArchive &archive_in);
const std::vector<AccessControlRateLimiteRules> & getRules() const;
const std::string & getMode() const;
std::vector<RateLimitRulesSection> createRateLimitRulesSection(const RateLimitRulesTriggerSection &trigger) const;
private:
std::string mode;
std::vector<AccessControlRateLimiteRules> rules;
};
class AccessControlPracticeSpec
{
public:
void load(cereal::JSONInputArchive &archive_in);
const AccessControlRateLimit & geRateLimit() const;
const std::string & getAppSecClassName() const;
const std::string & getName() const;
void setName(const std::string &_name);
private:
AccessControlRateLimit rate_limit;
std::string appsec_class_name;
std::string practice_name;
};
#endif // __ACCESS_CONTROL_PRACTICE_H__

View File

@@ -28,6 +28,8 @@
#include "triggers_section.h"
#include "exceptions_section.h"
#include "trusted_sources_section.h"
#include "reverse_proxy_section.h"
#include "new_practice.h"
class AppSecWebBotsURI
{
@@ -43,6 +45,9 @@ private:
class AppSecPracticeAntiBot
{
public:
std::vector<std::string> getIjectedUris() const;
std::vector<std::string> getValidatedUris() const;
void load(cereal::JSONInputArchive &archive_in);
void save(cereal::JSONOutputArchive &out_ar) const;
@@ -144,7 +149,7 @@ public:
PracticeAdvancedConfig() {}
PracticeAdvancedConfig(const AppSecPracticeSpec &parsed_appsec_spec)
:
:
http_header_max_size(parsed_appsec_spec.getWebAttacks().getMaxHeaderSizeBytes()),
http_illegal_methods_allowed(0),
http_request_body_max_size(parsed_appsec_spec.getWebAttacks().getMaxBodySizeKb()),
@@ -152,6 +157,22 @@ public:
url_max_size(parsed_appsec_spec.getWebAttacks().getMaxUrlSizeBytes())
{}
// LCOV_EXCL_START Reason: no test exist
PracticeAdvancedConfig(
int _http_header_max_size,
int _http_request_body_max_size,
int _json_max_object_depth,
int _url_max_size)
:
http_header_max_size(_http_header_max_size),
http_illegal_methods_allowed(0),
http_request_body_max_size(_http_request_body_max_size),
json_max_object_depth(_json_max_object_depth),
url_max_size(_url_max_size)
{}
// LCOV_EXCL_STOP
void save(cereal::JSONOutputArchive &out_ar) const;
private:
@@ -166,7 +187,7 @@ class TriggersInWaapSection
{
public:
TriggersInWaapSection(const LogTriggerSection &log_section)
:
:
trigger_type("log"),
id(log_section.getTriggerId()),
name(log_section.getTriggerName()),
@@ -182,16 +203,58 @@ private:
LogTriggerSection log;
};
class AppSecOverride
class ParsedMatch
{
public:
AppSecOverride(const SourcesIdentifiers &parsed_trusted_sources);
ParsedMatch() {}
ParsedMatch(const std::string &_operator, const std::string &_tag, const std::string &_value);
ParsedMatch(const ExceptionMatch &exceptions);
void save(cereal::JSONOutputArchive &out_ar) const;
private:
std::string operator_type;
std::string tag;
std::string value;
std::vector<ParsedMatch> parsed_match;
};
class AppSecOverride
{
public:
AppSecOverride(const SourcesIdentifiers &parsed_trusted_sources);
AppSecOverride(const InnerException &parsed_exceptions);
void save(cereal::JSONOutputArchive &out_ar) const;
private:
std::string id;
std::vector<std::map<std::string, std::string>> parsed_behavior;
std::map<std::string, std::string> parsed_match;
ParsedMatch parsed_match;
};
class AppsecPracticeAntiBotSection
{
public:
AppsecPracticeAntiBotSection() {};
// LCOV_EXCL_START Reason: no test exist
AppsecPracticeAntiBotSection(const NewAppSecPracticeAntiBot &anti_bot) :
injected_uris(anti_bot.getIjectedUris()),
validated_uris(anti_bot.getValidatedUris())
{};
// LCOV_EXCL_STOP
AppsecPracticeAntiBotSection(const AppSecPracticeAntiBot &anti_bot) :
injected_uris(anti_bot.getIjectedUris()),
validated_uris(anti_bot.getValidatedUris())
{};
void save(cereal::JSONOutputArchive &out_ar) const;
private:
std::vector<std::string> injected_uris;
std::vector<std::string> validated_uris;
};
class WebAppSection
@@ -207,12 +270,30 @@ public:
const std::string &_rule_name,
const std::string &_practice_id,
const std::string &_practice_name,
const std::string &_context,
const AppSecPracticeSpec &parsed_appsec_spec,
const LogTriggerSection &parsed_log_trigger,
const std::string &default_mode,
const AppSecTrustedSources &parsed_trusted_sources
const AppSecTrustedSources &parsed_trusted_sources,
const std::vector<InnerException> &parsed_exceptions
);
WebAppSection(
const std::string &_application_urls,
const std::string &_asset_id,
const std::string &_asset_name,
const std::string &_rule_id,
const std::string &_rule_name,
const std::string &_practice_id,
const std::string &_practice_name,
const std::string &_context,
const std::string &_web_attack_mitigation_severity,
const std::string &_web_attack_mitigation_mode,
const PracticeAdvancedConfig &_practice_advanced_config,
const AppsecPracticeAntiBotSection &_anti_bots,
const LogTriggerSection &parsed_log_trigger,
const AppSecTrustedSources &parsed_trusted_sources);
void save(cereal::JSONOutputArchive &out_ar) const;
private:
@@ -230,7 +311,7 @@ private:
bool web_attack_mitigation;
std::vector<TriggersInWaapSection> triggers;
PracticeAdvancedConfig practice_advanced_config;
AppSecPracticeAntiBot anti_bots;
AppsecPracticeAntiBotSection anti_bots;
std::vector<AppSecTrustedSources> trusted_sources;
std::vector<AppSecOverride> overrides;
};
@@ -250,8 +331,8 @@ public:
const std::string &_web_attack_mitigation_severity,
const std::string &_web_attack_mitigation_mode,
bool _web_attack_mitigation,
const AppSecPracticeSpec &parsed_appsec_spec)
:
const PracticeAdvancedConfig &_practice_advanced_config)
:
application_urls(_application_urls),
asset_id(_asset_id),
asset_name(_asset_name),
@@ -264,8 +345,8 @@ public:
web_attack_mitigation_severity(_web_attack_mitigation_severity),
web_attack_mitigation_mode(_web_attack_mitigation_mode),
web_attack_mitigation(_web_attack_mitigation),
practice_advanced_config(parsed_appsec_spec)
{}
practice_advanced_config(_practice_advanced_config)
{}
void save(cereal::JSONOutputArchive &out_ar) const;
@@ -291,7 +372,7 @@ public:
AppSecRulebase(
std::vector<WebAppSection> _webApplicationPractices,
std::vector<WebAPISection> _webAPIPractices)
:
:
webApplicationPractices(_webApplicationPractices),
webAPIPractices(_webAPIPractices) {}
@@ -302,11 +383,12 @@ private:
std::vector<WebAPISection> webAPIPractices;
};
class AppSecWrapper
{
public:
AppSecWrapper(const AppSecRulebase &_app_sec)
:
:
app_sec_rulebase(_app_sec)
{}
@@ -328,6 +410,9 @@ public:
const std::vector<std::string> & getPractices() const;
const std::string & getHost() const;
const std::string & getMode() const;
const std::string &rpmGetUpstream() const;
const std::string &rpmGetRPSettings() const;
bool rpmIsHttps() const;
void setHost(const std::string &_host);
void setMode(const std::string &_mode);
const std::string & getCustomResponse() const;
@@ -343,6 +428,9 @@ private:
std::string custom_response;
std::string source_identifiers;
std::string trusted_sources;
std::string rpm_upstream;
std::string rpm_settings;
bool rpm_is_ssl = false;
};
class AppsecPolicySpec : Singleton::Consume<I_Environment>
@@ -369,10 +457,10 @@ public:
const std::vector<AppSecPracticeSpec> &_practices,
const std::vector<AppsecTriggerSpec> &_log_triggers,
const std::vector<AppSecCustomResponseSpec> &_custom_responses,
const std::vector<AppsecExceptionSpec> &_exceptions,
const std::vector<AppsecException> &_exceptions,
const std::vector<TrustedSourcesSpec> &_trusted_sources,
const std::vector<SourceIdentifierSpecWrapper> &_sources_identifiers)
:
:
policies(_policies),
practices(_practices),
log_triggers(_log_triggers),
@@ -387,9 +475,10 @@ public:
const std::vector<AppSecPracticeSpec> & getAppSecPracticeSpecs() const;
const std::vector<AppsecTriggerSpec> & getAppsecTriggerSpecs() const;
const std::vector<AppSecCustomResponseSpec> & getAppSecCustomResponseSpecs() const;
const std::vector<AppsecExceptionSpec> & getAppsecExceptionSpecs() const;
const std::vector<AppsecException> & getAppsecExceptions() const;
const std::vector<TrustedSourcesSpec> & getAppsecTrustedSourceSpecs() const;
const std::vector<SourceIdentifierSpecWrapper> & getAppsecSourceIdentifierSpecs() const;
const std::vector<RPMSettings> &rpmGetRPSettings() const;
void addSpecificRule(const ParsedRule &_rule);
private:
@@ -397,9 +486,10 @@ private:
std::vector<AppSecPracticeSpec> practices;
std::vector<AppsecTriggerSpec> log_triggers;
std::vector<AppSecCustomResponseSpec> custom_responses;
std::vector<AppsecExceptionSpec> exceptions;
std::vector<AppsecException> exceptions;
std::vector<TrustedSourcesSpec> trusted_sources;
std::vector<SourceIdentifierSpecWrapper> sources_identifiers;
std::vector<RPMSettings> rpm_settings;
};
#endif // __APPSEC_PRACTICE_SECTION_H__

View File

@@ -0,0 +1,41 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __CONFIGMAPS_H__
#define __CONFIGMAPS_H__
#include <vector>
#include <map>
#include "config.h"
#include "debug.h"
#include "rest.h"
#include "cereal/archives/json.hpp"
#include <cereal/types/map.hpp>
#include "customized_cereal_map.h"
#include "local_policy_common.h"
class ConfigMaps : public ClientRest
{
public:
bool loadJson(const std::string &json);
std::string getFileContent() const;
std::string getFileName() const;
private:
std::map<std::string, std::string> data;
};
#endif // __CONFIGMAPS_H__

View File

@@ -24,13 +24,13 @@
#include "debug.h"
#include "rest.h"
#include "local_policy_common.h"
#include "new_exceptions.h"
class AppsecExceptionSpec
{
public:
void load(cereal::JSONInputArchive &archive_in);
const std::string & getName() const;
const std::string & getAction() const;
const std::vector<std::string> & getCountryCode() const;
const std::vector<std::string> & getCountryName() const;
@@ -41,10 +41,10 @@ public:
const std::vector<std::string> & getSourceIdentifier() const;
const std::vector<std::string> & getSourceIp() const;
const std::vector<std::string> & getUrl() const;
void setName(const std::string &_name);
bool isOneCondition() const;
private:
std::string name;
int conditions_number;
std::string action;
std::vector<std::string> country_code;
std::vector<std::string> country_name;
@@ -57,20 +57,42 @@ private:
std::vector<std::string> url;
};
class AppsecException
{
public:
AppsecException() {};
// LCOV_EXCL_START Reason: no test exist
AppsecException(const std::string &_name, const std::vector<AppsecExceptionSpec> &_exception_spec)
:
name(_name),
exception_spec(_exception_spec) {};
// LCOV_EXCL_STOP
void load(cereal::JSONInputArchive &archive_in);
const std::string & getName() const;
const std::vector<AppsecExceptionSpec> & getExceptions() const;
void setName(const std::string &_name);
private:
std::string name;
std::vector<AppsecExceptionSpec> exception_spec;
};
class ExceptionMatch
{
public:
ExceptionMatch() {}
ExceptionMatch(const AppsecExceptionSpec &parsed_exception);
ExceptionMatch(const std::string &_key, const std::vector<std::string> &_value)
:
match_type(MatchType::Condition),
key(_key),
op("in"),
value(_value)
{}
ExceptionMatch(const std::string &_key, const std::vector<std::string> &_value);
ExceptionMatch(const NewAppsecException &parsed_exception);
void save(cereal::JSONOutputArchive &out_ar) const;
const std::string & getOperator() const;
const std::string & getKey() const;
const std::string & getValue() const;
const std::vector<ExceptionMatch> & getMatch() const;
private:
MatchType match_type;
@@ -84,13 +106,12 @@ class ExceptionBehavior
{
public:
ExceptionBehavior() {}
ExceptionBehavior(
const std::string &_key,
const std::string &_value
);
ExceptionBehavior(const std::string &_value);
void save(cereal::JSONOutputArchive &out_ar) const;
const std::string getBehaviorId() const;
const std::string & getBehaviorId() const;
const std::string & getBehaviorKey() const;
const std::string & getBehaviorValue() const;
private:
std::string key;
@@ -102,15 +123,13 @@ class InnerException
{
public:
InnerException() {}
InnerException(
ExceptionBehavior _behavior,
ExceptionMatch _match)
:
behavior(_behavior),
match(_match) {}
InnerException(ExceptionBehavior _behavior, ExceptionMatch _match);
void save(cereal::JSONOutputArchive &out_ar) const;
const std::string getBehaviorId() const;
const std::string & getBehaviorId() const;
const std::string & getBehaviorKey() const;
const std::string & getBehaviorValue() const;
const ExceptionMatch & getMatch() const;
private:
ExceptionBehavior behavior;

Some files were not shown because too many files have changed in this diff Show More