Policies
Each policy
proposes to enforce a set of requirements (aka rules
) your supply chain must comply with. The outcome of a policy evaluation is a policy result attestation, a report that details the rule evaluatoin results and references to the provided evidence.
Policy configuration can be set under the main configuration policies
section.
A policy
consists of a set of rules
and is verified if all of them are evaluated and verified.
A rule
is verified if ANY evidence
is found that complies with the rule
configuration and setting.
Usage
Policies can be configured as part of Valint configuration file, under the policies
section
attest:
cocosign:
policies: # Set of policies - grouping rules
- name: <policy_name>
rules: # Set of rule settings/configuration and input
- name: "<rule_name>"
path: "<rule_path>" # Specify if an external script is used
description: "A brief rule description"
aggregate-results: false # Aggregate all of the rule violations to a single SARIF result
labels: [] # list of user-specified labels
initiatives: [] # list of related initatives, like SLSA, SSDF, etc.
evidence: #Evidence lookup parameters
signed: false
format-type: <format-type>
filter-by: [] # A group of Context fields to use for the evidence lookup
with: {} # rule input, depending on the rule type
Or as a separate file, referenced in --policy
flag (Early Availability, see below)
defaults:
labels: []
initiatives: []
evidence:
signed: false
format-type: <format-type>
filter-by: []
env: # File-wise environment variables for the template engine (see below)
ENV_VAR_1: "value"
name: <policy_name>
rules: # Set of rule settings/configuration and input
- name: "<rule_name>"
path: "<rule_path>" # Specify if an external script is used
description: "A brief rule description"
aggregate-results: false # Aggregate all of the rule violations to a single SARIF result
labels: [] # list of user-specified labels
initiatives: [] # list of related initatives, like SLSA, SSDF, etc.
evidence: #Evidence lookup parameters
signed: false
format-type: <format-type>
filter-by: [] # A group of Context fields to use for the evidence lookup
with: {} # rule input, depending on the rule type
Note the
defaults
section, which allows you to override values for the underlying rules, including evidence lookup parameters (which are used as defaults), labels and initatives (both appended to the existing lists).
Also note file-wise
env
values, used byvalint
for the templating engine.
A single rule can also be described in a separate file and referenced by --rule
flag (Early Availability, see below)
name: "<rule_name>"
path: "<rule_path>" # Specify if an external script is used
description: "A brief rule description"
aggregate-results: false # Aggregate all of the rule violations to a single SARIF result
labels: [] # list of user-specified labels
initiatives: [] # list of related initatives, like SLSA, SSDF, etc.
evidence: #Evidence lookup parameters
signed: false
format-type: <format-type>
filter-by: [] # A group of Context fields to use for the evidence lookup
with: {} # rule input, depending on the rule type
For configuration details, see the configuration section.
For PKI configuration, see the attestations section.
Policy
Policy support the following fields:
disable
, disable rule (default false).name
, policy name (required).rules
, list of policy rule configuration.
The field name
can be omitted. In this case, the policy will be evaluated as a default policy.
If rules
section is empty, the whole policy will be omitted.
Policy rules
A rule is a compliance check that you can configure to your specific organization's requirements.
disable
, disable rule (default false).name
, policy rule name (required).type
, type of the rule, currently supporting onlyverify-artifact
(which is used as a default and therefore can be omitted).description
, rule description (optional).labels
, list of user-specified labels (optional).initiatives
, list of related initiatives, like SLSA, SSDF, etc. (optional).path
, path to a custom rule script ORscript
, embedded rule script.script-lang
script language, currently onlyrego
is supported.evidence
, match on evidence with a specified parameters (see full description below).with
, rule-specific configuration parameters (for the detailed description, see the docs for the specific rule).
For
evidence
details, see Rule Configuration section.
Forwith
details, see related rule section.
Verify Artifact rule type
A rule of Verify Artifact type verifies some properties of an artifact. Examples of such checks are:
- Signed Evidence: The artifact should include signed or unsigned evidence, as specified by the
signed
field in the input. - Signing Identity: The artifact should be signed by a specific identity, as specified by the
identity
fields in the input (for signed evidence). - Evidence Format: The evidence format should follow the specified format(s) provided in the
format-type
field of the input. - Origin of artifact: The artifact should originate from an expected source, as specified by the
evidence
origin labels. For instance, you can verify that an artifact is generated from a particular pipeline or repository. - Artifact details: The rule applies to a specific artifact or any group of artifacts, as specified by the
evidence
subject labels. - Policy as code: The rule allows extension of the verification using custom scripts, as specified by the
path
orscript
input.
Use cases
A rule of verify-artifact
type can be used to enforce compliance with specific supply chain requirements, such as:
- Images must be signed and have a matching CycloneDX SBOM.
- Images must be built by a CircleCI workflow and produce a signed SLSA provenance.
- Tagged sources must be signed and verified by a set of individuals or processes.
- Released binaries must be built by Azure DevOps on a specific git repository using unsigned SLSA provenance.
Configuration
- name: "" # Any user provided name
description: "A brief rule description"
aggregate-results: false # Aggregate all of the rule violations to a single SARIF result
evidence:
signed: <true|false> # Define if target should be signed
format-type: "<cyclonedx-json, slsa>" # Expected evidence format
filter-by: [<product, pipeline, target, none>] # A group of Context fields to use for the evidence lookup
{environment-context} # Any Evidence Context field is also supported for matching
with:
identity:
emails: [] # Signed email identities
uris: [] # Signed URIs identities
common-names: [] # Signed common name identities
{custom script input} # Any rule-specific input
path: <path to policy script> # OR script
script-lang: rego # Currently only rego is supported
script: | # OR path
package verify
verify = v {
v := {
"allow": {Custom policy validation}
}
}
Examples
Copy the Examples into a file named .valint.yaml
in the same directory as running Valint commands.
For configuration details, see configuration section.
Details
Signed Images policy
In this example, the policy rule namedsigned_image
will evaluate images where signed by mycompony.com
using attest-cyclondex-json
format.attest:
cocosign:
policies:
- name: my_policy
rules:
- name: signed_image
evidence:
signed: true
format-type: cyclonedx
target_type: image
with:
identity:
common-names:
- mycompany.com
Command:
Run the command on the required supply chain location.
# Generate required evidence, requires signing capabilities.
valint bom busybox:latest -o attest
# Verify policy (cache store)
valint verify busybox:latest
Details
Image SLSA provenance policy
In this example, the policy rule namedslsa_prov_rule
will evaluate images where signed by bob@mycompany.com
or alice@mycompany.com
using attest-slsa
format.attest:
cocosign:
policies:
- name: my_policy
rules:
- name: slsa_prov_rule
evidence:
signed: true
format-type: slsa
target_type: image
with:
identity:
emails:
- bob@mycompany.com
- alice@mycompany.com
*Command:
Run the command on the required supply chain location.
# Generate required evidence, requires signing capabilities.
valint bom busybox:latest -o attest-slsa
# Verify policy (cache store)
valint verify busybox:latest
Details
Signed tagged sourced rule
In this example, the policy rule named "tagged_git_rule" will evaluate sources'mycompany/somerepo
tags where defined in the main
branch and signed by bob@mycompany.com
.The policy requires only the HEAD of the git target to comply to the policy not the entire history.
attest:
cocosign:
policies:
- name: my_policy
rules:
- name: tagged_git_rule
evidence:
signed: true
format-type: slsa
target_type: git
target_git_url: git@github.com:mycompany/somerepo.git # Git url of the target.
branch: main
with:
identity:
emails:
- bob@mycompany.com
*Command:
Run the command on the required supply chain location.
# Generate required evidence, requires signing capabilities.
valint bom git:github.com:your_org/your_repo.git --tag 0.1.3 -o attest-slsa
# Verify policy (cache store)
valint verify git:github.com:your_org/your_repo.git --tag 0.1.3 -i statement-slsa
Details
Binary verification
In this example, the policy, named "binary_origin" enforces requirements on the binarymy_binary.exe
was Originated from which Azure DevOps triggered by the https://dev.azure.com/mycompany/somerepo
repo.
The policy rule also enforces an unsigned SLSA provenance statement is produced as evidence.attest:
cocosign:
policies:
- name: my_policy
rules:
- name: binary_origin
evidence:
signed: false
format-type: slsa
target_type: file
context_type: azure
git_url: https://dev.azure.com/mycompany/somerepo # Git url of the environment.
input_name: my_binary.exe
*Command:
Run the command on the required supply chain location.
# Generate required evidence
valint bom file:my_binary.exe -o statement-slsa
# Verify policy (cache store)
valint verify file:my_binary.exe
Details
3rd party verification
In this example, the policy rule named "3rd-party-scan" will evaluate scanned3rd-party-scan.json
file, Originated from Azure DevOps triggered by the https://dev.azure.com/mycompany/somerepo
and signed by bob@mycompany.com
.attest:
cocosign:
policies:
- name: my_policy
rules:
- name: 3rd-party-rule
evidence:
signed: true
format-type: generic
target_type: generic
context_type: azure
git_url: https://dev.azure.com/mycompany/somerepo
git_branch: main
input_name: 3rd-party-scan.json
with:
identity:
emails:
- bob@mycompany.com
*Command:
Run the command on the required supply chain location.
# Generate required evidence
valint evidence 3rd-party-scan.json -o attest --predicate-type https://scanner.com/scan_format
# Verify policy (cache store)
valint verify 3rd-party-scan.json -i attest-generic --predicate-type https://scanner.com/scan_format
Policy as Code
You can define custom policies for artifacts verified by the rule by attaching them as code. After the rule enforces the origin and subject of the evidence, you can further analyze and customize the content to meet your organization's requirements.
Usage
The following rule verifies the predicate of the evidence in a custom Rego script embedded in the policy.
- name: signed_image_custom_policy
evidence:
signed: true
format-type: cyclonedx
target_type: image
with:
identity:
common-names:
- mycompany.com
script: |
package verify
default allow = false
verify = {
"allow": allow
}
allow = {
input.evidence.predicate-type == "https://cyclonedx.org/bom"
}
Rego script
In order to add a verification script you must provide a verify
rule in your script.
A Rego script can be provided in two forms: as an embedded code snippet in the script
section or as a dedicated file using the path
field.
By default
valint
looks for a.valint.rego
file.
Use the following rule structure.
package verify
default allow = false
verify = {
"allow": false,
"violation": {
"type": "violation_type",
"details": [],
},
"summary": [{
"allow": false,
"violations": count(violations),
"reason": "some reason string"
}],
}
Input structure
Script input has the following structure.
evidence: {Intoto-statment}
verifier: {verifier-context}
config:
args: {custom script input}
stores:
oci: {OCI store configuration}
cache: {Cache store configuration}
scribe: {Scribe store configuration}
When using Signed Attestations, the Custom Rego script receives the raw In-toto statement along with the identity of the signer.
Output structure
Script output must provide the following structure.
{
"allow": bool, # Required
"summary": [ # Optional
{
"allow": bool,
"type": "string",
"details": "string",
"violations": "int",
"reason": "string"
},
],
"errors": [], # Optional
"violation": [ # Optional
{
"type": "string",
"details": [{}],
},
]
}
Examples
Copy the Examples into a file named .valint.yaml
and Copy Examples custom script into file name .valint.rego
.
Files should be in the same directory as running Valint commands.
For configuration details, see configuration section. You may also use
path
field to set a custom path for your script.
Details
Custom package policy
In this example, the policy rule namedcustom-package-policy
to verify a custom package requirements.
In the example Alpine packages are forbidden.attest:
cocosign:
policies:
- name: my_policy
rules:
- name: signed_image
evidence:
signed: true
format-type: cyclonedx
target_type: image
script: |
package verify
import data.policies.sbom_parser as parser
default allow = false
verify = v {
v := {
"allow": allow,
"violation": violation(input.evidence.predicate.bom.components),
}
}
allow {
v := violation(input.evidence.predicate.bom.components)
count(v) == 0
input.evidence.predicateType == "https://cyclonedx.org/bom"
}
violation(components) = v {
v := { x |
some i
comp := components[i]
comp.type == "library"
comp.group == "apk"
x := comp["purl"]
}
}
Command:
Run the command on the required supply chain location.
# Generate required evidence, requires signing capabilities.
valint bom busybox:latest -o attest
# Verify policy (cache store)
valint verify busybox:latest
Default policy
When no policy configuration is found, the signed artifact policy is used.
By default, the following command runs a signature and identity verification on the target provided:
valint verify [target] --input-format [attest, attest-slsa] \
--email [email] --common-name <common name> --uri [uri]
In other words, the Signed Artifact policy allows you to verify signature compliance and format of artifacts in your supply chain.
For full command details, see valint verify section.
Details
Default Policy Evaluation
The default policy can also be evaluated as the following policy configuration:attest:
cocosign:
policies:
- name: default-policy
rules:
name: "default-rule"
evidence:
signed: true
format: ${current.content_type} # Populated by --input-format flag.
sbomversion: ${current.sbomversion} # Populated from the artifact version provided to verify command.
with:
identity: # Populated by `--email`, `--uri` and `--common-name flags sets
For rule details, see verify artifact rule section.
Templating policy params
The template engine for policy configuration provides users with a flexible mechanism to define and customize policies through the use of template arguments. These template arguments act as placeholders within the policy configuration, allowing users to dynamically substitute values before the policy is evaluated.
Currently valint
supports three groups of template arguments:
-
Context-defined
Context arguments are derived from the evidence context, enabling users to directly reference any field within it. The syntax for referencing a context variable is as follows:{{ .Context.<var_name> }}
.
Replace<var_name>
with the specific variable name from the evidence context that you want to use. Foe example,{{ .Context.git_commit }}
. -
Environment-defined
Environment arguments are derived from the environment variables. The syntax for referencing an environment variable is as follows:{{ .Env.<var_name> }}
.
Note that one can define file-wise environment variables in the policy configuration file under theenv
field. These variables will only be used for the template evaluations in the file where they are defined. -
User-defined
Users can pass custom arguments through the command line using the--rule-args
flag. These user-defined arguments are then referenced in the policy configuration using the following syntax:{{ .Args.<var_name> }}
.
For example,
valint verify git:repo.git --rule-args "my_arg"="foo"
In the policy configuration: {{ .Args.my_arg }}
.
Replacement and Error Handling
Before a policy is evaluated, template engine performs a substitution of templated arguments with the corresponding values. If the replacement process encounters an issue, such as no value provided for a variable used by the configuration, an error is issued and policy evaluation is halted.
Usage
This example demonstrates the use of template arguments in a policy configuration. The policy requires that the evidence is generated from a specific git repository and branch. The git repository and branch should beare passed as arguments to the policy using the --rule-args
flag as --rule-args git_url=<url> --rule-args git_branch=<branch>
. The target_type is passed as a field from the evidence context.
attest:
cocosign:
policies:
- name: my_policy
rules:
- name: my_rule
with:
signed: true
format-type: cyclonedx
target_type: '{{ .Context.target_type }}'
git_url: '{{ .Args.git_url }}'
git_branch: '{{ .Args.git_branch }}'
Filtering Policy Rules (Early Availability)
Since policy rules can be labeled with user-defined labels and also can be a part of one ore more initiatives, it's possible to filter them by these parameters on runtime. For this purpose, valint
has flags --rule-label
and --initiative
respectively.
When using these flags, valint
will only evaluate the rules that match the provided labels and/or initiatives. In order to be run, a rule should match all the provided labels and/or any of the initiatives. If a rule doesn't match the requirements, it will be disabled. Similarly, if no rules in a policy match the requirements, the policy will be omitted.
Evidence Lookup
In order to run a policy rule, valint
requires relevant evidence, which can be found in a storage using a number of parameters. These parameters can be set manually by the user or automatically derived from the context. Parameters that can be derived automatically are categorized into three context groups: "target," "pipeline", and "product".
-
target
context group specifies parameters that can be derived from the target provided (if any). Those parameters are:target_type
- the type of the target provided (e.g., image, git, generic etc.)sbomversion
- the version of the SBOM provided (usually it's sha256 or sha1 hash)
-
pipeline
context group specifies parameters that can be derived from the running environment. Those parameters are:context_type
- type of the environment (e.g., local, github, etc.)git_url
- git url of the repository (if any)git_commit
- git commit of the current repository state (if any)run_id
- run idbuild_num
- build number
-
product
context group specifies product parameters that can be derived from the command line arguments. Those parameters are:name
- name of the productproduct_version
- version of the productpredicate_type
- type of the predicate (e.g., https://cyclonedx.org/bom, https://slsa.dev/provenance/v0.1, etc.)
User can specify any combination of these three groups or a special value none
to indicate that the parameter should not be derived automatically.
By default target
and product
groups are used.
The list of groups to be used should be provided to the attest.cocosign.policies.<policy>.rules.<rule>.evidence.filter-by
field in the configuration file.
In addition, one can manually specify any parameters that they want to be matched by an evidence. For example, these can be git_url
or timestamp
.
If more than one evidence is found, the newest one is used.
Usage
An example of using the target
context group and a specific timestamp value is shown below:
attest:
cocosign:
policies:
- name: my_policy
rules:
- name: my_rule
evidence:
signed: true
format-type: cyclonedx
timestamp: "2023-11-16T09:46:25+02:00" # manually specified timestamp
filter-by:
- target
Targetless Run
Using evidence
field it's possible to run a policy rule without providing a target. In this case, the evidence will be looked up using the provided parameters for each rule and no values from any target will be used (simply, the filter-by: target
flag will be ignored).
To be able to run valint verify
in targetless mode, the evidence
field in a rule config should describe the needed evidence well enough.
In the following example, the newest evidence of target_type: image
for the provided product (defined by the name & version) will be used.
# my_policy.yaml
attest:
cocosign:
policies:
- name: my_policy
rules:
- name: my_rule
evidence:
signed: true
format-type: cyclonedx
target_ttpe: image
filter-by:
- product
with:
identity:
emails:
- my@email.com
valint bom busybox:latest -o attest --product-key my_product --product-version 1.0.0
valint verify --product-key my_product --product-version 1.0.0 -c my_policy.yaml
External policy configs - Early Availability
Policy or rule configuration can be set not only in the main configuration file but also in external files. This can be useful when you want to reuse the same policy configuration for different targets or as a part of a configuration bundle or when you just want to keep your main configuration file clean.
External policy/rule configuration can be set in a separate file and then referenced in the cmd args via the --policy/--rule
flag correspondingly or in the main configuration file via the attest.policy_configs
field of type []string
.
Each extermal configuration should represent an entry to attest.cocosign.policies
or to attest.cocosign.policies[].rules
field of the main configuration file.
For example, a policy configuration defined by the following file:
attest:
cocosign:
policies:
- name: default
rules:
- name: "default-rule"
evidence:
signed: true
format-type: cyclonedx
with:
identity:
emails:
- my@email.com
Can be represented in an external policy
file like
name: default
rules:
- name: "default-rule"
evidence:
signed: true
format-type: cyclonedx
with:
identity:
emails:
- my@email.com
or in an external rule
file like
name: "default-rule"
evidence:
signed: true
format-type: cyclonedx
with:
identity:
emails:
- my@email.com
One can reference several policies/rules configs per valint verify
run.
When using --policy/--rule
flag, valint
will first lookup the config in local FS and if not found, will try to use a config from the bundle (if used).
Bundle policy configs - Early Availability
Policy configurations along with the corresponding rego scripts can be bundled together in a directory or a git repo and then referenced in the cmd args via the --bundle
flag or in the main configuration file via the attest.bundle
field.
In case of using a git repo, it's possible to also specify a branch and a commit or a tag to be used with --git-branch
, --git-commit
and --git-tag
options respectively. The repo would be cloned automatically by valint
.
For the GitHub authentication, a token can be provided via GITHUB_TOKEN
environment variable or as part of url like <token>@github.com
.
To reference a policy/rule in a bundle, the relative path to the bundle root should be provided in the --policy/--rule
flag correspondingly.
Default bundle
By default, valint
defaults to work with scribe-public/sample-policies as a bundle. One can use its rules out of the box by providing the rule name in the --policy/--rule
flags. If no --policy
or --rule
flag is provided or the --skip-bundle
flag is used, no bundle will be downloaded.
Reusing bundle rules
The "uses" flag in rule descriptions allows users to utilize external configurations from a bundle as a base for creating custom rules. This feature simplifies reusing of bundle rules with different parameters.
For example, lets reuse bundle config v1/images/fresh-image.yaml
. Let's create a local rule config file:
uses: images/fresh-image@v1
with:
max_days: 1000
Note that the config file extension is applied by valint
automatically, there's no need to specify it.
The value with.max_days: 1000
will override the default from the bundle config, the other values will remain the same. If needed, one can override any other value from the bundle config.
It's also possible to create a policy config utilizing multiple bundle rules:
rules:
- uses: images/fresh-image@v1
with:
max_days: 1000
- uses: images/forbid-large-images@v1
Such policy configs can later be referenced in the --policy
flag (see examples below).
Examples
To run an external policy, say, on a docker image target, first we need to create an image SBOM:
valint bom busybox:latest -o attest
Then, if we have a policy rule like
name: "default-rule"
evidence:
signed: true
format-type: cyclonedx
with:
identity:
emails:
- my@email.com
saved in path/to/rule.yaml
, we can run the policy:
valint verify busybox:latest --rule /path/to/rule.yaml
If the rule is a part of a bundle and the path in the bundle looks like v1/images/rule.yaml
, then we can run it like
valint verify busybox:latest --bundle https://github.com/user/bundle --git-tag v1.0.0 --rule images/rule@v1
An example of policy evaluation results can be found in the policy results section.