From dd880368034923e9fc67aff15c1ed1729eb08e97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20Garc=C3=ADa=20Veytia=20=28Puerco=29?= Date: Thu, 2 May 2024 01:24:25 -0600 Subject: [PATCH 1/5] WIP Github SLSA Provenance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Adolfo García Veytia (Puerco) --- .../github/attestation_slsa_github.yaml | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 rule-types/github/attestation_slsa_github.yaml diff --git a/rule-types/github/attestation_slsa_github.yaml b/rule-types/github/attestation_slsa_github.yaml new file mode 100644 index 0000000..a2148a1 --- /dev/null +++ b/rule-types/github/attestation_slsa_github.yaml @@ -0,0 +1,135 @@ +--- +version: v1 +type: rule-type +name: artifact_signature +context: + provider: github +description: | + Verifies a provenance attestation with a GitHub build definition matches the + expected values. +guidance: | + Provenance attestation capture the build environment and parameters where a + software artifact was created. By controlling the build environment, developers + can make sure no malicious artifacts where injected into the build process. +def: + # Defines the section of the pipeline the rule will appear in. + # This will affect the template used to render multiple parts + # of the rule. + in_entity: artifact + # Defines the schema for parameters that will be passed to the rule + param_schema: + type: object + properties: + name: + type: string + description: "The name of the artifact to check." + tags: + "type": array + "items": { + "type": "string" + } + description: "The tags of the artifact to check. Must be a subset of the tags the artifact has" + tag_regex: + type: string + description: "The regex to match the tags of the artifact to check. Conflicts with tags." + type: + "type": string + "default": "container" + "enum": ["container"] + description: "The type of artifact to check. Currently only container is supported." + sigstore: + type: string + description: "URL of the sigstore TUF root to use for verification." + default: "tuf-repo-cdn.sigstore.dev" + required: + - tags + # Defines the schema for writing a rule with this rule being checked + rule_schema: + type: "object" + properties: + event: + type: array + description: "Events allowed to trigger a build" + enum: + - worflow_dispatch + - push + default: ["worflow_dispatch", "push"] + workflow_repository: + type: string + description: "Tepository expected to produce the artifact, i.e. https://github.com/stacklok/minder" + workflow_ref: + type: string + description: "The git reference of the executed workflow" + is_verified: + type: boolean + description: "Set to true to enforce artifact signature being verified." + signer_identity: + type: string + description: "Set the signer identity that is expected to produce the artifact, i.e. docker-image-build-push.yml or an email address" + runner_environment: + type: string + description: "Set the runner environment that is expected to produce the artifact, i.e. github-hosted" + allowed_workflow: + type: boolean + description: "Set to true to enforce checking if the workflow that build this artifact is part of the allowed workflows" + cert_issuer: + type: string + description: "Set the certificate issuer that is expected to produce the artifact provenance, i.e. https://token.actions.githubusercontent.com" + # Defines the configuration for ingesting data relevant for the rule + ingest: + type: artifact + # Currently no configuration + artifact: {} + # Defines the configuration for evaluating data ingested against the given profile + eval: + type: rego + rego: + type: deny-by-default + def: | + package minder + + import rego.v1 + + default allow := false + + allow if { + some artifact in input.ingested + artifact.Verification.attestation.predicate_type == "https://slsa.dev/provenance/v1" + + # These parameters only apply when the slsa attestation has a + # buildDefinition.buildType of https://slsa-framework.github.io/github-actions-buildtypes/workflow/v1 + + # Check the external parameters + artifact.Verification.attestation.predicate.buildDefinition.externalParameters.workflow.path == ".github/workflows/build-image-signed-ghat.yml" + artifact.Verification.attestation.predicate.buildDefinition.externalParameters.workflow.ref == "refs/heads/main" + artifact.Verification.attestation.predicate.buildDefinition.externalParameters.workflow.repository == "https://github.com/jakubtestorg/good-repo-go" + + # Internal parameters + # Event is anm arrau + artifact.Verification.attestation.predicate.buildDefinition.internalParameters.github.event_name == "workflow_dispatch" + } + + + #every artifactVersion in input.ingested { + # some x in artifactVersion.Verification.attestation.predicateType + # x == "https://slsa.dev/provenance/v1" + ##artifactVersion.Verification.attestation.predicateType == "https://slsa.dev/provenance/v1" { + # artifactVersion.Verification["is_signed"] + #} + #} + + #allow if { + # every artifactVersion in input.ingested { + # if artifactVersion.Verification.attestation.predicateType == "https://slsa.dev/provenance/v1" { + # artifactVersion.Verification["is_signed"] + # } + ## #every key, value in input.profile { + # # # artifactVersion.Verification[key] == value + # #} + # } + #} + # Defines the configuration for alerting on the rule + alert: + type: security_advisory + security_advisory: + severity: "medium" From ce216f475f6dd2b22415d159be0ea5ed17dc603c Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Thu, 2 May 2024 13:33:52 +0200 Subject: [PATCH 2/5] Additions to the ruletype --- .../github/attestation_slsa_github.yaml | 61 ++++++++----------- 1 file changed, 25 insertions(+), 36 deletions(-) diff --git a/rule-types/github/attestation_slsa_github.yaml b/rule-types/github/attestation_slsa_github.yaml index a2148a1..5522c28 100644 --- a/rule-types/github/attestation_slsa_github.yaml +++ b/rule-types/github/attestation_slsa_github.yaml @@ -1,7 +1,7 @@ --- version: v1 type: rule-type -name: artifact_signature +name: artifact_signature_slsa context: provider: github description: | @@ -50,13 +50,15 @@ def: event: type: array description: "Events allowed to trigger a build" - enum: - - worflow_dispatch - - push - default: ["worflow_dispatch", "push"] + items: + type: string + enum: + - workflow_dispatch + - push + default: ["workflow_dispatch", "push"] workflow_repository: type: string - description: "Tepository expected to produce the artifact, i.e. https://github.com/stacklok/minder" + description: "Repository expected to produce the artifact, i.e. https://github.com/stacklok/minder" workflow_ref: type: string description: "The git reference of the executed workflow" @@ -91,43 +93,30 @@ def: import rego.v1 default allow := false + default skip := false - allow if { + artifacts_github_provenance = {artifact | some artifact in input.ingested artifact.Verification.attestation.predicate_type == "https://slsa.dev/provenance/v1" - - # These parameters only apply when the slsa attestation has a - # buildDefinition.buildType of https://slsa-framework.github.io/github-actions-buildtypes/workflow/v1 - - # Check the external parameters - artifact.Verification.attestation.predicate.buildDefinition.externalParameters.workflow.path == ".github/workflows/build-image-signed-ghat.yml" - artifact.Verification.attestation.predicate.buildDefinition.externalParameters.workflow.ref == "refs/heads/main" - artifact.Verification.attestation.predicate.buildDefinition.externalParameters.workflow.repository == "https://github.com/jakubtestorg/good-repo-go" - - # Internal parameters - # Event is anm arrau - artifact.Verification.attestation.predicate.buildDefinition.internalParameters.github.event_name == "workflow_dispatch" + artifact.Verification.attestation.predicate.buildDefinition.buildType == "https://slsa-framework.github.io/github-actions-buildtypes/workflow/v1" } + allow if { + count(artifacts_github_provenance) > 0 + + every artifact in artifacts_github_provenance { + artifact.Verification.attestation.predicate.buildDefinition.externalParameters.workflow.path == input.profile.signer_identity + artifact.Verification.attestation.predicate.buildDefinition.externalParameters.workflow.ref == input.profile.workflow_ref + artifact.Verification.attestation.predicate.buildDefinition.externalParameters.workflow.repository == input.profile.workflow_repository - #every artifactVersion in input.ingested { - # some x in artifactVersion.Verification.attestation.predicateType - # x == "https://slsa.dev/provenance/v1" - ##artifactVersion.Verification.attestation.predicateType == "https://slsa.dev/provenance/v1" { - # artifactVersion.Verification["is_signed"] - #} - #} + some event in input.profile.event + artifact.Verification.attestation.predicate.buildDefinition.internalParameters.github.event_name == event + } + } - #allow if { - # every artifactVersion in input.ingested { - # if artifactVersion.Verification.attestation.predicateType == "https://slsa.dev/provenance/v1" { - # artifactVersion.Verification["is_signed"] - # } - ## #every key, value in input.profile { - # # # artifactVersion.Verification[key] == value - # #} - # } - #} + skip if { + count(artifacts_github_provenance) == 0 + } # Defines the configuration for alerting on the rule alert: type: security_advisory From 37059e2b0dd1d4535b08eb8ff9975e54f0ef7c39 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Thu, 2 May 2024 19:11:37 +0200 Subject: [PATCH 3/5] more changes - Get rid of the is_verified, allowed_workflow and cert_issuer attributes - fix descriptions - check that if is_verified and is_signed is present, it must be true - check runner_environment --- .../github/attestation_slsa_github.yaml | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/rule-types/github/attestation_slsa_github.yaml b/rule-types/github/attestation_slsa_github.yaml index 5522c28..176cf72 100644 --- a/rule-types/github/attestation_slsa_github.yaml +++ b/rule-types/github/attestation_slsa_github.yaml @@ -1,7 +1,7 @@ --- version: v1 type: rule-type -name: artifact_signature_slsa +name: attestation_slsa_github context: provider: github description: | @@ -62,21 +62,12 @@ def: workflow_ref: type: string description: "The git reference of the executed workflow" - is_verified: - type: boolean - description: "Set to true to enforce artifact signature being verified." signer_identity: type: string - description: "Set the signer identity that is expected to produce the artifact, i.e. docker-image-build-push.yml or an email address" + description: "Set the signer identity that is expected to produce the artifact, e.g. .github/workflows/build-image-signed-ghat-malicious.yml or an email address" runner_environment: type: string - description: "Set the runner environment that is expected to produce the artifact, i.e. github-hosted" - allowed_workflow: - type: boolean - description: "Set to true to enforce checking if the workflow that build this artifact is part of the allowed workflows" - cert_issuer: - type: string - description: "Set the certificate issuer that is expected to produce the artifact provenance, i.e. https://token.actions.githubusercontent.com" + description: "Set the runner environment that is expected to produce the artifact, e.g. https://github.com/actions/runner/github-hosted" # Defines the configuration for ingesting data relevant for the rule ingest: type: artifact @@ -105,9 +96,16 @@ def: count(artifacts_github_provenance) > 0 every artifact in artifacts_github_provenance { + # we use not == false here because that handles the case where the field is not present + # the fields are also not exposed as parameters, we might want to change them while we reword the + # the artifact_signature rule so let's not depend on them in a new rule + not artifact.Verification.is_verified == false + not artifact.Verification.is_signed == false + artifact.Verification.attestation.predicate.buildDefinition.externalParameters.workflow.path == input.profile.signer_identity artifact.Verification.attestation.predicate.buildDefinition.externalParameters.workflow.ref == input.profile.workflow_ref artifact.Verification.attestation.predicate.buildDefinition.externalParameters.workflow.repository == input.profile.workflow_repository + artifact.Verification.attestation.predicate.runDetails.builder.id == input.profile.runner_environment some event in input.profile.event artifact.Verification.attestation.predicate.buildDefinition.internalParameters.github.event_name == event From 3018f7c02c1925420fc9d1672b46526166ffa0bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20Garc=C3=ADa=20Veytia=20=28Puerco=29?= Date: Thu, 2 May 2024 13:55:15 -0600 Subject: [PATCH 4/5] Rename slsa ruletype to artifact_attestation_slsa MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Adolfo García Veytia (Puerco) --- ...ttestation_slsa_github.yaml => artifact_attestation_slsa.yaml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename rule-types/github/{attestation_slsa_github.yaml => artifact_attestation_slsa.yaml} (100%) diff --git a/rule-types/github/attestation_slsa_github.yaml b/rule-types/github/artifact_attestation_slsa.yaml similarity index 100% rename from rule-types/github/attestation_slsa_github.yaml rename to rule-types/github/artifact_attestation_slsa.yaml From d64ebcc01311d5eab2dba156588933ac9bf99839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20Garc=C3=ADa=20Veytia=20=28Puerco=29?= Date: Thu, 2 May 2024 14:35:08 -0600 Subject: [PATCH 5/5] Update attestaion ruletype name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Adolfo García Veytia (Puerco) --- .../github/artifact_attestation_slsa.yaml | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/rule-types/github/artifact_attestation_slsa.yaml b/rule-types/github/artifact_attestation_slsa.yaml index 176cf72..43b5e1b 100644 --- a/rule-types/github/artifact_attestation_slsa.yaml +++ b/rule-types/github/artifact_attestation_slsa.yaml @@ -1,16 +1,18 @@ --- version: v1 type: rule-type -name: attestation_slsa_github +name: artifact_attestation_slsa context: provider: github description: | - Verifies a provenance attestation with a GitHub build definition matches the - expected values. + Verifies a SLSA provenance attestation guidance: | - Provenance attestation capture the build environment and parameters where a + Provenance attestations capture the build environment and parameters where a software artifact was created. By controlling the build environment, developers - can make sure no malicious artifacts where injected into the build process. + can check the integity of the build environment and that no malicious code + was injected into the build process. + + For more information visit https://slsa.dev def: # Defines the section of the pipeline the rule will appear in. # This will affect the template used to render multiple parts @@ -86,6 +88,9 @@ def: default allow := false default skip := false + workflow_ref := input.profile.workflow_ref + default workflow_ref := "refs/heads/main" + artifacts_github_provenance = {artifact | some artifact in input.ingested artifact.Verification.attestation.predicate_type == "https://slsa.dev/provenance/v1" @@ -94,7 +99,7 @@ def: allow if { count(artifacts_github_provenance) > 0 - + every artifact in artifacts_github_provenance { # we use not == false here because that handles the case where the field is not present # the fields are also not exposed as parameters, we might want to change them while we reword the @@ -103,7 +108,7 @@ def: not artifact.Verification.is_signed == false artifact.Verification.attestation.predicate.buildDefinition.externalParameters.workflow.path == input.profile.signer_identity - artifact.Verification.attestation.predicate.buildDefinition.externalParameters.workflow.ref == input.profile.workflow_ref + artifact.Verification.attestation.predicate.buildDefinition.externalParameters.workflow.ref == workflow_ref artifact.Verification.attestation.predicate.buildDefinition.externalParameters.workflow.repository == input.profile.workflow_repository artifact.Verification.attestation.predicate.runDetails.builder.id == input.profile.runner_environment