Multi-project setup

You can setup Binary Authorization in your environment in a single-project configuration or a multi-project configuration. A multi-project configuration is suitable for most real-world uses of Binary Authorization, as it provides better resource and ACL isolation.

In this tutorial, you will set up a Binary Authorization configuration that consists of a deployer project, an attestor project and an attestation project. You will then configure your Binary Authorization policy and test a deployment.

Set up the deployer project

The first step is to set up your deployer project.

A deployer project manages the Google Kubernetes Engine (GKE) clusters where your images are deployed, as well as the Binary Authorization policy that governs deployment. You can have more than one deployer project, depending on the size, complexity, and other requirements of your environment.

To set up the deployer project:

  1. Create the project and enable billing in Google Cloud Platform Console if you have not already done so.

  2. Set environment variables to store the project name and number:

    DEPLOYER_PROJECT_ID=PROJECT_ID
    DEPLOYER_PROJECT_NUMBER=$(gcloud projects describe "${DEPLOYER_PROJECT_ID}" \
        --format="value(projectNumber)")
    

    where PROJECT_ID is the name of the project in Google Cloud Platform.

  3. Enable the Binary Authorization and GKE APIs:

    gcloud --project=${DEPLOYER_PROJECT_ID} \
        services enable \
        container.googleapis.com \
        binaryauthorization.googleapis.com
    
  4. Get the deployer project service account name:

    DEPLOYER_SERVICE_ACCOUNT="service-${DEPLOYER_PROJECT_NUMBER}@gcp-sa-binaryauthorization.iam.gserviceaccount.com"
    

    You use the service account name in a later step when you configure permissions on the Container Analysis note associated with your attestor.

Set up the attestor project

An attestor project stores the attestors that can verify that an image is ready for deployment. Often, you have a single attestor project that acts as a centralized store for information about trusted parties in the authorization process. This allows you to centrally manage security keys required to verify the identity of attestors and to restrict access to only those parties who administer them.

To set up the attestor project:

  1. Create the project and enable billing in Google Cloud Platform Console if you have not already done so.

  2. Set environment variables to store the project name and number:

    ATTESTOR_PROJECT_ID=PROJECT_ID
    ATTESTOR_PROJECT_NUMBER=$(gcloud projects describe "${ATTESTOR_PROJECT_ID}" \
        --format="value(projectNumber)")
    

    where PROJECT_ID is the name of the project in Google Cloud Platform.

  3. Enable the Container Analysis and Binary Authorization APIs:

    gcloud services --project=${ATTESTOR_PROJECT_ID} \
        enable containeranalysis.googleapis.com \
        binaryauthorization.googleapis.com
    
  4. Get the attestor project service account name:

    ATTESTOR_SERVICE_ACCOUNT="service-${ATTESTOR_PROJECT_NUMBER}@gcp-sa-binaryauthorization.iam.gserviceaccount.com"
    

    You use the service account name in a later step when you configure permissions on the Container Analysis note associated with your attestor.

Set up the attestations project

An attestation project is one that stores attestations that attestors make when they verify an image. A separate attestation project allows you to organize and inspect statements about software readiness more easily.

  1. Create the project and enable billing in Google Cloud Platform Console if you have not already done so.

  2. Set an environment variable to store the project name:

    ATTESTATION_PROJECT_ID=PROJECT_ID
    

    where PROJECT_ID is the name of the project in Google Cloud Platform.

  3. Enable the Container Analysis and Binary Authorization APIs:

    gcloud services --project=${ATTESTATION_PROJECT_ID} \
        enable containeranalysis.googleapis.com \
        binaryauthorization.googleapis.com
    

Create a cluster

Now you can create a GKE cluster in the deployer project. This is the cluster where you want your deployed container images to run. When you create the cluster, you pass the --enable-binauthz flag to the gcloud beta container clusters create command.

To create the cluster:

gcloud --project=${DEPLOYER_PROJECT_ID} \
    beta container clusters create \
    --enable-binauthz \
    --zone us-central1-a \
    test-cluster

Here, you create a cluster named test-cluster in the GKE zone us-central1-a.

You must also update the local kubeconfig file for your kubectl installation. This provides the credentials and endpoint information required to access the cluster in GKE.

To update the local kubeconfig file:

gcloud --project=${DEPLOYER_PROJECT_ID} \
    container clusters get-credentials \
    --zone us-central1-a \
    test-cluster

Create an attestor

An attestor is a party that is responsible for attesting that a required process has completed before a container image can be deployed. This party can be a human user or, more often, a machine process like a build and test system, or your continuous integration (CI) and deployment (CD) pipelines. You create attestors in your attestor project.

Creating an attestor requires you to:

  • Create a note in Container Analysis to store trusted metadata used in the authorization process
  • Create the attestor itself in the attestor project and associate the note you created
  • Add an IAM role binding for the deployer project service account to the attestor
  • Set permissions on the Container Analysis note

For this tutorial, you have one attestor named test-attestor and a Container Analysis note named test-attestor-note. In a real-world scenario, you can have any number of attestors, each one representing a party that participates in the authorization process for the image.

Create the Container Analysis note

  1. Set variables that store the name of your attestor and Container Analysis note:

    ATTESTOR=test-attestor
    NOTE_ID=test-attestor-note
    
  2. Create a JSON file in /tmp/note_payload.json that describes the Container Analysis note:

    cat > /tmp/note_payload.json << EOM
    {
      "name": "projects/${ATTESTOR_PROJECT_ID}/notes/${NOTE_ID}",
      "attestation": {
        "hint": {
          "human_readable_name": "Attestor Note"
        }
      }
    }
    EOM
    
  3. Create the note by sending an HTTP request to the Container Analysis REST API:

    curl -X POST \
        -H "Content-Type: application/json" \
        -H "Authorization: Bearer $(gcloud auth print-access-token)"  \
        --data-binary @/tmp/note_payload.json  \
        "https://containeranalysis.googleapis.com/v1/projects/${ATTESTOR_PROJECT_ID}/notes/?noteId=${NOTE_ID}"
    
  4. Verify that the note was created:

    curl \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    "https://containeranalysis.googleapis.com/v1/projects/${ATTESTOR_PROJECT_ID}/notes/${NOTE_ID}"
    

Create the attestor

Now, you can create the attestor:

  1. Create the attestor in Binary Authorization:

    gcloud --project=${ATTESTOR_PROJECT_ID} \
        beta container binauthz attestors create ${ATTESTOR} \
        --attestation-authority-note=${NOTE_ID} \
        --attestation-authority-note-project=${ATTESTOR_PROJECT_ID}
    
  2. Verify that the attestor was created:

    gcloud --project=${ATTESTOR_PROJECT_ID} \
        beta container binauthz attestors list
    

The attestor you created is not yet usable without an associated PGP key pair, which you create below.

Add an IAM role binding for the deployer project

You must add an IAM role binding for the deployer project to the attestor. This is used by Binary Authorization when it evaluates a policy to determine whether the project has permissions to access any associated attestations.

To add the IAM role binding:

gcloud --project ${ATTESTOR_PROJECT_ID} \
    beta container binauthz attestors add-iam-policy-binding \
    "projects/${ATTESTOR_PROJECT_ID}/attestors/${ATTESTOR}" \
    --member="serviceAccount:${DEPLOYER_SERVICE_ACCOUNT}" \
    --role=roles/binaryauthorization.attestorsVerifier

Set permissions on the Container Analysis note

You must also set permissions on the Container Analysis note you created so that it is accessible to both the deployer project and the attestor project. You do this by updating the IAM policy for the note to assign Viewer access to the project service accounts.

  1. Generate a JSON file that contains the information needed to set the IAM policy on your note.

    cat > /tmp/iam_request.json << EOM
    {
      'resource': 'projects/${ATTESTOR_PROJECT_ID}/notes/${NOTE_ID}',
      'policy': {
        'bindings': [
          {
            'role': 'roles/containeranalysis.notes.occurrences.viewer',
            'members': [
              'serviceAccount:${ATTESTOR_SERVICE_ACCOUNT}'
            ]
          }
        ]
      }
    }
    EOM
    
  2. Add the service account and requested access roles to the IAM policy for the note you created:

    curl -X POST  \
        -H "Content-Type: application/json" \
        -H "Authorization: Bearer $(gcloud auth print-access-token)" \
        --data-binary @/tmp/iam_request.json \
        "https://containeranalysis.googleapis.com/v1/projects/${ATTESTOR_PROJECT_ID}/notes/${NOTE_ID}:setIamPolicy"
    

Set up PGP keys

Binary Authorization uses cryptographic keys to securely verify the identity of attestors. This ensures that only verified parties can participate in the authorization of a container image. The key pair consists of a private key, which the attestor uses to digitally sign attestations, and a public key, which you add to the attestor as stored by the Binary Authorization service.

In this tutorial, you use PGP cryptographic keys. However, you can also use PKIX keys as an alternative. The asymmetric keys generated and stored by Cloud Key Management Service (Cloud KMS) are PKIX-compliant. See Creating attestors using the CLI for more information on using PKIX keys and Cloud KMS.

Generate a PGP key pair

First, generate the key pair:

  1. Run gpg --gen-key from the command line:

    gpg --batch --gen-key <(
      cat <<- EOF
        Key-Type: RSA
        Key-Length: 2048
        Name-Real: "Test Attestor"
        Name-Email: "test-attestor@example.com"
        %commit
    EOF
    )
    
  2. Find the fingerprint for the PGP public key:

    gpg --list-keys "test-attestor@example.com"
    

    This command prints:

    pub   rsa2048 2018-07-05 [SCEA]
          PUBLIC_KEY_FINGERPRINT
    uid           [ultimate] "Test Attestor" <"attestor@example.com">
    

    where PUBLIC_KEY_FINGERPRINT is the version 4, full 160-bit fingerprint, expressed as a 40 character hexidecimal string, such as ABAB2098B3F5F05FF0D12ABE45895BDDDCD17B90. See the OpenPGP RFC for more information on PGP fingerprints.

  3. Set a variable that stores the fingerprint:

    FINGERPRINT=PUBLIC_KEY_FINGERPRINT
    
  4. Export the public key:

    gpg --armor --export ${FINGERPRINT} > /tmp/generated-key.pgp
    

The exported public key is located in /tmp/generated-key.pgp. The private key is stored on the local system where you ran the gpg --gen-key command.

Add the PGP public key to the attestor

Now, add the public key you exported to the attestor so that it can be used by Binary Authorization for identity verification:

gcloud --project=${ATTESTOR_PROJECT_ID} \
    beta container binauthz attestors public-keys add \
    --attestor=${ATTESTOR} \
    --public-key-file=/tmp/generated-key.pgp

Configure the policy

Now, you can configure your policy in the deployer project. In this step, you export the policy YAML file to your local system and modify the default rule so that it requires an attestation by the attestor you defined above.

To configure the policy:

  1. Create a new policy file that sets the evaluationMode to REQUIRE_ATTESTATION and adds a node named requireAttestationsBy that references the attestor you created:

    cat > /tmp/policy.yaml << EOM
        admissionWhitelistPatterns:
        - namePattern: gcr.io/google_containers/*
        - namePattern: gcr.io/google-containers/*
        - namePattern: k8s.gcr.io/*
        - namePattern: gcr.io/stackdriver-agents/*
        defaultAdmissionRule:
          evaluationMode: REQUIRE_ATTESTATION
          enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
          requireAttestationsBy:
            - projects/${ATTESTOR_PROJECT_ID}/attestors/${ATTESTOR}
        name: projects/${DEPLOYER_PROJECT_ID}/policy
    EOM
    
  2. Import the policy YAML file into Binary Authorization:

    gcloud --project=${DEPLOYER_PROJECT_ID} \
        beta container binauthz policy import /tmp/policy.yaml
    

For more information on configuring a policy, see Configuring a Policy Using the CLI.

Test the policy

You can test the policy you configured above by trying to deploy a sample container image to the cluster. The policy will block deployment because the required attestation has not been made.

For this tutorial, you can use the sample image located at the path gcr.io/google-samples/hello-app in Container Registry. This is a public container image created by Google that contains a Hello, World! sample application.

To try to deploy the image:

kubectl run hello-server --image gcr.io/google-samples/hello-app:1.0 --port 8080

Now, verify that the deployment was blocked by Binary Authorization:

kubectl get pods

The command prints the following message, which indicates that the image was not deployed:

No resources found.

You can get further details about the deployment:

kubectl get event --template \
'{{range.items}}{{"\033[0;36m"}}{{.reason}}:{{"\033[0m"}}\{{.message}}{{"\n"}}{{end}}'

which shows that the deployment was disallowed by the policy:

FailedCreate: Error creating: pods "hello-server-579859fb5b-hjvnr" is forbidden: image policy webhook backend denied one or more images: Denied by default admission rule. Denied by Attestation Authority. Image gcr.io/google-samples/hello-app:1.0 denied by projects/example-project/attestors/test-attestor: No attestations found

Make sure to delete the deployment so you can continue to the next step:

kubectl delete deployment hello-server

Create an attestation

An attestation is a statement by an attestor that a required process in your pipeline has been completed and that the container image in question is authorized for deployment. The attestation itself is a digitally-signed record that contains the full path to a version of the image as stored your container image registry, as well as the identity of the attestor.

In this tutorial, your attestation simply states that you authorize the image for deployment. You create the attestation in the attestation project.

To create an attestation:

  1. Set variables that store the registry path and digest of the image:

    IMAGE_PATH="gcr.io/google-samples/hello-app"
    IMAGE_DIGEST="sha256:c62ead5b8c15c231f9e786250b07909daf6c266d0fcddd93fea882eb722c3be4"
    
  2. Generate the attestation payload:

    gcloud --project=${ATTESTATION_PROJECT_ID} \
        beta container binauthz create-signature-payload \
        --artifact-url=${IMAGE_PATH}@${IMAGE_DIGEST} > /tmp/generated_payload.json
    

    The payload JSON file has the following contents:

    {
      "critical": {
        "identity": {
          "docker-reference": "gcr.io/google-samples/hello-app"
        },
        "image": {
          "docker-manifest-digest": "sha256:c62ead5b8c15c231f9e786250b07909daf6c266d0fcddd93fea
    882eb722c3be4"
        },
        "type": "Google cloud binauthz container signature"
      }
    }
    
  3. Sign the payload with your PGP private key and output a signature file:

    gpg \
        --local-user "test-attestor@example.com" \
        --armor \
        --output /tmp/generated_signature.pgp \
        --sign /tmp/generated_payload.json
    

    The signature file is a digitally-signed version of the payload JSON file you created above.

  4. Create the attestation:

    gcloud --project=${ATTESTATION_PROJECT_ID} \
        beta container binauthz attestations create \
        --artifact-url="${IMAGE_PATH}@${IMAGE_DIGEST}" \
        --attestor="projects/${ATTESTOR_PROJECT_ID}/attestors/${ATTESTOR}" \
        --signature-file=/tmp/generated_signature.pgp \
        --public-key-id="${FINGERPRINT}"
    

    where FINGERPRINT is the public key fingerprint that you found in Generate a PGP key pair above.

  5. Verify that the attestation was created:

    gcloud --project=${ATTESTATION_PROJECT_ID} \
        beta container binauthz attestations list \
        --attestor=$ATTESTOR --attestor-project=$ATTESTOR_PROJECT_ID
    

For more information on creating attestations, see Creating Attestations.

Retest the policy

Again, test the policy by deploying a sample container image to the cluster. This time, you must deploy the image using the digest rather than a tag like 1.0 or latest, as Binary Authorization will use both the image path and digest to look up attestations. Here, Binary Authorization allows the image to be deployed because the required attestation has been made.

To deploy the image:

kubectl run hello-server --image ${IMAGE_PATH}@${IMAGE_DIGEST} --port 8080

To verify that the image was deployed:

kubectl get pods

The command prints a message similar to the following, which indicates that deployment was successful:

NAME                            READY     STATUS    RESTARTS   AGE
hello-server-579859fb5b-h2k8s   1/1       Running   0          1m

Now that you have successfully deployed the container image and verified that your setup is working, you can delete the cluster you created in GKE:

gcloud --project=${DEPLOYER_PROJECT_ID} \
    container clusters delete \
    --zone=us-central1-a \
    test-cluster
Was this page helpful? Let us know how we did:

Send feedback about...

Binary Authorization Documentation