Logic Rules (OPA)
You can integrate Code Security with the Open Policy Agent (OPA) project such that it can use its logic facilities.
Rego in Code Security
A generic schema of a Code Security-compatible Rego policy:
package opa_rule
Policy[result] {
< LOGIC >
result := {
"id": "CR-AF001",
# search expression to detect line numbers when needed
# "keysearch": "",
"severity": "WARNING",
"text": "Airflow encryption scheme should be more strict",
# just a reference URL for playbooks, and additional information
"url": "https://example.com"
}
}
Best practice for building detectors based on Rego:Principles:
-
Every policy returns a result.
-
Every result has a clear and strict schema, which Code Security requires to create a finding.
-
Multiple policies can co-exist in the same rule, as long as each of those have a different ID.
|
Notes:
|
Building a Custom Code Security Detector with OPA
Code Security supports two different match types:
-
opa_inline - pointing
to a rego rule inlined inside the yaml, in the pattern field. You must specify parser withparams.parser
. -
opa_file - pointing
to a physical file on disk. pattern spec isparser:namespace:file-relative-to-spectral.yaml
.
Example:
rules:
- id: AF001
tags:
- base # activate by default, part of the base package
applies_to:
- ".*\\.conf$"
severity: info
pattern_group:
aggregate: or
scope: text
patterns:
# remember: rego file must declare package 'opa_rule'
# <parser>:<policy name>:<path to rego file>
- pattern: "ini:airflow-main-configuration:./af.rego"
pattern_type: opa_file
test_regex_prematch:
# this detects that the configuration file is *actually* Airflow related
- pattern: "airflow_"
- id: AF002
tags:
- base # activate by default, part of the base package
applies_to:
- ".*\\.conf$"
severity: info
pattern_group:
aggregate: or
scope: text
patterns:
# pattern is the actual rego policy, and we specify a parser in 'params:' later below
- pattern_type: opa_inline
params:
parser: ini
test_regex_prematch:
# this detects that the configuration file is *actually* Airflow related
- pattern: "airflow_"
pattern: >
package opa_rule
Policy[result] {
true # <some logic>
result := {
"id": "AF002",
"severity": "WARNING",
"text": "Airflow encryption seed value should not be visible",
"url": "https://example.com",
}
}
Rule Settings
Code Security's OPA rules are a combination of:
-
Routing - the concept of detecting configuration types and pointing to the correct parser and policy bundle.
-
Logic - Defined through Rego.
-
Rule settings (
rule_settings
) - Overlay of settings to allow for user customization.
Rule setting example:
RuleSettings{
shared: json_value
rules: json_value
}
Corresponding yaml file example:
rule_settings:
shared:
whitelist_email: ".*"
rules:
CR010:
min_committers: 3
Usage in rules is optional and depends on your requirement to customize settings for your rules. If you want to use rules, then we recommend this pragma to set up rule settings inside the Rego policy:
package opa_rule
_s := object.get(input, "__rule_settings__", {})
rules := object.get(_s, "rules", {})
shared := object.get(_s, "shared", {})
Policy[result] {
rule_id := "ELA001"
settings = object.get(rules, rule_id, {})
port := object.get(settings, "port", 9200)
not input.play.server.http.port = port
result := {
"id": rule_id,
"severity": "WARNING",
"text": "Elastic should always be on port 9200",
"url": "https://example.com",
}
}
To override the port value to a different value, use this rule settings in spectral.yaml
:
rule_settings:
rules:
ELA001:
port: 20200
Keysearch
Use keysearch for configuration that are unpredictable in its shape to find a line number.
No capture
"keysearch": "some-string-to-find"
Capture
Typically used with multi-line. Enable multiline with (?s)
flag.
"keysearch": "(?s)foo.*bar(capture-this = .*?)andthat"