mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-23 07:29:00 -08:00
228 lines
12 KiB
Markdown
228 lines
12 KiB
Markdown
# Custom Checks
|
|
|
|
## Overview
|
|
You can write custom checks in [Rego][rego].
|
|
Once you finish writing custom checks, you can pass the check files or the directory where those checks are stored with --config-check` option.
|
|
|
|
``` bash
|
|
trivy config --config-check /path/to/policy.rego --config-check /path/to/custom_checks --namespaces user /path/to/config_dir
|
|
```
|
|
|
|
As for `--namespaces` option, the detail is described as below.
|
|
|
|
### File formats
|
|
If a file name matches the following file patterns, Trivy will parse the file and pass it as input to your Rego policy.
|
|
|
|
| File format | File pattern |
|
|
|---------------|-----------------------------------------------------------|
|
|
| JSON | `*.json` |
|
|
| YAML | `*.yaml` and `*.yml` |
|
|
| Dockerfile | `Dockerfile`, `Dockerfile.*`, and `*.Dockerfile` |
|
|
| Containerfile | `Containerfile`, `Containerfile.*`, and `*.Containerfile` |
|
|
| Terraform | `*.tf` and `*.tf.json` |
|
|
|
|
### Configuration languages
|
|
In the above general file formats, Trivy automatically identifies the following types of configuration files:
|
|
|
|
- CloudFormation (JSON/YAML)
|
|
- Kubernetes (JSON/YAML)
|
|
- Helm (YAML)
|
|
- Terraform Plan (JSON/Snapshot)
|
|
|
|
This is useful for filtering inputs, as described below.
|
|
|
|
## Rego format
|
|
A single package must contain only one policy.
|
|
|
|
!!!example
|
|
``` rego
|
|
# METADATA
|
|
# title: Deployment not allowed
|
|
# description: Deployments are not allowed because of some reasons.
|
|
# schemas:
|
|
# - input: schema["kubernetes"]
|
|
# custom:
|
|
# id: ID001
|
|
# severity: LOW
|
|
# input:
|
|
# selector:
|
|
# - type: kubernetes
|
|
package user.kubernetes.ID001
|
|
|
|
deny[res] {
|
|
input.kind == "Deployment"
|
|
msg := sprintf("Found deployment '%s' but deployments are not allowed", [input.metadata.name])
|
|
res := result.new(msg, input.kind)
|
|
}
|
|
```
|
|
|
|
In this example, ID001 "Deployment not allowed" is defined under `user.kubernetes.ID001`.
|
|
If you add a new custom policy, it must be defined under a new package like `user.kubernetes.ID002`.
|
|
|
|
### Policy structure
|
|
|
|
`# METADATA` (optional unless the check will be contributed into Trivy)
|
|
: - SHOULD be defined for clarity since these values will be displayed in the scan results
|
|
- `custom.input` SHOULD be set to indicate the input type the policy should be applied to. See [list of available types][source-types]
|
|
|
|
`package` (required)
|
|
: - MUST follow the Rego's [specification][package]
|
|
- MUST be unique per policy
|
|
- SHOULD include policy id for uniqueness
|
|
- MAY include the group name such as `kubernetes` for clarity
|
|
- Group name has no effect on policy evaluation
|
|
|
|
`deny` (required)
|
|
: - SHOULD be `deny` or start with `deny_`
|
|
- Although `warn`, `warn_*`, `violation`, `violation_` also work for compatibility, `deny` is recommended as severity can be defined in `__rego_metadata__`.
|
|
- SHOULD return ONE OF:
|
|
- The result of a call to `result.new(msg, cause)`. The `msg` is a `string` describing the issue occurrence, and the `cause` is the property/object where the issue occurred. Providing this allows Trivy to ascertain line numbers and highlight code in the output.
|
|
- A `string` denoting the detected issue
|
|
- Although `object` with `msg` field is accepted, other fields are dropped and `string` is recommended if `result.new()` is not utilised.
|
|
- e.g. `{"msg": "deny message", "details": "something"}`
|
|
|
|
### Package
|
|
A package name must be unique per policy.
|
|
|
|
!!!example
|
|
``` rego
|
|
package user.kubernetes.ID001
|
|
```
|
|
|
|
By default, only `builtin.*` packages will be evaluated.
|
|
If you define custom packages, you have to specify the package prefix via `--namespaces` option. By default, Trivy only runs in its own namespace, unless specified by the user. Note that the custom namespace does not have to be `user` as in this example. It could be anything user-defined.
|
|
|
|
``` bash
|
|
trivy config --config-check /path/to/custom_checks --namespaces user /path/to/config_dir
|
|
```
|
|
|
|
In this case, `user.*` will be evaluated.
|
|
Any package prefixes such as `main` and `user` are allowed.
|
|
|
|
### Metadata
|
|
|
|
The check must contain a [Rego Metadata](https://www.openpolicyagent.org/docs/latest/policy-language/#metadata) section. Trivy uses standard rego metadata to define the new policy and general information about it.
|
|
|
|
Trivy supports extra fields in the `custom` section as described below.
|
|
|
|
!!!example
|
|
``` rego
|
|
# METADATA
|
|
# title: Deployment not allowed
|
|
# description: Deployments are not allowed because of some reasons.
|
|
# custom:
|
|
# id: ID001
|
|
# severity: LOW
|
|
# input:
|
|
# selector:
|
|
# - type: kubernetes
|
|
```
|
|
|
|
If you are creating checks for your Trivy misconfiguration scans, some fields are optional as referenced in the table below. The `schemas` field should be used to enable policy validation using a built-in schema. It is recommended to use this to ensure your checks are
|
|
correct and do not reference incorrect properties/values.
|
|
|
|
| Field name | Allowed values | Default value | In table | In JSON |
|
|
|------------------------------|----------------------------------------------------------------------------------------------|:----------------------------:|:--------:|:-------:|
|
|
| title | Any characters | N/A | ✅ | ✅ |
|
|
| description | Any characters | | - | ✅ |
|
|
| schemas.input | `schema["kubernetes"]`, `schema["dockerfile"]`, `schema["cloud"]`, `schema["terraform-raw"]` | (applied to all input types) | - | - |
|
|
| custom.id | Any characters | N/A | ✅ | ✅ |
|
|
| custom.severity | `LOW`, `MEDIUM`, `HIGH`, `CRITICAL` | UNKNOWN | ✅ | ✅ |
|
|
| custom.recommended_actions | Any characters | | - | ✅ |
|
|
| custom.deprecated | `true`, `false` | `false` | - | ✅ |
|
|
| custom.input.selector.type | Any item(s) in [this list][source-types] | | - | ✅ |
|
|
| custom.minimum_trivy_version | The minimum version of Trivy that's required to evaluate this check | | - | ✅ |
|
|
| url | Any characters | | - | ✅ |
|
|
|
|
#### custom.avd_id and custom.id
|
|
|
|
The AVD_ID can be used to link the check to the Aqua Vulnerability Database (AVD) entry. For example, the `avd_id` `AVD-AWS-0176` is the ID of the check in the [AWS Vulnerability Database](https://avd.aquasec.com/). If you are [contributing your check to trivy-checks](../../../../community/contribute/checks/overview.md), you need to generate an ID using `make id` in the [trivy-checks](https://github.com/aquasecurity/trivy-checks) repository. The output of the command will provide you the next free IDs for the different providers in Trivy.
|
|
|
|
The ID is based on the AVD_ID. For instance if the `avd_id` is `AVD-AWS-0176`, the ID is `ID0176`.
|
|
|
|
#### custom.provider
|
|
|
|
The `provider` field references the [provider](https://github.com/aquasecurity/trivy/tree/main/pkg/iac/providers) available in Trivy. This should be the same as the provider name in the `pkg/iac/providers` directory, e.g. `aws`.
|
|
|
|
#### custom.service
|
|
|
|
Services are defined within a provider. For instance, RDS is a service and AWS is a provider. This should be the same as the service name in one of the provider directories. ([Link](https://github.com/aquasecurity/trivy/tree/main/pkg/iac/providers)), e.g. `aws/rds`.
|
|
|
|
#### custom.input
|
|
|
|
The `input` tells Trivy what inputs this check should be applied to. Cloud provider checks should always use the `selector` input, and should always use the `type` selector with `cloud`. Check targeting Kubernetes yaml can use `kubernetes`, RBAC can use `rbac`, and so on.
|
|
|
|
#### Subtypes in the custom data
|
|
|
|
Subtypes currently only need to be defined for cloud providers [as detailed in the documentation.](./selectors.md/#enabling-selectors-and-subtypes)
|
|
|
|
#### Scan Result
|
|
|
|
Some fields are displayed in scan results.
|
|
|
|
``` bash
|
|
k.yaml (kubernetes)
|
|
───────────────────
|
|
|
|
Tests: 32 (SUCCESSES: 31, FAILURES: 1)
|
|
Failures: 1 (UNKNOWN: 0, LOW: 1, MEDIUM: 0, HIGH: 0, CRITICAL: 0)
|
|
|
|
LOW: Found deployment 'my-deployment' but deployments are not allowed
|
|
════════════════════════════════════════════════════════════════════════
|
|
Deployments are not allowed because of some reasons.
|
|
────────────────────────────────────────────────────────────────────────
|
|
k.yaml:1-2
|
|
────────────────────────────────────────────────────────────────────────
|
|
1 ┌ apiVersion: v1
|
|
2 └ kind: Deployment
|
|
────────────────────────────────────────────────────────────────────────
|
|
```
|
|
|
|
### Input
|
|
You can specify input format via the `custom.input` annotation.
|
|
|
|
!!!example
|
|
``` rego
|
|
# METADATA
|
|
# custom:
|
|
# input:
|
|
# combine: false
|
|
# selector:
|
|
# - type: kubernetes
|
|
```
|
|
|
|
`combine` (boolean)
|
|
: The details are [here](combine.md).
|
|
|
|
`selector` (array)
|
|
: This option filters the input by file format or configuration language.
|
|
In the above example, Trivy passes only Kubernetes files to this policy.
|
|
Even if a Dockerfile exists in the specified directory, it will not be passed to the policy as input.
|
|
|
|
Possible values for input types are:
|
|
|
|
- `dockerfile` (Dockerfile)
|
|
- `kubernetes` (Kubernetes YAML/JSON)
|
|
- `rbac` (Kubernetes RBAC YAML/JSON)
|
|
- `cloud` (Cloud format, as defined by Trivy - this is used for Terraform, CloudFormation, and Cloud/AWS scanning)
|
|
- `yaml` (Generic YAML)
|
|
- `json` (Generic JSON)
|
|
- `toml` (Generic TOML)
|
|
- `terraform-raw` (Terraform configuration is not converted to common state as for the Cloud format, allowing for more flexible and direct checks on the original code)
|
|
|
|
When configuration languages such as Kubernetes are not identified, file formats such as JSON will be used as `type`.
|
|
When a configuration language is identified, it will overwrite `type`.
|
|
|
|
!!! example
|
|
`pod.yaml` including Kubernetes Pod will be handled as `kubernetes`, not `yaml`.
|
|
`type` is overwritten by `kubernetes` from `yaml`.
|
|
|
|
`type` accepts `kubernetes`, `dockerfile`, `cloudformation`, `terraform`, `terraformplan`, `json`, or `yaml`.
|
|
|
|
### Schemas
|
|
See [here](schema.md) for the detail.
|
|
|
|
[rego]: https://www.openpolicyagent.org/docs/latest/policy-language/
|
|
[package]: https://www.openpolicyagent.org/docs/latest/policy-language/#packages
|
|
[source-types]: https://github.com/aquasecurity/trivy/blob/e4af279b29ed5b77ed1d62e31b232b1f9b92ef4f/pkg/iac/types/sources.go#L5-L17
|