Creating attestations with Kritis Signer

This tutorial explains how to build Kritis Signer and use it to check container images for vulnerabilities before creating Binary Authorization attestations.

Overview

Kritis Signer is an open source command-line tool that can create Binary Authorization attestations based on a policy that you configure. You can also use Kritis Signer to create attestations after checking an image for vulnerabilities identified by Container Analysis.

Additionally, Cloud Build can run Kritis Signer as a custom builder in a build pipeline.

In this tutorial you perform a one-time build of the Kritis Signer custom builder, and then you run sample build pipelines. Each sample pipeline contains the following build steps:

  1. Build a sample container image.
  2. Push the image to Container Registry.
  3. Check and sign the image: Use Kritis Signer to create an attestation based on the policy.

In the check-and-sign build step of each pipeline, Kritis Signer does the following:

  1. Scans the newly built image with Container Analysis and retrieves a list of vulnerabilities.
  2. Checks the list of vulnerabilities against vulnerability signing rules in the policy and then:
    1. If all of the identified vulnerabilities satisfy the vulnerability signing rules, Kritis Signer creates the attestation.
    2. If any of the identified vulnerabilities violate the vulnerability signing rules, Kritis Signer does not create the attestation.

At deploy time, the Binary Authorization enforcer checks for a verifiable attestation. Without one, the enforcer disallows the image from deploying.

This tutorial also explains how to run Kritis Signer in check-only mode in a Cloud Build pipeline. In this mode, Kritis Signer does not create an attestation, it only checks whether the vulnerability results satisfy the vulnerability signing rules in the policy. If they do, the Kritis Signer build step succeeds and the pipeline continues to run, otherwise the step fails and the pipeline exits.

Objectives

In this tutorial you do the following:

  1. Set up Kritis Signer as a Cloud Build custom builder.
  2. View a policy that contains vulnerability signing rules.
  3. Run Kritis Signer in create attestations based on vulnerability scanning results.
  4. Run Kritis Signer in check-only mode.

Costs

This tutorial uses the following Google Cloud products.

  • Container Registry
  • Container Analysis
  • Cloud Build
  • Cloud Key Management Service

Use the Pricing Calculator to generate a cost estimate based on your projected usage.

Before you begin

In this section, you perform a one-time setup of the system.

Set up your environment

  1. Store your Google Cloud project in an environment variable.

    export PROJECT_ID=PROJECT_ID
    

    Replace PROJECT_ID with your Google Cloud project.

  2. Set the default project ID to your Google Cloud project:

    gcloud config set project $PROJECT_ID
    
  3. Store the project number in an environment variable for future steps:

    export PROJECT_NUMBER=$(gcloud projects list --filter="${PROJECT_ID}" \
     --format="value(PROJECT_NUMBER)")
    
  4. Enable APIs:

    To ensure the services required for this guide are enabled, execute the following command:

    gcloud services enable \
      cloudbuild.googleapis.com \
      containerregistry.googleapis.com \
      containerscanning.googleapis.com \
      cloudkms.googleapis.com
    

Set up IAM roles

Run the following commands to configure the Cloud Build service account with the following roles:

  • containeranalysis.notes.editor: adds the Container Analysis Notes Editor role to manage the attestor.
  • containeranalysis.notes.occurrences.viewer: adds the Container Analysis Occurrences for Notes role to manage both the vulnerability and attestation occurrences.
  • roles/containeranalysis.occurrences.editor: adds the Container Analysis Occurrences Editor role to create attestation occurrences in Container Analysis.
  • cloudkms.signer: adds the Cloud KMS CryptoKey Signer role that allows the service account to access the Cloud KMS signing service.

    gcloud projects add-iam-policy-binding $PROJECT_ID --member serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com --role roles/containeranalysis.notes.editor
    gcloud projects add-iam-policy-binding $PROJECT_ID --member serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com --role roles/containeranalysis.notes.occurrences.viewer
    gcloud projects add-iam-policy-binding $PROJECT_ID --member serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com --role roles/containeranalysis.occurrences.editor
    gcloud projects add-iam-policy-binding $PROJECT_ID --member serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com --role roles/cloudkms.signer
    

Set up the Kritis Signer custom builder

In this section, you perform a one-time setup of the Kritis Signer custom builder. Once you obtain, build, and push Kritis Signer, it can then be used in any Cloud Build pipeline.

This section shows you how to:

  • Clone the Kritis repository.
  • Build the Kritis Signer Cloud Build custom builder.
  • Push Kritis Signer to Container Registry to make it available for use as a Cloud Build build step.

Run the following commands to get the code and configuration files used in this guide:

  1. Clone the Kritis repository:

    git clone --branch signer-v1.0.0 https://github.com/grafeas/kritis.git
    

    This repository contains the following:

    • Source code for Kritis that also includes Kritis Signer.
    • A Cloud Build configuration file that is used by Cloud Build to build the Kritis Signer custom builder.
    • An example policy that contains vulnerability signing rules.
    • Example Cloud Build configuration files. Each configuration file uses Kritis Signer in a vulnerability scanning pipeline.
  2. Navigate to the kritis/ directory:

    cd kritis
    
  3. Build and register Kritis Signer custom builder.

    This one-time setup step builds the Kritis Signer custom builder and registers it with Cloud Build. Once registered, the custom builder is available for use in any Cloud Build pipeline.

    gcloud builds submit . --config deploy/kritis-signer/cloudbuild.yaml
    

View an existing policy

This section shows an example Kritis Signer policy.

This policy configures Kritis Signer to request Container Analysis to scan the image for vulnerabilities. After the scan completes, Kritis Signer checks returned vulnerability results against the vulnerability signing rules in the policy.

You can edit the vulnerability signing rules in this policy to allowlist:

  • Specific Qualitative Severity Ratings (QSR), such as Critical, High, Medium, and Low. These QSRs describe the severity of identified vulnerabilities. For more information, see the CVSS Specification (opens in a new tab).
  • Specific vulnerabilities (CVEs).

To view the Kritis Signer policy:

cat samples/signer/policy.yaml

It looks like this:

apiVersion: kritis.grafeas.io/v1beta1
kind: VulnzSigningPolicy
metadata:
  name: my-vsp
spec:
  imageVulnerabilityRequirements:
    maximumFixableSeverity: MEDIUM
    maximumUnfixableSeverity: MEDIUM
    allowlistCVEs:
    - projects/goog-vulnz/notes/CVE-2020-10543
    - projects/goog-vulnz/notes/CVE-2020-10878
    - projects/goog-vulnz/notes/CVE-2020-14155

Where:

  • maximumUnfixableSeverity and maximumFixableSeverity each may be one of:

    • CRITICAL: A QSR of Critical, according to the CVSS Specification (opens in new tab).
    • HIGH: A QSR of High, according to the CVSS Specification (opens in new tab).
    • MEDIUM: A QSR of Medium, according to the CVSS Specification (opens in new tab).
    • LOW: A QSR of Low, according to the CVSS Specification (opens in new tab).
    • BLOCK_ALL: The attestation is not created if any vulnerability is identified.
    • ALLOW_ALL: The attestation is always created.
  • allowlistCVEs is a list of vulnerabilities. Each entry must exactly match the note name.

Create a Cloud KMS signing key

Cloud Key Management Service keys are used to create the attestation.

  1. Create a new Cloud KMS key ring with name kritis-signer-key-ring:

    gcloud kms keyrings create kritis-signer-key-ring \
       --location global
    
  2. Create a new Cloud KMS key called kritis-signer-key within the key ring:

    gcloud kms keys create kritis-signer-key \
        --keyring kritis-signer-key-ring \
        --location global \
        --purpose "asymmetric-signing" \
        --default-algorithm "rsa-sign-pkcs1-2048-sha256"
    
  3. Store the digest algorithm and Cloud KMS in an environment variable for future steps:

    export KMS_DIGEST_ALG=SHA256
    export KMS_KEY_NAME=projects/$PROJECT_ID/locations/global/keyRings/kritis-signer-key-ring/cryptoKeys/kritis-signer-key/cryptoKeyVersions/1
    

Define a note name

All attestations reference a Container Analysis note. Kritis Signer automatically creates a note for a given name. You can also reuse existing note names.

export NOTE_ID=my-signer-note
export NOTE_NAME=projects/${PROJECT_ID}/notes/${NOTE_ID}

Create attestations with Kritis Signer in a Cloud Build pipeline

This section demonstrates how to use the Kritis Signer custom cloud builder to create Binary Authorization attestations based on vulnerability scanning results.

The following steps demonstrate how Kritis Signer works using the example build config files in the Kritis Signer repository. Each example config file contains the following build steps:

  1. A docker build step that builds a Docker container image.
  2. A docker push step that pushes the newly built container image to Container Registry.
  3. A vulnsign step that checks and signs the container image by:

    1. Waiting for Container Analysis to return vulnerability findings on the newly built container image.
    2. Checking the findings against the vulnerability signing rules in the policy.
    3. Creating the attestation if the findings satisfy the vulnerability rules.

You submit each of the example builds to Cloud Build. Each build produces a vulnerability result:

  • Failure case: In the first build, the vulnerability result violates the vulnerability signing rules. This build fails.
  • Success case: In the second build, the vulnerability result satisfies the vulnerability signing rules. This build succeeds.

Submit the failure-case sample build

This example builds a container image based on Debian 9. At present, the image contains a vulnerability that violates the vulnerability signing rules. The Kritis Signer custom builder does not produce an attestation.

  1. (Optional) View the build configuration file for the failure case.

    cat samples/signer/cloudbuild-bad.yaml
    
  2. Submit the build:

    gcloud builds submit \
      --substitutions=_KMS_KEY_NAME=$KMS_KEY_NAME,_KMS_DIGEST_ALG=$KMS_DIGEST_ALG,_NOTE_NAME=$NOTE_NAME \
      --config=samples/signer/cloudbuild-bad.yaml samples/signer
    

    You see output like the following:

    "ERROR: (gcloud.builds.submit) build BUILD_ID completed with status "FAILURE"
    
  3. Save the build ID from the last build:

    export BUILD_ID=$(gcloud builds list --limit=1 --format="value('ID')")
    
  4. Verify the result:

     gsutil cat gs://${PROJECT_NUMBER}.cloudbuild-logs.googleusercontent.com/log-${BUILD_ID}.txt | grep "does not pass VulnzSigningPolicy"
    

Submit the success-case sample build

This example builds a container image that contains vulnerabilities that do not violate the vulnerability signing rules. The Kritis Signer custom builder creates an attestation.

To submit the success-case sample build to Cloud Build, do the following:

  1. (Optional) View the build configuration file for the success case

    cat samples/signer/cloudbuild-good.yaml
    
  2. Submit the build:

    gcloud builds submit \
      --substitutions=_KMS_KEY_NAME=$KMS_KEY_NAME,_KMS_DIGEST_ALG=$KMS_DIGEST_ALG,_NOTE_NAME=$NOTE_NAME \
      --config=samples/signer/cloudbuild-good.yaml samples/signer
    
  3. Save the build ID from the last build:

    export BUILD_ID=$(gcloud builds list --limit=1 --format="value('ID')")
    
  4. Verify the result:

    gcloud builds describe $BUILD_ID | grep status
    

Use Kritis Signer in check-only mode

This section shows you how to use Kritis Signer in check-only mode. In this mode, Kritis Signer does not create an attestation. It only checks the image for vulnerabilities before either succeeding or failing the build step based on the vulnerability signing rules.

Submit the failure-case sample build

  1. (Optional) View the build configuration file for the failure case.

    cat samples/policy-check/cloudbuild-bad.yaml
    

    In the Kritis Signer build step, note that the mode flag is set to check-only.

  2. Submit the build:

    gcloud builds submit \
      --substitutions=_KMS_KEY_NAME=$KMS_KEY_NAME,_KMS_DIGEST_ALG=$KMS_DIGEST_ALG,_NOTE_NAME=$NOTE_NAME \
      --config=samples/policy-check/cloudbuild-bad.yaml samples/policy-check
    

    Note that the build fails.

  3. Save the build ID from the last build:

    export BUILD_ID=$(gcloud builds list --limit=1 --format="value('ID')")
    
  4. Verify the result:

     gsutil cat gs://${PROJECT_NUMBER}.cloudbuild-logs.googleusercontent.com/log-${BUILD_ID}.txt | grep "does not pass VulnzSigningPolicy"
    

Submit the success-case sample build

  1. (Optional) View the build configuration file for the failure case.

    cat samples/policy-check/cloudbuild-good.yaml
    
  2. Submit the build:

    gcloud builds submit \
     --substitutions=_KMS_KEY_NAME=$KMS_KEY_NAME,_KMS_DIGEST_ALG=$KMS_DIGEST_ALG,_NOTE_NAME=$NOTE_NAME \
     --config=samples/policy-check/cloudbuild-good.yaml samples/policy-check
    
  3. Save the build ID from the last build:

    export BUILD_ID=$(gcloud builds list --limit=1 --format="value('ID')")
    
  4. Verify the result:

    gcloud builds describe $BUILD_ID | grep status
    

Clean up

To clean up resources used in this document, you can delete the project:

gcloud projects delete ${PROJECT_ID}

What's next