Providers
Providers are the policy engines which evaluate the input data from the specified domain. Currently supported Providers are:
The provider block of a Lula Validation
is given as follows, where the sample is indicating the OPA provider is in use:
# ... Rest of Lula Validation
provider:
type: opa # opa or kyverno accepted
opa-spec:
# ... Rest of opa-spec
# ... Rest of Lula Validation
Each domain specification retreives a specific dataset, and each will return that data to the selected Provider
in a domain-specific format. However, this data will always take the form of a JSON object when input to a Provider
. For that reason, it is important that Domain
and Provider
specifications are not built wholly independently in a given Validation.
1 -
Kyverno Provider
The Kyverno provider provides Lula with the capability to evaluate the domain
in against a Kyverno policy.
Payload Expectation
The validation performed should use the form of provider with the type
of kyverno
and using the kyverno-spec
, along with a valid domain.
Example:
domain:
type: kubernetes
kubernetes-spec:
resources:
- name: podsvt
resource-rule:
group:
version: v1
resource: pods
namespaces: [validation-test]
provider:
type: kyverno
kyverno-spec:
policy:
apiVersion: json.kyverno.io/v1alpha1 # Required
kind: ValidatingPolicy # Required
metadata:
name: pod-policy # Required
spec:
rules:
- name: no-latest # Required
# Match payloads corresponding to pods
match: # Optional
any: # Assertion Tree
- apiVersion: v1
kind: Pod
assert: # Required
all: # Assertion Tree
- message: Pod `{{ metadata.name }}` uses an image with tag `latest`
check:
~.podsvt:
spec:
# Iterate over pod containers
# Note the `~.` modifier, it means we want to iterate over array elements in descendants
~.containers:
image:
# Check that an image tag is present
(contains(@, ':')): true
# Check that the image tag is not `:latest`
(ends_with(@, ':latest')): false
You can have mutiple policies defined. Optionally, output.validation
can be specified in the kyverno-spec
to control which (Policy, Rule) pair control validation allowance/denial, which is in the structure of a comma separated list of rules: policy-name1.rule-name-1,policy-name-1.rule-name-2
. If you have a desired observation to include, output.observations
can be added to payload to observe violations by a certain (Policy, Rule) pair such as:
domain:
type: kubernetes
kubernetes-spec:
resources:
- name: podsvt
resource-rule:
group:
version: v1
resource: pods
namespaces: [validation-test]
provider:
type: kyverno
kyverno-spec:
policy:
apiVersion: json.kyverno.io/v1alpha1
kind: ValidatingPolicy
metadata:
name: labels
spec:
rules:
- name: foo-label-exists
assert:
all:
- check:
~.podsvt:
metadata:
labels:
foo: bar
output:
validation: labels.foo-label-exists
observations:
- labels.foo-label-exists
The validatation
and observations
fields must specify a (Policy, Rule) pair. These observations will be printed out in the remarks
section of relevant-evidence
in the assessment results.
2 -
OPA Provider
The OPA provider provides Lula with the capability to evaluate the domain
against a rego policy.
Payload Expectation
The validation performed should use the form of provider with the type
of opa
and using the opa-spec
, along with a valid domain.
Example:
domain:
type: kubernetes
kubernetes-spec:
resources:
- name: podsvt
resource-rule:
group:
version: v1
resource: pods
namespaces: [validation-test]
provider:
type: opa
opa-spec:
rego: | # Required - Rego policy used for data validation
package validate # Required - Package name
import future.keywords.every # Optional - Any imported keywords
validate { # Required - Rule Name for evaluation - "validate" is the only supported rule
every pod in input.podsvt {
podLabel == "bar"
}
}
Optionally, an output
can be specified in the opa-spec
. Currently, the default validation allowance/denial is given by validate.validate
, which is really of the structure <package-name>.<json-path-to-boolean-variable>
. If you have a desired alternative validation boolean variable, as well as additional observations to include, an output can be added such as:
domain:
type: kubernetes
kubernetes-spec:
resource-rules:
- group:
version: v1
resource: pods
namespaces: [validation-test]
provider:
type: opa
opa-spec:
rego: |
package mypackage
result {
input.kind == "Pod"
podLabel := input.metadata.labels.foo
podLabel == "bar"
}
test := "my test string"
output:
validation: mypackage.result
observations:
- validate.test
The validatation
field must specify a json path that resolves to a boolean value. The observations
array currently only support variables that resolve as strings. These observations will be printed out in the remarks
section of relevant-evidence
in the assessment results.
Policy Creation
The required structure for writing a validation in rego for Lula to validate is as follows:
rego: |
package validate
validate {
}
This structure can be utilized to evaluate an expression directly:
rego: |
package validate
validate {
input.kind == "Pod"
podLabel := input.metadata.labels.foo
podLabel == "bar"
}
The expression can also use multiple rule bodies
as such:
rego: |
package validate
foolabel {
input.kind == "Pod"
podLabel := input.metadata.labels.foo
podLabel == "bar"
}
validate {
foolabel
}
[!IMPORTANT]
package validate
and validate
are required package and rule for Lula use currently when an output.validation value has not been set.
Reusing OPA modules
Custom OPA modules can be imported and referenced in the main rego module. The following example shows how to
import a custom module and use it in the main rego module:
Let’s say we have a file that is called lula.rego
with the following contents that verifies that pods have
the label lula: "true"
:
package lula.labels
import rego.v1
has_lula_label(pod) if {
pod.metadata.labels.lula == "true"
}
We can import this module and use it in the main rego module as follows:
domain:
type: kubernetes
kubernetes-spec:
resources:
- name: podsvt
resource-rule:
group:
version: v1
resource: pods
namespaces: [validation-test]
provider:
type: opa
opa-spec:
modules:
lula.labels: lula.rego
rego: | # Required - Rego policy used for data validation
package validate # Required - Package name
import future.keywords.every # Optional - Any imported keywords
import data.lula.labels as lula_labels # Optional - Import the custom module
validate { # Required - Rule Name for evaluation - "validate" is the only supported rule
every pod in input.podsvt {
lula_labels.has_lula_label(pod) # Use the rules defined in the custom module
}
}
[!Note]
The validate.rego
module name is reserved for the main rego policy and cannot be used as a custom module name.