This page explains how to create a custom attestor in Binary Authorization by
using the [REST API](https://docs.cloud.google.com/binary-authorization/docs/reference/rest).

As an alternative, you can also perform these steps by using the
[Google Cloud CLI](https://docs.cloud.google.com/binary-authorization/docscreating-attestors-cli), or the
[Google Cloud console](https://docs.cloud.google.com/binary-authorization/docscreating-attestors-console). This
task is part of [setting up Binary Authorization](https://docs.cloud.google.com/binary-authorization/docssetting-up).

Cloud Build users: you can instead use the `built-by-cloud-build` attestor
to [deploy only images built by Cloud Build](https://docs.cloud.google.com/binary-authorization/docs/deploy-cloud-build).

## Overview

An [attestor](https://docs.cloud.google.com/binary-authorization/docs/key-concepts#attestors) is a Google Cloud resource that Binary Authorization
uses to verify an [attestation](https://docs.cloud.google.com/binary-authorization/docs/key-concepts#attestations). To learn more
about attestations, see the [Binary Authorization overview](https://docs.cloud.google.com/binary-authorization/docs/overview).

> [!NOTE]
> **Note:** Cloud Build users, you can use the `built-by-cloud-build` attestor to [deploy only images built by Cloud Build](https://docs.cloud.google.com/binary-authorization/docs/deploy-cloud-build) ([Preview](https://cloud.google.com/products#product-launch-stages)).

Creating an attestor requires you to do the following:

- Create a [note](https://docs.cloud.google.com/binary-authorization/docs/key-concepts#analysis_notes) in [Artifact Analysis](https://docs.cloud.google.com/artifact-analysis/docs/artifact-analysis) to store trusted metadata used in the attestation process.
- Set up a Public-Key Infrastructure (X.509) (PKIX) key pair that can be used to verify the identity of the attestor. (Asymmetric key pairs generated by [Cloud Key Management Service](https://docs.cloud.google.com/kms/docs) (Cloud KMS) are in PKIX-compatible format.) You can also use PGP key pairs instead of PKIX keys.
- Create the attestor itself in Binary Authorization, and associate the note and public key you created.

In a [single-project setup](https://docs.cloud.google.com/binary-authorization/docs/getting-started-cli), you create your attestor in
the same Google Cloud project where you configure your Binary Authorization
[policy](https://docs.cloud.google.com/binary-authorization/docs/key-concepts#policies). In a
[multi-project setup](https://docs.cloud.google.com/binary-authorization/docs/multi-project-setup-cli), you most likely have a
*deployer project* where your policy is configured and a separate
*attestor project* where your attestors are stored.

## Before you begin

1. [Enable Binary Authorization.](https://docs.cloud.google.com/binary-authorization/docs/enabling)

2. [Set up Binary Authorization for your platform.](https://docs.cloud.google.com/binary-authorization/docs/set-up-platform)

## Set the default project

Set the default Google Cloud project if you have not already done so:

```
PROJECT_ID=PROJECT_ID
gcloud config set project ${PROJECT_ID}
```

## Set up the environment

Set up environment variables to store your project names and numbers:

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

If your attestor and deployer project are the same project, use the same project
ID for both variables.

You must also get the service account names for the projects:

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

## Create an Artifact Analysis note

Binary Authorization uses
[Artifact Analysis](https://docs.cloud.google.com/artifact-analysis/docs/artifact-analysis) to
store trusted metadata used in the authorization process. For each attestor you
create, you must create one Artifact Analysis
[note](https://docs.cloud.google.com/binary-authorization/docs/key-concepts#analysis_notes). Each
[attestation](https://docs.cloud.google.com/binary-authorization/docs/key-concepts#attestations) is stored as an occurrence of this
note.

To create an Artifact Analysis note:

1. Set up environment variables to store the note ID and a human-readable
   description:

   ```
   NOTE_ID=NOTE_ID
   NOTE_URI="projects/${ATTESTOR_PROJECT_ID}/notes/${NOTE_ID}"
   DESCRIPTION=DESCRIPTION
   ```

   Replace the following:
   - <var translate="no">NOTE_ID</var> is the internal name of the note in alphanumeric characters with no spaces (for example, `test-attestor-note`)
   - <var translate="no">NOTE_URI</var> is the fully-qualified path to the note resource
   - <var translate="no">DESCRIPTION</var> is a human-readable display name for the note (for example, `Test Attestor Note`)
2. In a text editor, create a JSON file in `/tmp/note_payload.json` that
   describes the Artifact Analysis note:

   ```
   cat > /tmp/note_payload.json << EOM
   {
     "name": "${NOTE_URI}",
     "attestation": {
       "hint": {
         "human_readable_name": "${DESCRIPTION}"
       }
     }
   }
   EOM
   ```
3. Create the note by sending an HTTP request to the Artifact Analysis REST
   API:

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

   > [!CAUTION]
   > **Caution:** Binary Authorization doesn't support Artifact Analysis [regional
   > storage](https://docs.cloud.google.com/artifact-analysis/docs/locations) or [regional
   > endpoints](https://docs.cloud.google.com/artifact-analysis/docs/endpoints). We recommend that you use the Artifact Analysis global API endpoint (`https://containeranalysis.googleapis.com/`).

To verify that the note was created successfully, run the following command:

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

## Set permissions on the note

You must also set permissions on the Artifact Analysis note you
created so that it is accessible to the attestor project service account. You
do this by updating the IAM policy for the note to assign the
`containeranalysis.notes.occurrences.viewer` role to the account.

To set the permissions:

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': '${NOTE_URI}',
     '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)" \
       -H "x-goog-user-project: ${ATTESTOR_PROJECT_ID}" \
       --data-binary @/tmp/iam_request.json \
       "https://containeranalysis.googleapis.com/v1/projects/${ATTESTOR_PROJECT_ID}/notes/${NOTE_ID}:setIamPolicy"
   ```

   > [!NOTE]
   > When you add a role to the policy using the above method, it replaces any existing roles on the note. If you want to preserve existing roles, make sure that you are including them in the JSON data when you set the policy.

## Set up cryptographic keys

Binary Authorization allows you to use PKIX keys to
securely verify the identity of [signer](https://docs.cloud.google.com/binary-authorization/docs/key-concepts#signers) that created an
[attestation](https://docs.cloud.google.com/binary-authorization/docs/key-concepts#attestations). This ensures that only verified
parties can authorize a container image. As an alternative to PKIX, you can also
use PGP keys.

### Create a PKIX key pair

Binary Authorization allows you to use asymmetric
[PKIX key pairs](https://docs.cloud.google.com/kms/docs/creating-asymmetric-keys) to verify an
attestation. The key pair consists of a private key, which the
[signer](https://docs.cloud.google.com/binary-authorization/docs/key-concepts#signers) uses to digitally sign attestations, and a public
key, which you add to the attestor. Later, the Binary Authorization enforcer uses
the public key in the attestor to verify that the attestation was created by the
signer.

In this guide, the recommended
[Elliptic Curve Digital Signature Algorithm (ECDSA)](https://docs.cloud.google.com/kms/docs/algorithms#asymmetric_signing_algorithms)
is used to generate a PKIX key pair. You can also use RSA or PGP keys for
signing. See [Key purposes and algorithms](https://docs.cloud.google.com/kms/docs/algorithms) for more
information on signing algorithms.

The asymmetric key pairs generated and stored in
[Cloud KMS](https://docs.cloud.google.com/kms/docs) are compliant with the PKIX format. To create
a Cloud KMS key for use with Binary Authorization, see
[Creating Asymmetric Keys](https://docs.cloud.google.com/kms/docs/creating-asymmetric-keys). Make sure that
you choose **Asymmetric Sign** as the key purpose when you create the key.

### PKIX (Cloud KMS)

To create the key pair in Cloud KMS, do the following:

1. To set up environment variables needed to create the key pair, run the
   following commands:

       KMS_KEY_PROJECT_ID=KMS_KEY_PROJECT_ID
       KMS_KEY_LOCATION=KMS_KEY_LOCATION
       KMS_KEYRING_NAME=KMS_KEYRING_NAME
       KMS_KEY_NAME=KMS_KEY_NAME
       KMS_KEY_VERSION=KMS_KEY_VERSION
       KMS_KEY_PURPOSE=asymmetric-signing
       KMS_KEY_ALGORITHM=KMS_KEY_ALGORITHM
       KMS_PROTECTION_LEVEL=KMS_PROTECTION_LEVEL

   Replace the following:
   - `KMS_KEY_PROJECT_ID`: the ID of the project where the keys are stored.
   - `KMS_KEY_LOCATION`: the location of the key
   - `KMS_KEYRING_NAME`: the name of the key ring
   - `KMS_KEY_NAME`: the name of the key
   - `KMS_KEY_VERSION`: the key version
   - `KMS_KEY_ALGORITHM`: the algorithm; `ec-sign-p256-sha256` is recommended
   - `KMS_PROTECTION_LEVEL`: the protection level---for example, `software`
2. To create the keyring, run the following command:

       gcloud kms keyrings create ${KMS_KEYRING_NAME} \
           --location ${KMS_KEY_LOCATION}

3. To create the key, run the following command:

       gcloud kms keys create ${KMS_KEY_NAME} \
           --location ${KMS_KEY_LOCATION} \
           --keyring ${KMS_KEYRING_NAME}  \
           --purpose ${KMS_KEY_PURPOSE} \
           --default-algorithm ${KMS_KEY_ALGORITHM} \
           --protection-level ${KMS_PROTECTION_LEVEL}

### PKIX (local key)


> [!WARNING]
> **Warning:** We strongly recommend against using locally generated key pairs in production environments as they present a security risk. We recommend that you instead use Cloud Key Management Service. This example is provided for illustrative purposes only.

<br />

To generate a new local asymmetric PKIX key pair and store it in a file:

1. Generate the key:

   ```
   PRIVATE_KEY_FILE="/tmp/ec_private.pem"
   openssl ecparam -genkey -name prime256v1 -noout -out ${PRIVATE_KEY_FILE}
   ```
2. Since this file contains both a public and private key, you need to
   extract the public key into a separate file so you can add it to the
   attestor:

   ```
   PUBLIC_KEY_FILE="/tmp/ec_public.pem"
   openssl ec -in ${PRIVATE_KEY_FILE} -pubout -out ${PUBLIC_KEY_FILE}
   ```

## Create the attestor

The next step is to create the attestor itself in Binary Authorization with
the associated Artifact Analysis note. You must also add the
cryptographic public key.

To create the attestor:

1. Set up an environment variable to store the name of the attestor as defined
   in Binary Authorization:

   ```
   ATTESTOR_NAME=ATTESTOR_NAME
   ```

   where <var translate="no">ATTESTOR_NAME</var> is the name of the attestor you want to create
   (for example, `build-secure` or `prod-qa`).
2. Create the attestor and attach the public security key:

   ### PKIX (Cloud KMS)

   1. Set up additional environment variables to store information about
      the Cloud KMS key pair for the call to the Binary Authorization
      API.

      ```
      KMS_CRYPTO_KEY_URI="projects/${KMS_KEY_PROJECT_ID}/locations/${KMS_KEY_LOCATION}/keyRings/${KMS_KEYRING_NAME}/cryptoKeys/${KMS_KEY_NAME}"
      KMS_CRYPTO_KEY_VERSION_URI="${KMS_CRYPTO_KEY_URI}/cryptoKeyVersions/${KMS_KEY_VERSION}"
      KMS_KEY_ID="//cloudkms.googleapis.com/v1/${KMS_CRYPTO_KEY_VERSION_URI}"
      ```
   2. [Download](https://docs.cloud.google.com/kms/docs/retrieve-public-key) the public key file from
      Cloud KMS and save it to a file named
      `/tmp/kms_public_key.pem` on your local system.

   3. Generate a JSON file that contains the information needed to create
      the attestor:

      ```
      cat > /tmp/attestor.json << EOM
      {
          "userOwnedDrydockNote": {
              "noteReference": "${NOTE_URI}",
              "publicKeys": {
                  "id": "${KMS_KEY_ID}",
                  "pkixPublicKey": {
                      "signatureAlgorithm": "${KMS_KEY_ALGORITHM}",
                      "publicKeyPem": $( \
                          python < /tmp/kms_public_key.pem \
                          -c 'import json, sys; print(json.dumps(sys.stdin.read()))' \
                      )
                  }
              }
          }
      }
      EOM
      ```

      > [!NOTE]
      > The Python script embedded in the \`publicKeyPem\` field in the example above escapes newline characters in the \`.pem\` file, as appropriate newlines are required to parse the key.

   4. Create the attestor:

      ```
      curl -X POST  \
          -H "Content-Type: application/json" \
          -H "Authorization: Bearer $(gcloud auth print-access-token)" \
          -H "X-Goog-User-Project: ${ATTESTOR_PROJECT_ID}" \
          --data-binary @/tmp/attestor.json \
      "https://binaryauthorization.googleapis.com/v1/projects/${ATTESTOR_PROJECT_ID}/attestors?attestorId=${ATTESTOR_NAME}"
      ```

   ### PKIX (local key)

   1. Generate a JSON file that contains the information needed to create the attestor:

      ```
      cat > /tmp/attestor.json << EOM
      {
         "userOwnedGrafeasNote": {
             "noteReference": "${NOTE_URI}",
             "publicKeys": {
                 "pkixPublicKey": {
                     "signatureAlgorithm": "ecdsa_p256_sha256",
                     "publicKeyPem": $( \
                         python < ${PUBLIC_KEY_FILE} \
                         -c 'import json, sys; print(json.dumps(sys.stdin.read()))' \
                     )
                 }
             }
         }
      }
      EOM
      ```
   2. Create the attestor:

      ```
      curl -X POST  \
         -H "Content-Type: application/json" \
         -H "Authorization: Bearer $(gcloud auth print-access-token)" \
         -H "X-Goog-User-Project: ${ATTESTOR_PROJECT_ID}" \
         --data-binary @/tmp/attestor.json \
      "https://binaryauthorization.googleapis.com/v1/projects/${ATTESTOR_PROJECT_ID}/attestors?attestorId=${ATTESTOR_NAME}"
      ```
3. 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 the referenced attestor.

   Generate a JSON file that contains the information needed to set the IAM
   policy on your attestor:

   ```
   cat > /tmp/iam_request.json << EOM
   {
     'resource': 'projects/${ATTESTOR_PROJECT_ID}/attestors/${ATTESTOR_NAME}',
     'policy': {
       'bindings': [
         {
           'role': 'roles/binaryauthorization.attestorsVerifier',
           'members': [
             'serviceAccount:${DEPLOYER_SERVICE_ACCOUNT}'
           ]
         }
       ]
     }
   }
   EOM
   ```

   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)" \
       -H "x-goog-user-project: ${ATTESTOR_PROJECT_ID}" \
       --data-binary @/tmp/iam_request.json \
       "https://binaryauthorization.googleapis.com/v1beta1/projects/${ATTESTOR_PROJECT_ID}/attestors/${ATTESTOR_NAME}:setIamPolicy"
   ```

## Verify that the attestor was created

To verify that the attestor was created, run the following command:

```
curl \
    -H "Authorization: Bearer $(gcloud auth print-access-token)"  \
    -H "x-goog-user-project: ${ATTESTOR_PROJECT_ID}" \
    "https://binaryauthorization.googleapis.com/v1/projects/${ATTESTOR_PROJECT_ID}/attestors/"
```

## What's next

- Learn how to [create attestations](https://docs.cloud.google.com/binary-authorization/docs/making-attestations) for your attestor.
- Update your Binary Authorization policy to require attestations using the [Google Cloud console](https://docs.cloud.google.com/binary-authorization/docs/configuring-policy-console), the [Google Cloud CLI](https://docs.cloud.google.com/binary-authorization/docs/configuring-policy-cli), and the [REST API](https://docs.cloud.google.com/binary-authorization/docs/configuring-policy-rest).