# Configuration Using CRDs

{% hint style="warning" %}
The CRDs explained below are based on the openappsec.io CRD schema **v1beta1**.\
The latest available, significantly enhanced openappsec.io CRD schema is **v1beta2**,\
documentation for **v1beta2** is available here: [configuration-using-crds-v1beta2](https://docs.openappsec.io/getting-started/start-with-kubernetes/configuration-using-crds-v1beta2 "mention")
{% endhint %}

You can create your own policies and apply them for either all or specific ingress rules, set exceptions and other advanced options using K8S native declarative configuration.

## Using open-appsec K8S Custom Resources

open-appsec configuration is done using [Kubernetes Custom Resource Definition](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) (CRD). Custom Resources are extensions of the Kubernetes API that allow powerful yet standard way of managing policies in a declarative way as well as using infrastructure-as-code paradigm. This support is an important goal of managing changes as part of your CI/CD processes.&#x20;

open-appsec provides seven CRDs. The main one is `policy` - which defines default behaviors that will apply to all Ingress rules and also behaviours that you wish to apply just to specific rules. The `policy` resource refers to all other CRDs.

The Kubernetes API serves and handles the storage of custom resources. They can be accessed and managed using standard tools: kubectl, a REST client that you write, Go and Python [client libraries](https://kubernetes.io/docs/reference/using-api/client-libraries/) and more.

For example, to see available policies:

```bash
$ kubectl get policy.openappsec.io
NAME                                       AGE
open-appsec-best-practice-policy           90m
```

To see e.g. the open-appsec-best-practice-policy-detect resource run:

```yaml
$ kubectl get policy.openappsec.io open-appsec-best-practice-policy -o yaml

apiVersion: openappsec.io/v1beta1
kind: Policy
metadata:
  name: open-appsec-best-practice-policy
spec:
  default:
    custom-response: 403-forbidden
    exceptions: []
    mode: detect-learn
    practices:
    - appsec-best-practice
    triggers:
    - appsec-log-trigger
```

In case you want to edit one of your own policies, e.g. your own default-policy you can do this with the following command (see further below for an example to create your own custom policy resource):&#x20;

```
kubectl edit policy.openappsec.io/open-appsec-best-practice-policy
```

## Activating open-appsec

In order to activate open-appsec, add the `policy` resource name (e.g. open-appsec-best-practice-policy) to your Ingress resource. \
\
For example:

```yaml
...
annotations:
  openappsec.io/policy: open-appsec-best-practice-policy
...
```

<details>

<summary>Ingress resource example</summary>

```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    openappsec.io/policy: open-appsec-best-practice-policy-detect
    # openappsec.io/policy: open-appsec-best-practice-policy-prevent
  name: ingress-wildcard-host
spec:
  rules:
  - host: "foo.bar.com"
    http:
      paths:
      - pathType: Prefix
        path: "/bar"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: "*.foo.com"
    http:
      paths:
      - pathType: Prefix
        path: "/foo"
        backend:
          service:
            name: service2
            port:
                number: 80
```

</details>

{% hint style="info" %}
The open-appsec-best-practice-policy will by default:

* Inspect traffic to all ingress rules (paths) and learn it
* Detect  suspicious requests in confidence high or critical
* In case of the prevent policy send an HTTP Error Code 403 Forbidden to the client that sent the bad request
* Log to stdout (so you can use fluentd/fluentbit) to send logs to ELK or other collector.
  {% endhint %}

You can define your own policy and change relevant parameters as explained in the next section.

## Custom Resources Specifications

### Policy&#x20;

Policy resource defines default behaviors that will apply to all Ingress rules and optional policies that you wish to apply just to specific rules.&#x20;

<details>

<summary> Example</summary>

```yaml
apiVersion: openappsec.io/v1beta1
kind: Policy
metadata:
  name: open-appsec-best-practice-policy
spec:
  default:
    triggers:
    - appsec-special-log-trigger
    mode: detect-learn
    practices:
    - webapp-best-practice
    source-identifiers: appsec-source-identifiers-sourceip-example
    trusted-sources: appsec-trusted-source-example
    custom-response: appsec-web-user-response-example
    exceptions:
    - appsec-exception-example
  specific-rules:
  - host: web.server.com/example
    triggers:
    - appsec-special-log-trigger
    mode: prevent-learn
    practices:
    - webapp-best-practice
    source-identifiers: appsec-source-identifiers-sourceip-example
    trusted-sources: appsec-trusted-source-example
    custom-response: appsec-web-user-response-example
    exceptions:
    - appsec-exception-example
  - host: web.server.com/another-example
    triggers:
    - appsec-special-log-trigger
    mode: prevent-learn
    practices:
    - webapp-best-practice
    source-identifiers: appsec-source-identifiers-sourceip-example
    trusted-sources: appsec-trusted-source-example
    custom-response: appsec-web-user-response-example
    exceptions:
    - appsec-exception-example

```

</details>

<details>

<summary>Specification</summary>

**default**

* **mode** *string enum* - security engines operation mode. Blocking will only happen in prevent-learn mode
  * prevent-learn / detect-learn / prevent / detect / inactive\
    (note that prevent and detect are just aliases for prevent-learn and detect-learn)
* **practices** *array of strings* - defines which security engines to activate and their specific settings (Note there cannot be multiple practices of the same kind specified here!)
  * reference to Practice resource(s)
* **triggers** *array of strings* - defines logging verbosity and destination (stdout, syslog, cloud, etc) (Note for now only a single trigger is supported!)
  * reference to LogTrigger resource(s)
* **custom-response** *string* - defines prevent mode behaviors upon decision to block: HTTP response code, block page, http redirect
  * reference to CustomResponse resource
* **source-identifiers** *string* - defines how ML engine will  distinguish between sources based on IP address, X-Foward-For, Key in Header/Cookie/JWT
  * reference to SourcesIdentifier resource
* **trusted-sources** *string -* defines which traffic sources are very unlikely to be malicious. Used for Machine Learning engine.
* **exceptions** *arrays of strings* - defines exceptions to be applied based on e.g. countryCode, countryName, sourceIP, URL, hostName, sourceIdentifier
  * reference to Exception resource(s)

**specific-rules** list\
list of one or more per-host (ingress rule) policies that will override the defaults above

* **host** *string -* policy will apply to this host
  * network path (exactly as appear in ingress rules)
* *All other keys can be used same as decribed above for default.*

</details>

{% hint style="warning" %}
When configuring specific rules in the open-appsec policy for APISIX and Kong on Kubernetes, make sure to also specific the correct default ports on which the APISIX and Kong containers receive traffic, as they deviate from the usual ports 80 and 443:\
\
APISIX:   HTTP: 9080, HTTPS: 9443

Kong:   HTTP: 8000, HTTPS: 8443
{% endhint %}

### Practice

Practice resources define which security engine will be active and their settings.&#x20;

<details>

<summary>Example </summary>

```yaml
apiVersion: openappsec.io/v1beta1
kind: Practice
metadata:
  name: webapp-best-practice
spec:
  openapi-schema-validation:
    configmap: []
    override-mode: 'prevent'
  snort-signatures:
    configmap: []
    override-mode: 'prevent'
  web-attacks:
    max-body-size-kb: 1222
    max-header-size-bytes: 44343
    max-object-depth: 2111
    max-url-size-bytes: 34434
    minimum-confidence: high
    override-mode: 'prevent'
    protections:
      csrf-enabled: prevent
      error-disclosure-enabled: prevent
      non-valid-http-methods: true
      open-redirect-enabled: prevent
  anti-bot:
    injected-URIs: []
    validated-URIs: []
    override-mode: 'prevent'
```

</details>

<details>

<summary>Specification</summary>

* **web-attacks - open-appsec ML engine settings**
  * **override-mode** *string enum* - allows overriding the mode defined at the Policy level for this specific engine
    * prevent-learn / detect-learn / prevent / detect / inactive
  * **minimum-confidence** *string* *enum, default: high* - defines which security engines to activate and their specific settings
    * medium / high / critical
  * **max-url-size-bytes** *integer,* default: 32768
  * **max-object-depth** *integer,* default: 40
  * **max-body-size-kb** *integer,* default: 102400
  * **max-header-size-bytes** *integer,* default: 32768
  * **protections** *- settings for various advanced protections:*
    * **csrf-enabled** *string, default: inactive -* Cross Site Request Forgery protection
      * prevent-learn / detect-learn / prevent / detect / inactive
    * **error-disclosure-enabled** *string, default: inactive -* Prevent disclosure of technical information to the attacker in server error messages
      * prevent-learn / detect-learn / prevent / detect / inactive
    * **open-redirect-enabled** *string, default: inactive* - Protect against URL redirection to untrusted sites
      * prevent-learn / detect-learn / prevent / detect / inactive
    * **non-valid-http-methods** *boolean, default: false* - Prevent attacker from sending requests with unsafe HTTP methods
      * true / false
* **open-api-schema-validation (currently not supported yet, will be added soon)**
  * **configmap** *array of strings* - specify configmap(s) containing the OpenAPI schema definitions
  * **override-mode** *enum* - allows overriding the mode defined at the Policy level for this specific engine
    * prevent-learn / detect-learn / prevent / detect / inactive
* **anti-bot**
  * **override-mode** *enum* - allows overriding the mode defined at the Policy level for this specific engine
    * prevent-learn / detect-learn / prevent / detect / inactive
  * **injected-URIs** *array of strings* - Provide URL(s) where Anti-Bot check is injected with GET request
  * **validated-URIs** *array of strings -* Provide URL(s) where result of Anti-Bot check is received from with POST request
* **snort-signatures (currently not supported yet, will be added soon)**
  * **override-mode** *enum* - allows overriding the mode defined at the Policy level for this specific engine
    * prevent-learn / detect-learn / prevent / detect / inactive
  * **configmap** *array of strings* - specify configmap(s) containing snort signatures

</details>

### Custom Response

Practice resources define which security engine will be active and their settings.&#x20;

<details>

<summary>Examples </summary>

```yaml
apiVersion: openappsec.io/v1beta1
kind: CustomResponse
metadata:
  name: appsec-web-user-response-example
spec:
  mode: block-page
  http-response-code: 403
  message-title: Block page title
  message-body: "<h1>Access blocked by open-appsec.</h1><p>Your access will be logged.</p>"

apiVersion: openappsec.io/v1beta1
kind: CustomResponse
metadata:
  name: appsec-default-web-user-response
spec:
  mode: response-code-only
  http-response-code: 403
```

</details>

<details>

<summary>Specification</summary>

* **mode** *enum -* engine will take one of these actions upon decision to block request
  * block-page - send HTML with text to client + HTTP response code
  * response-code-only - send only response code
* **message-title** *string* - title of block page that will be displayed only in case mode is block page and engine decided to block
* **message-body** *string* - content of block page that will be displayed only in case mode is block page and engine decided to block
* **http-response-code** *integer between 100-599* - http code that will be returned to client upon engine decision to block; default is 403 - HTTP Forbidden

</details>

### Log Trigger

<details>

<summary>Example </summary>

```yaml
apiVersion: openappsec.io/v1beta1
kind: LogTrigger
metadata:
  name: appsec-special-log-trigger
spec:
  access-control-logging:
    allow-events: false
    drop-events: true
  additional-suspicious-events-logging:
    enabled: true
    minimum-severity: high
    response-body: false
  appsec-logging:
    all-web-requests: false
    detect-events: false
    prevent-events: true
  extended-logging:
    http-headers: false
    request-body: false
    url-path: false
    url-query: false
  log-destination:
    cloud: false
    file: "/a/b/c"
    stdout:
      format: json
    syslog-service:
    - address: 1.2.3.4
      port: 514
    cef-service:
    - address: 5.6.7.8
      port: 514
      proto: tcp
```

</details>

<details>

<summary>Specification</summary>

* **access-control-logging** - configure logging for Access Control events
  * **allow-events** *boolean, default: false* - log access control allow eve*nts*
    * true / false
  * **drop-events** *boolean, default: true* - log access control drop event*s*
    * true / false
* **additional-suspicious-events-logging** configure additional logging for suspicious events based on a selectable minimum severity-level
  * **enabled** *boolean default: true* - enable/disable additional suspicious events logging
    * true / false
  * **minimum-severity** *string enum, default: high* - select minimum severity level
    * high / critical
* **appsec-logging** configure logging for open-appsec events (threat prevention, machine learning)
  * **detect-events** *boolean, default: true* - log detected events
    * true / false
  * **prevent-events** *boolean, default: true* - log prevented events
    * true / false
  * **all-web-requests** *boolean, default: false* - log all web requests (has performance impact!)
    * true / false
  * **extended-logging**
    * **url-path** *boolean, default: true* - log URL path
      * true / false
    * **url-query** *boolean, default: true* - log URL query
      * true / false
    * **http-headers** *boolean, default: false* - log the HTTP headers (has performance impact!)
      * true / false
    * **request-body** *boolean, default: false* - log the request body (has performance impact)
      * true / false
* **log-destination**
  * **cloud** *boolean, default: false* - enable or disable logging to the appsec-open Cloud Service (relevant when being connected to SaaS Mgmt WebUI)
    * true / false
  * **file** *string* - define file path to save logs to (local path from root directory of the open-appsec container, could also refer to a mountPath for a mounted Persistent Volume in the container)
  * **stdout** - configure logging to standard-out
    * **format** *string enum* - define the desired log format
      * json / json-formatted - select between formatted or standard json
  * **syslog-service** *objects array* - define one or more syslog servers and corresponding ports to send logs to
    * **address** *string* - Syslog server IP address
    * **port** *integer* - Syslog server port
  * **cef-service** - allows sending files to a log destination in CEF format
    * **address** *string -* CEF server IP address
    * **port** *integer -* CEF server port
    * **proto** *string enum* Select the correct protocol
      * tcp / udp - Chose TCP or UDP protocol

</details>

### Exceptions

<details>

<summary>Example </summary>

```yaml
apiVersion: openappsec.io/v1beta1
kind: Exception
metadata:
  name: appsec-exception-example
spec:
- action: skip
  comment: This is an example exception comment
  countryCode:
  - CA
  - IL
  countryName:
  - Israel
  - Canada
  hostName:
  - fff
  paramName:
  - key
  paramValue:
  - rrr
  protectionName:
  - cveee
  sourceIdentifier:
  - david
  sourceIp:
  - 1.2.3.4
  - '3.3.3.3'
  url:
  - "/rrr"
- action: accept
  hostName:
  - fff
  url:
  - "/rrr"
- action: drop
  comment: This is an example exception comment
  countryName:
  - Israel
  - Canada
  protectionName:
  - cveee
  sourceIdentifier:
  - david
  sourceIp:
  - 1.2.3.4
  - 2.3.4.5
  url:
  - "/rrr"
- action: suppressLog
  comment: This is an example exception comment
  countryCode:
  - CA
  - IL
  countryName:
  - Israel
  - Canada
  hostName:
  - fff
  url:
  - "/rrr"

```

</details>

<details>

<summary>Specification</summary>

Define a list of actions-objects with the corresponding parameters to match to configure flexible custom exceptions/rules, each having the following configurable keys:

* **action** *string enum* - Action to be performed when exception matches
  * skip / accept / drop / suppressLog
* **sourceIp** *string array* - Source IP(s)&#x20;
* **url** *string array* - URL(s)
* **sourceIdentifier** *string array* - Identified source(s)
* **protectionName** *string arr*ay - Protection(s)
* **paramValue** *string array* - Parameter value(s)
* **paramName** s*tring array* - Parameter name(s)
* **hostName** *string array* - Host name(s)
* **countryCode** *string array* - Country code(s)
* **countryName** *string array* - Country name(s)
* **comment** st*ring* - Comment for the exception

</details>

### Trusted Sources

<details>

<summary>Example </summary>

```yaml
apiVersion: openappsec.io/v1beta1
kind: TrustedSource
metadata:
  name: appsec-trusted-source-example
spec:
  minNumOfSources: 3
  sourcesIdentifiers: [sources-identifiers-1, sources-identifiers-1]
```

</details>

<details>

<summary>Specification</summary>

Define trusted sources by referencing the source identifiers custom resources as well as setting the minimum amount of sources that need to be observed by the behavioural ML engine sending certain identical traffic patterns in order to learn this behaviour as being benign.

* **minNumOfSources** *integer* - Minimum amount of sources having to be observed sending same traffic patterns to learn behaviour as benign.
* **sourcesIdentifiers** *string array* -  Specify one or more source identifiers

</details>

### Source Identifiers

<details>

<summary>Examples </summary>

```yaml
apiVersion: openappsec.io/v1beta1
kind: SourcesIdentifier
metadata:
  name: appsec-source-identifiers-sourceip-example
spec:
  - sourceIdentifier: sourceip

apiVersion: openappsec.io/v1beta1
kind: SourcesIdentifier
metadata:
  name: appsec-source-identifiers-JWTKey-example
spec:
  - sourceIdentifier: JWTKey
    value: userfield

apiVersion: openappsec.io/v1beta1
kind: SourcesIdentifier
metadata:
  name: appsec-source-identifiers-x-forwarded-for-example
spec:
  - sourceIdentifier: x-forwarded-for
    value: [1.2.3.4,5.6.7.8]
```

</details>

<details>

<summary>Specification</summary>

Define list of one or more specific source identifiers that can be used in trusted sources custom resources.

* **sourceIdentifier** *string enum* - Specify the source identifier type of which the content shall be matched
  * headerkey, JWTKey, cookie, sourceip, x-forwarded-for
* **value** *string array* - Content to match the specified sourceIdentifier type
  * For types headerkey, cookie and JWTKey provide the fieldname that designates user&#x20;
  * For type Source IP no value is required
  * For type x-forwarded-for provide previous proxy hops if there are any

</details>
