Skip to content

Commit

Permalink
Add StepAction policy rules
Browse files Browse the repository at this point in the history
Ref: EC-1010

Signed-off-by: Luiz Carvalho <lucarval@redhat.com>
  • Loading branch information
lcarva committed Nov 22, 2024
1 parent 78a62de commit b6f40b6
Show file tree
Hide file tree
Showing 9 changed files with 319 additions and 0 deletions.
1 change: 1 addition & 0 deletions antora/docs/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ include::partial$release_policy_nav.adoc[]
include::partial$pipeline_policy_nav.adoc[]
include::partial$build_task_policy_nav.adoc[]
include::partial$task_policy_nav.adoc[]
include::partial$stepaction_policy_nav.adoc[]
* xref:trusted_tasks.adoc[Trusted Tasks]
* xref:trusting_tasks.adoc[Trusting Tasks]
* xref:policy_bundles.adoc[Policy Bundles]
Expand Down
1 change: 1 addition & 0 deletions antora/docs/modules/ROOT/pages/stepaction.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
= StepAction Policy
65 changes: 65 additions & 0 deletions antora/docs/modules/ROOT/pages/stepaction_policy.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
= StepAction Task Policy

:numbered:

These rules are applied to Tekton StepAction definitions.

[#image_package]
== link:#image_package[Tekton StepAction images policies]

This package ensures that a StepAction definition contains a valid and allowed value for the image reference.

* Package name: `image`
[#image__permitted]
=== link:#image__permitted[Image comes from permitted registry]

Confirm the StepAction uses a container image with a URL that matches one of the prefixes in the provided list of allowed step image registry prefixes. The list is customizeable via the `allowed_step_image_registry_prefixes` rule data key.

*Solution*: Make sure the container image used comes from an approved registry.

* Rule type: [rule-type-indicator failure]#FAILURE#
* FAILURE message: `Image ref %q is disallowed`
* Code: `image.permitted`
* https://github.com/enterprise-contract/ec-policies/blob/{page-origin-refhash}/policy/stepaction/image/image.rego#L38[Source, window="_blank"]
[#image__accessible]
=== link:#image__accessible[Image is accessible]
Confirm the container image used in the StepTemplate is accessible.
*Solution*: Make sure the container image used in the StepTemplate is pushed to the registry and that it can be fetched.
* Rule type: [rule-type-indicator failure]#FAILURE#
* FAILURE message: `Image ref %q is inaccessible`
* Code: `image.accessible`
* https://github.com/enterprise-contract/ec-policies/blob/{page-origin-refhash}/policy/stepaction/image/image.rego#L16[Source, window="_blank"]
[#image__rule_data]
=== link:#image__rule_data[Rule data provided]
Confirm the `allowed_step_image_registry_prefixes` rule data is provided.
*Solution*: Make sure the xref:ec-cli:ROOT:configuration.adoc#_data_sources[data sources] contains a key 'allowed_step_image_registry_prefixes' that contains a list of approved registries.
* Rule type: [rule-type-indicator failure]#FAILURE#
* FAILURE message: `%s`
* Code: `image.rule_data`
* https://github.com/enterprise-contract/ec-policies/blob/{page-origin-refhash}/policy/stepaction/image/image.rego#L62[Source, window="_blank"]
[#kind_package]
== link:#kind_package[Tekton StepAction kind checks]
Policies to verify that a Tekton StepAction definition has the expected value for kind.
* Package name: `kind`
[#kind__valid]
=== link:#kind__valid[StepAction definition has expected kind]
Confirm the StepAction definition has the kind "StepAction".
* Rule type: [rule-type-indicator failure]#FAILURE#
* FAILURE message: `Unexpected kind %q for StepAction definition`
* Code: `kind.valid`
* https://github.com/enterprise-contract/ec-policies/blob/{page-origin-refhash}/policy/stepaction/kind/kind.rego#L14[Source, window="_blank"]
7 changes: 7 additions & 0 deletions antora/docs/modules/ROOT/partials/stepaction_policy_nav.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
* xref:stepaction_policy.adoc[StepAction Task Policy]
** xref:stepaction_policy.adoc#image_package[Tekton StepAction images policies]
*** xref:stepaction_policy.adoc#image__permitted[Image comes from permitted registry]
*** xref:stepaction_policy.adoc#image__accessible[Image is accessible]
*** xref:stepaction_policy.adoc#image__rule_data[Rule data provided]
** xref:stepaction_policy.adoc#kind_package[Tekton StepAction kind checks]
*** xref:stepaction_policy.adoc#kind__valid[StepAction definition has expected kind]
5 changes: 5 additions & 0 deletions docs/asciidoc/asciidoc.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,11 @@ var docs = []doc{
Qualifier: "build_task",
Description: "These rules are applied to Tekton build task definitions.",
},
{
Name: "StepAction Task",
Qualifier: "stepaction",
Description: "These rules are applied to Tekton StepAction definitions.",
},
}

//go:embed nav.template
Expand Down
100 changes: 100 additions & 0 deletions policy/stepaction/image/image.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#
# METADATA
# title: Tekton StepAction images policies
# description: >-
# This package ensures that a StepAction definition contains a valid and allowed value for the
# image reference.
#
package stepaction.image

import rego.v1

import data.lib
import data.lib.json as j
import data.lib.k8s

# METADATA
# title: Image is accessible
# description: >-
# Confirm the container image used in the StepTemplate is accessible.
# custom:
# short_name: accessible
# failure_msg: Image ref %q is inaccessible
# solution: >-
# Make sure the container image used in the StepTemplate is pushed to the registry and that it
# can be fetched.
#
deny contains result if {
image_ref := input.spec.image
not ec.oci.image_manifest(image_ref)

result := lib.result_helper_with_term(
rego.metadata.chain(),
[image_ref],
image_ref,
)
}

# METADATA
# title: Image comes from permitted registry
# description: >-
# Confirm the StepAction uses a container image with a URL that matches one of the prefixes in the
# provided list of allowed step image registry prefixes. The list is customizeable via the
# `allowed_step_image_registry_prefixes` rule data key.
# custom:
# short_name: permitted
# failure_msg: Image ref %q is disallowed
# solution: >-
# Make sure the container image used comes from an approved registry.
#
deny contains result if {
image_ref := input.spec.image
allowed_registry_prefixes := lib.rule_data(_rule_data_key)
not ref_permitted(image_ref, allowed_registry_prefixes)

result := lib.result_helper_with_term(
rego.metadata.chain(),
[image_ref],
k8s.name_version(input),
)
}

# METADATA
# title: Rule data provided
# description: >-
# Confirm the `allowed_step_image_registry_prefixes` rule data is provided.
# custom:
# short_name: rule_data
# failure_msg: "%s"
# solution: >-
# Make sure the xref:ec-cli:ROOT:configuration.adoc#_data_sources[data sources] contains a key
# 'allowed_step_image_registry_prefixes' that contains a list of approved registries.
#
deny contains result if {
some e in _rule_data_errors
result := lib.result_helper_with_severity(rego.metadata.chain(), [e.message], e.severity)
}

ref_permitted(image_ref, allowed_prefixes) if {
some allowed_prefix in allowed_prefixes
startswith(image_ref, allowed_prefix)
}

_rule_data_errors contains error if {
some e in j.validate_schema(
lib.rule_data(_rule_data_key),
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "array",
"items": {"type": "string"},
"uniqueItems": true,
"minItems": 1,
},
)
error := {
"message": sprintf("Rule data %s has unexpected format: %s", [_rule_data_key, e.message]),
"severity": e.severity,
}
}

_rule_data_key := "allowed_step_image_registry_prefixes"
97 changes: 97 additions & 0 deletions policy/stepaction/image/image_test.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package policy.stepaction.image_test

import rego.v1

import data.lib
import data.stepaction.image

test_image_accessible if {
stepaction := {
"kind": "StepAction",
"spec": {"image": "registry.io/repository/ok:1"},
}

lib.assert_empty(image.deny) with input as stepaction
with ec.oci.image_manifest as mock_image_manifest
with data.rule_data as default_rule_data
}

test_image_not_accessible if {
stepaction := {
"kind": "StepAction",
"spec": {"image": "registry.io/repository/not_ok:1"},
}

expected := {{
"code": "stepaction.image.accessible",
"msg": `Image ref "registry.io/repository/not_ok:1" is inaccessible`,
"term": "registry.io/repository/not_ok:1",
}}

lib.assert_equal_results(expected, image.deny) with input as stepaction
with ec.oci.image_manifest as mock_image_manifest
with data.rule_data as default_rule_data
}

test_image_not_permitted if {
stepaction := {
"kind": "StepAction",
"spec": {"image": "registry.io/repository/ok:1"},
}

rule_data := {"allowed_step_image_registry_prefixes": ["dope.registry.io/"]}

expected := {{
"code": "stepaction.image.permitted",
"msg": `Image ref "registry.io/repository/ok:1" is disallowed`,
"term": "noname/noversion",
}}

lib.assert_equal_results(expected, image.deny) with input as stepaction
with ec.oci.image_manifest as mock_image_manifest
with data.rule_data as rule_data
}

test_rule_data_list_empty if {
expected := {{
"code": "stepaction.image.rule_data",
# regal ignore:line-length
"msg": "Rule data allowed_step_image_registry_prefixes has unexpected format: (Root): Array must have at least 1 items",
"severity": "failure",
}}

lib.assert_equal_results(expected, image.deny) with data.rule_data as {}
}

test_rule_data_list_format if {
d := {"allowed_step_image_registry_prefixes": [
# Wrong type
1,
# Duplicated items
"registry.local/",
"registry.local/",
]}

expected := {
{
"code": "stepaction.image.rule_data",
# regal ignore:line-length
"msg": "Rule data allowed_step_image_registry_prefixes has unexpected format: 0: Invalid type. Expected: string, given: integer",
"severity": "failure",
},
{
"code": "stepaction.image.rule_data",
# regal ignore:line-length
"msg": "Rule data allowed_step_image_registry_prefixes has unexpected format: (Root): array items[1,2] must be unique",
"severity": "failure",
},
}

lib.assert_equal_results(expected, image.deny) with data.rule_data as d
}

mock_image_manifest(ref) := {} if {
startswith(ref, "registry.io/repository/ok")
}

default_rule_data := {"allowed_step_image_registry_prefixes": ["registry.io/"]}
26 changes: 26 additions & 0 deletions policy/stepaction/kind/kind.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#
# METADATA
# title: Tekton StepAction kind checks
# description: >-
# Policies to verify that a Tekton StepAction definition has the expected
# value for kind.
#
package stepaction.kind

import rego.v1

import data.lib

# METADATA
# title: StepAction definition has expected kind
# description: >-
# Confirm the StepAction definition has the kind "StepAction".
# custom:
# short_name: valid
# failure_msg: Unexpected kind %q for StepAction definition
#
deny contains result if {
k := object.get(input, "kind", "")
k != "StepAction"
result := lib.result_helper(rego.metadata.chain(), [k])
}
17 changes: 17 additions & 0 deletions policy/stepaction/kind/kind_test.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package policy.stepaction.kind_test

import rego.v1

import data.lib
import data.stepaction.kind

test_invalid_kind if {
lib.assert_equal_results(kind.deny, {{
"code": "stepaction.kind.valid",
"msg": `Unexpected kind "Foo" for StepAction definition`,
}}) with input.kind as "Foo"
}

test_valid_kind if {
lib.assert_empty(kind.deny) with input as {"kind": "StepAction"}
}

0 comments on commit b6f40b6

Please sign in to comment.