Vulnerability scanning integration with Kritis Signer

This guide explains how to create Binary Authorization attestations, based on Container Analysis vulnerability scanning, using Kritis Signer.

Overview of Kritis Signer

Software vulnerabilities are weaknesses that can either cause an accidental system failure or be intentionally exploited. Preventing vulnerable images from deploying is an important aspect of supply chain security.

Kritis Signer is an open source command line tool that can create Binary Authorization attestations based on CI/CD pipeline services, such as vulnerability scanning. You can use Kritis Signer as a Cloud Build custom builder to retrieve Container Analysis vulnerability scanning results and check the results against a vulnerability policy you configure.

If all of the identified vulnerabilities in the vulnerability results satisfy the vulnerability signing policy, Kritis Signer creates a Binary Authorization attestation for the associated image.

If any of the identified vulnerabilities in the vulnerability results violate the vulnerability policy, Kritis Signer does not create an attestation.

Without a verified attestation, the Binary Authorization enforcer denies the image from deploying.

Objectives

In this guide you will do the following:

  1. Set up Kritis Signer as a Cloud Build custom builder.
  2. View a vulnerability signing policy.
  3. Run the Kritis Signer custom builder to create attestations based on vulnerability scanning results.

Costs

This guide uses the following Google Cloud products. Costs may be incurred.

  • 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

where project-id is the ID of the Google Cloud project.

  1. Store the project number in an environment variable for future steps:

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

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

    gcloud --project=$PROJECT_ID services enable \
      cloudbuild.googleapis.com \
      containerregistry.googleapis.com \
      containeranalysis.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 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 repo:

     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 vulnerability signing policy.
    • Example Cloud Build configuration files. Each configuration file demonstrates a Kritis Signer-based 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 --project=$PROJECT_ID builds submit . --config deploy/kritis-signer/cloudbuild.yaml
    

View an existing vulnerability signing policy

This section shows an example Kritis Signer vulnerability signing policy.

Kritis Signer checks vulnerabilities identified by Container Analysis against this policy.

You can edit this policy to allowlist:

  • Qualified severity scores associated with identified vulnerabilities, as described in the CVSS Specification.
  • Specific vulnerabilities (CVEs).

To view the vulnerability signing policy:

cat samples/signer/policy.yaml

It should look 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 score of Critical, according to the CVSS Specification
    • HIGH: A score of High, according to the CVSS Specification
    • MEDIUM: A score of Medium, according to the CVSS Specification
    • LOW: A score of Low, according to the CVSS Specification
    • BLOCK_ALL: The attestation is not created if any vulnerability is identified.
    • ALLOW_ALL: The attestation is created even if vulnerabilities are identified.
  • 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 create the attestor and the attestation.

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

    gcloud --project=$PROJECT_ID kms keyrings create my-key-ring-1 \
       --location global
    
  2. Create a new Cloud KMS key called my-signing-key-1 within the key ring:

    gcloud --project=$PROJECT_ID kms keys create my-signing-key-1 \
        --keyring my-key-ring-1 \
        --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/my-key-ring-1/cryptoKeys/my-signing-key-1/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 repo. 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 policy.
    3. Creating the attestation if the findings satisfy the vulnerability policy.

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 policy. This build should fail.
  • Success case: In the second build, the vulnerability result should not violate the vulnerability signing policy. This build should succeed.

Submit the failure-case sample build

This example builds a container image based on Debian 9. At present, the container has a vulnerability that is not allowed by the vulnerability signing policy described above. 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 --project=$PROJECT_ID 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 should see output like the following:

    "ERROR: (gcloud.builds.submit) build build-id completed with status "FAILURE"
    
  3. Note Build ID in the build output.

    Set the $BUILD_ID environment variable to the build-id:

    export BUILD_ID=build-id
    

    This variable is used in the next step.

  4. Alternatively, you can find the build ID of your last build by running the following command:

    gcloud builds list --limit 1
    

    The build ID is the first returned field. Change the --limit value to see more builds, or remove the flag altogether to view all builds.

  5. 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 policy. The Kritis Signer custom builder should produce 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 --project=$PROJECT_ID 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. Again, make sure to note the build ID and store it in $BUILD_ID environment variable:

    export BUILD_ID=build-id
    
  4. Finally, to verify the result, enter the following command:

    gcloud --project=$PROJECT_ID builds describe $BUILD_ID | grep status
    

What's next