Create attestations with Voucher

This tutorial describes how to set up and use Voucher to create Binary Authorization attestations.

Overview of Voucher

Voucher is an open source tool that runs a suite of checks on container images before creating Binary Authorization attestations for the images. Voucher has a client and a server component. You run Voucher Client as an added step within your build pipeline, after the step that builds the image. When the Voucher Client build step runs, it submits the image to Voucher Server, which performs the checks. You define which checks Voucher runs, along with other criteria, in the Voucher Server configuration file.

This tutorial shows how to use the Voucher snakeoil check to test for vulnerabilities in images. You enable the check in the configuration file by setting the fail-on option to a vulnerability threshold, as shown later in this tutorial.

After the snakeoil check completes, if all of the identified vulnerabilities fall below the threshold, Voucher Server creates the Binary Authorization attestation for the image. If any of the identified vulnerabilities meet or exceed the threshold, Voucher Server does not create an attestation.

At container image deploy time, without a verified attestation, the Binary Authorization enforcer disallows the image from being deployed.

Objectives

In this guide you do the following:

  1. Set up Voucher Server in Cloud Run.
  2. Set up Voucher Client.
  3. Use Voucher in example build pipelines.

Costs

This guide uses the following Google Cloud products.

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

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

Before you begin

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. Make sure that billing is enabled for your Google Cloud project.

  4. Enable the Cloud Build, Container Registry, Artifact Analysis, Cloud KMS, Cloud Run, and Identity and Access Management APIs.

    Enable the APIs

  5. Install the Google Cloud CLI.
  6. To initialize the gcloud CLI, run the following command:

    gcloud init
  7. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  8. Make sure that billing is enabled for your Google Cloud project.

  9. Enable the Cloud Build, Container Registry, Artifact Analysis, Cloud KMS, Cloud Run, and Identity and Access Management APIs.

    Enable the APIs

  10. Install the Google Cloud CLI.
  11. To initialize the gcloud CLI, run the following command:

    gcloud init
  12. We recommend that you set up Binary Authorization with Google Kubernetes Engine. This tutorial describes how to create an attestation. In order to use deploy-time enforcement to verify the attestation and deploy the associated image, Binary Authorization must be set up. Make sure you configure the policy to require attestations. You can configure the policy in Google Cloud console or at the command line.
  13. Specify your Google Cloud project in an environment variable.

      export PROJECT_ID=PROJECT_ID
    

    Replace PROJECT_ID with your project ID.

  14. Set the project ID for gcloud commands:

    gcloud config set project ${PROJECT_ID}

  15. Specify the project number in an environment variable for future steps:

    export PROJECT_NUMBER=$(gcloud projects describe "${PROJECT_ID}" \
      --format='value(project_number)')

Set up Voucher Server

In the following steps you set up Voucher Server.

Create a Cloud Key Management Service signing key

In this section you create the key that Voucher Server uses to create a Binary Authorization attestation.

  1. Create a key ring:

    gcloud kms keyrings create KEY_RING\
       --location global
    

    Replace KEY_RING with a key ring name, such as voucher-key-ring.

  2. Create a signing key:

    gcloud kms keys create KEY_NAME \
      --keyring KEY_RING \
      --location global \
      --purpose "asymmetric-signing" \
      --default-algorithm "rsa-sign-pkcs1-4096-sha512"
    

    Replace KEY_NAME with the name a key name, such as voucher-key.

  3. Store the Cloud Key Management Service key version resource ID:

    export KMS_RESOURCE_ID=projects/$PROJECT_ID/locations/global/keyRings/KEY_RING/cryptoKeys/KEY_NAME/cryptoKeyVersions/1
    
  4. Grant the cloudkms.signer role to the Compute Engine runtime engine service account.

    In this step, you grant the cloudkms.signer role to the service account that runs Voucher Server. This enables Voucher Server to sign attestations with Cloud Key Management Service keys. To do this, execute the following command:

    gcloud kms keys add-iam-policy-binding\
      KEY_NAME --keyring=KEY_RING\
      --location=global\
      --member=serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com\
      --role=roles/cloudkms.signer
    

Create the Artifact Analysis note

In this section you create the note.

  1. Store the note ID:

    export NOTE_ID=snakeoil
    
  2. Store the note URI:

    export NOTE_URI=projects/$PROJECT_ID/notes/$NOTE_ID
    
  3. Create request payload:

    cat > /tmp/note_payload.json << EOM
    {
      "name": "${NOTE_URI}",
      "attestation": {
        "hint": {
          "human_readable_name": "voucher note for snakeoil check"
        }
      }
    }
    EOM
    
  4. Create the note:

    curl -X POST \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer $(gcloud --project ${PROJECT_ID} auth print-access-token)"  \
      -H "x-goog-user-project: ${PROJECT_ID}" \
      --data-binary @/tmp/note_payload.json  \
    "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/?noteId=${NOTE_ID}"
    

Build and configure Voucher Server

In this one-time setup, you get, configure and build the Voucher Server image. You then store it in Container Registry.

  1. Clone the Voucher repository:

    git clone https://github.com/grafeas/voucher.git
    cd voucher/
    

    This repository contains:

    • Source code to build Voucher Server.
    • Source code to build Voucher Client.
    • Examples that demonstrate using Voucher.
  2. Update the Voucher Server configuration file.

    Linux

    Create the Voucher Server configuration file from a template, replacing and with values you defined above. You do this by executing the following command:

     cat tutorials/cloudrun/config.toml.template \
        | sed -e "s?<PROJECT_ID>?${PROJECT_ID}?g" \
        | sed -e "s?<KMS_KEY_NAME>?${KMS_RESOURCE_ID}?g" \
          > tutorials/cloudrun/config.toml
    

    Other OS

    1. Edit the file tutorials/cloudrun/config.toml.template.

      • Replace <PROJECT_ID> with the value in ${PROJECT_ID}.
      • Replace <KMS_KEY_NAME> with the value in ${KMS_RESOURCE_ID}.
    2. Save the file as tutorials/cloudrun/config.toml.

  3. View the Voucher Server configuration file:

    cat tutorials/cloudrun/config.toml
    

    You see output containing the following:

    failon = "high"
    

    Note that in the configuration file, the failon option is set to high. This setting configures Voucher Server to perform a vulnerability check on an image. If the image contains vulnerabilities with severity of HIGH, the check fails and Voucher Server does not create the Binary Authorization attestation. For more information on fail-on settings, see Fail-On: Failing on vulnerabilities.

  4. Build and upload the Voucher Server container image:

    In this section you run the Cloud Build pipeline that builds the Voucher Server container image. The build also uploads the Voucher Server image to gcr.io/$PROJECT_ID/voucher-server.

    gcloud  builds submit --config ./tutorials/cloudrun/cloudbuild-server.yaml
    

Deploy Voucher Server on Cloud Run

  1. Select a region.

    To view a list of available regions, see Viewing a list of available regions. Create a variable to store your selected region:

    export REGION=REGION
    

    Replace REGION with the name of the region in which you plan to deploy your Voucher Server.

  2. Deploy Voucher Server on Cloud Run.

    gcloud run deploy --image gcr.io/${PROJECT_ID}/voucher-server \
      --platform managed voucher-server \
      --region ${REGION} \
      --no-allow-unauthenticated
    

    You see output like the following:

    Service [voucher-server] revision [voucher-server-00001-caw] has been deployed and is serving 100 percent of traffic.
    Service URL: https://voucher-server-4wjtm2amga-uc.a.run.app
    
  3. Store the Voucher Server service URL:

    export SERVER_SERVICE_URL=$(gcloud run services describe voucher-server --platform managed --region ${REGION} --format='value(status.url)')
    

Set up Voucher Client

In the following steps you set up Voucher Client.

  1. Create the invoker service account for Voucher Client:

    gcloud iam service-accounts create INVOKER_ACCOUNT_NAME
    

    Replace INVOKER_ACCOUNT_NAME with a name for the invoker service account, such as voucher-invoker.

  2. Specify the service account:

    export INVOKER_SERVICE_ACCOUNT=INVOKER_ACCOUNT_NAME@$PROJECT_ID.iam.gserviceaccount.com
    
  3. Grant the run.invoker role to the invoker service account for your project.

    Grant your invoker service account permission to invoke the Voucher Server on Cloud Run. To do this, enter the following command:

    gcloud run services add-iam-policy-binding voucher-server \
      --member serviceAccount:$INVOKER_SERVICE_ACCOUNT \
      --role roles/run.invoker \
      --platform managed \
      --region ${REGION}
    
  4. Grant the iam.serviceAccountTokenCreator role to the invoker service account for Cloud Build.

    In this section, you grant the Cloud Build service account permission to impersonate the invoker service account so that Voucher Client has permission to send requests to Voucher Server during the build. To do this, enter the following command:

    gcloud iam service-accounts add-iam-policy-binding $INVOKER_SERVICE_ACCOUNT \
      --member=serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com \
      --role=roles/iam.serviceAccountTokenCreator
    

Use Voucher to check images for vulnerabilities

In this section, you run two example Cloud Build pipelines. In both pipelines, you build an image and then use Voucher to check it for vulnerabilities.

Failure case

In this section the example build pipeline fails to create an attestation. The image you build-based on Debian 9-contains at least one vulnerability of severity HIGH. The fail-on option in the Voucher Server config.toml is set to fail on HIGH severity vulnerabilities. In this case, Voucher Server does not create a Binary Authorization attestation.

  1. Run the build pipeline:

    gcloud builds submit \
      --substitutions=_SERVICE_URL=$SERVER_SERVICE_URL,_SERVICE_ACCOUNT=$INVOKER_SERVICE_ACCOUNT \
      --config=tutorials/cloudrun/examples/cloudbuild-bad.yaml tutorials/cloudrun/examples
    
  2. Search the log from the last build for Voucher snakeoil findings:

    Console

    1. Note the build ID from the last build.

    2. In the Google Cloud console, go to the Build History page.

      Go to Build History

    3. Under Build, click the item that contains the first few characters of the build ID.

    4. Click View Raw.

    5. Search for snakeoil using your browser.

      You see output like the following:

      "name":"snakeoil","error":"vulnerable to 14 vulnerabilities"
      

    gcloud

    1. Save the build ID from the build:

      export BUILD_ID=$(gcloud builds list --limit=1 --format="value('ID')")
      
    2. Search your build log by entering the following command:

       gcloud builds log ${BUILD_ID} | grep "snakeoil"
      

      The output looks like the following:

      "name":"snakeoil","error":"vulnerable to 14 vulnerabilities"
      

Success case

In this section, the example build pipeline succeeds in creating an attestation. All of the identified vulnerabilities are classified lower than the fail-on threshold so the check passes the pipeline creates the attestation.

  1. Run the pipeline:

    gcloud builds submit\
      --substitutions=_SERVICE_URL=$SERVER_SERVICE_URL,_SERVICE_ACCOUNT=$INVOKER_SERVICE_ACCOUNT\
      --config=tutorials/cloudrun/examples/cloudbuild-good.yaml tutorials/cloudrun/examples
    
  2. Search the log from the last build for Voucher snakeoil findings:

    Console

    1. Note the build ID from the last build.

    2. In the Google Cloud console, go to the Build History page.

      Go to Build History

    3. Under Build, click the item that contains the first few characters of the build ID.

    4. Click View Raw.

    5. Search for snakeoil using your browser.

      You see output like the following:

      "name":"snakeoil","success":true,"attested":true
      

    gcloud

    1. Save the build ID from the last build:

      export BUILD_ID=$(gcloud builds list --limit=1 --format="value('ID')")
      
    2. Search your build log by entering the following command:

       gcloud builds log ${BUILD_ID} | grep "snakeoil"
      

      The output looks like the following:

      "name":"snakeoil","success":true,"attested":true
      

Clean up

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

gcloud projects delete ${PROJECT_ID}

Create an attestor

To create a policy that requires the attestations that you create using the method described in this guide, you must first create an attestor.

To create an attestor, do the following:

  1. Retrieve the public key material from the Cloud KMS key that you created earlier in this guide:

    gcloud kms keys versions get-public-key 1 \
    --key KEY_NAME \
    --keyring KEY_RING \
    --location global \
    --output-file OUTPUT_PATH
    
    • KEY_NAME: the key name
    • KEY_RING: the key ring name
    • OUTPUT_PATH: a file path—for example, my-key.pem
  2. Create an attestor by using the public key material in the file and the note that you created earlier in this guide. You can create an attestor through the Google Cloud console or the gcloud CLI.

  3. Create a policy that requires attestations and supply the attestor that you created in this section. You can create a policy through the Google Cloud console or the gcloud CLI

Create an attestation

To create an attestation using your attestor, see Create an attestation using Cloud KMS.

What's next