创建证明

本页面介绍了创建 Binary Authorization 证明的步骤。

您可以使用证明来授权要在 Google Kubernetes Engine (GKE) 和 Cloud Run 等平台上部署的特定容器映像。如需使用证明,您必须在政策的相应规则中要求提供证明。

单个证明可以授权存储在多个不同位置或不同注册表(例如 Artifact RegistryContainer Registry 或外部容器注册表)中的相同映像。

在部署时,Binary Authorization 会使用证明者来验证证明。

如需在 Cloud Run、GKE、Google Distributed Cloud 和 Cloud Service Mesh 上设置 Binary Authorization,请参阅按平台设置并选择您的平台。

GKE 用户:如需查看描述如何使用 Binary Authorization 和 Google Kubernetes Engine (GKE) 实现基于证明的强制执行的端到端教程,请参阅命令行工具使用入门Google Cloud 控制台使用入门

准备工作

证明概览介绍了在创建证明之前需要完成的步骤。

  1. 启用 Binary Authorization

  2. 使用 Google Cloud 控制台Google Cloud CLIREST API 创建证明者。

设置环境

  1. 指定项目 ID:

    ATTESTOR_PROJECT_ID=ATTESTOR_PROJECT_ID
    ATTESTATION_PROJECT_ID=ATTESTATION_PROJECT_ID
    

    替换以下内容:

    • ATTESTOR_PROJECT_ID:您要在其中存储证明者的项目的名称
    • ATTESTATION_PROJECT_ID:您要在其中存储证明的项目的名称

    如果您希望在证明者所在的项目中创建证明,请对这两个变量使用同一项目 ID。如需查看演示如何使用不同项目实现职责分离的端到端教程,请参阅多项目设置

  2. 指定证明者名称和映像信息:

    ATTESTOR_NAME=ATTESTOR_NAME
    IMAGE_PATH=IMAGE_PATH
    IMAGE_DIGEST=IMAGE_DIGEST
    IMAGE_TO_ATTEST="${IMAGE_PATH}@${IMAGE_DIGEST}"
    

    替换以下内容:

    • ATTESTOR_NAME:证明者的名称,例如 build-secureprod-qa
    • IMAGE_PATH:表示映像路径的 URI。虽然 URI 必须包含域名和映像名称,但它并不需要引用实际的映像。在创建证明期间,系统不会访问映像。下面是一些映像路径的示例:

      • us-docker.pkg.dev/google-samples/containers/gke/hello-app
      • gcr.io/example-project/quickstart-image
      • example.com/hello-app
    • IMAGE_DIGEST:映像清单的摘要。例如,sha256:37e5287945774f27b418ce567cd77f4bbc9ef44a1bcd1a2312369f31f9cce567 是与示例 us-docker.pkg.dev/google-samples/containers/gke/hello-app 映像路径关联的映像摘要。如需了解如何在 Artifact Registry 中获取映像摘要,请参阅管理映像;如需查看 Container Registry 中的映像,请参阅列出映像版本

授予 Identity and Access Management 角色

如需创建证明,您必须将以下 Identity and Access Management (IAM) 角色授予给创建证明者的身份,如下所示:

  • 与证明者关联的备注资源上的 roles/containeranalysis.notes.attacher 角色。
  • 证明项目资源上的 roles/containeranalysis.occurrences.editor 角色。

您可以根据证明者创建证明。证明者与 Artifact Analysis 备注相关联。创建证明后,系统会创建一个 Artifact Analysis 发生实例并将其附加到备注。

详细了解如何授予访问权限

如需了解如何在 Cloud Build 流水线中创建证明,请参阅使用 Kritis Signer 创建证明

创建证明

创建使用本地存储密钥的证明

如需创建使用本地密钥签名的证明,请执行以下操作:

  1. 创建签名载荷文件:

    gcloud

    如需创建签名载荷文件,请输入以下命令:

    gcloud container binauthz create-signature-payload \
        --artifact-url="${IMAGE_TO_ATTEST}" > /tmp/generated_payload.json
    

    JSON 格式的载荷文件类似于以下输出:

    {
      "critical": {
        "identity": {
          "docker-reference": "us-docker.pkg.dev/google-samples/containers/gke/hello-app"
        },
        "image": {
          "docker-manifest-digest": "sha256:37e5287945774f27b418ce567cd77f4bbc9ef44a1bcd1a2312369f31f9cce567"
        },
        "type": "Google cloud binauthz container signature"
      }
    }
    

    REST API

    使用您在本文档前面部分设置的环境变量创建名为 /tmp/generated_payload.json 的载荷文件:

    cat > /tmp/generated_payload.json << EOM
    {
      "critical": {
        "identity": {
          "docker-reference": "${IMAGE_PATH}"
        },
        "image": {
          "docker-manifest-digest": "${IMAGE_DIGEST}"
        },
        "type": "Google cloud binauthz container signature"
      }
    }
    EOM
    
  2. 使用私钥对载荷签名以生成签名文件。

    本指南使用推荐的椭圆曲线数字签名算法 (ECDSA) 算法进行签名。您还可以使用 RSA 算法。如需详细了解签名算法,请参阅密钥用途和算法。本指南还使用公钥基础架构 (X.509) (PKIX) 签名格式。您还可以使用 PGP。

    PRIVATE_KEY_FILE=PRIVATE_KEY_FILE
    openssl dgst -sha256 -sign ${PRIVATE_KEY_FILE} /tmp/generated_payload.json > /tmp/ec_signature
    

    PRIVATE_KEY_FILE 替换为您在创建证明者时生成的私钥的路径。

  3. 获取公钥 ID。

    您可以通过输入以下命令从证明者中检索公钥 ID:

    PUBLIC_KEY_ID=$(gcloud container binauthz attestors describe ${ATTESTOR_NAME} \
      --format='value(userOwnedGrafeasNote.publicKeys[0].id)')
    
  4. 创建证明:

    gcloud

    如需创建和验证证明,请输入以下命令:

    gcloud container binauthz attestations create \
        --project="${ATTESTATION_PROJECT_ID}" \
        --artifact-url="${IMAGE_TO_ATTEST}" \
        --attestor="projects/${ATTESTOR_PROJECT_ID}/attestors/${ATTESTOR_NAME}" \
        --signature-file=/tmp/ec_signature \
        --public-key-id="${PUBLIC_KEY_ID}" \
        --validate
    

    validate 标志用于检查证明是否可由您在政策中配置的证明者进行验证。

    注意:密钥 ID 可以是任何字符串。

    REST API

    如需创建证明,请执行以下操作:

    1. 检索与证明关联的证明者并提取存储的公钥 ID:

      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/"
      

      Binary Authorization 会返回类似于以下内容的 JSON 对象:

      {
        "name": "projects/example-project/attestors/test-attestor",
        "userOwnedGrafeasNote": {
          "noteReference": "projects/example-project/notes/test-attestor",
          "publicKeys": [
            {
              "id": "ni:///sha-256;EwVxs8fNUAHq9FI2AMfh8WNIXVBuuTMeGtPH72U-I70",
              "pkixPublicKey": {
                "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXnpuYEfvLl1kj4fjxViFRwY1a+zC\n5qzlf9LJIK+rnjq42tiKGyyXMbnZKJiYPPdMDGyltnkrABnztg2jJ48aYQ==\n-----END PUBLIC KEY-----\n",
                "signatureAlgorithm": "ECDSA_P256_SHA256"
              }
            }
          ],
          "delegationServiceAccountEmail": "service-363451293945@gcp-sa-binaryauthorization.iam.gserviceaccount.com"
        },
        "updateTime": "2019-06-26T16:58:33.977438Z"
      }
      

      公钥可在 id 字段中找到。

    2. /tmp/attestation.json 中创建一个描述该证明的 JSON 文件:

      cat > /tmp/attestation.json << EOM
      {
        "resourceUri": "${IMAGE_TO_ATTEST}",
        "note_name": "${NOTE_URI}",
        "attestation": {
           "serialized_payload": "$(base64 --wrap=0 /tmp/generated_payload.json)",
           "signatures": [
              {
               "public_key_id": "${PUBLIC_KEY_ID}",
               "signature": "$(base64 --wrap=0 /tmp/ec_signature)"
              }
           ]
        }
       }
      EOM
      
    3. 创建证明:

      curl -X POST \
          -H "Content-Type: application/json" \
          -H "X-Goog-User-Project: ${ATTESTATION_PROJECT_ID}" \
          -H "Authorization: Bearer $(gcloud auth print-access-token)" \
          --data-binary @/tmp/attestation.json \
          "https://containeranalysis.googleapis.com/v1/projects/${ATTESTATION_PROJECT_ID}/occurrences/"
      

使用 Cloud KMS 创建证明

如需使用 Cloud Key Management Service 创建证明,请执行以下操作:

  1. 创建环境变量:

    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_PROJECT_ID:在其中存储 Cloud Key Management Service 密钥的项目的 ID
    • KMS_KEY_LOCATION:密钥的位置(默认为 global
    • KMS_KEYRING_NAME:密钥环的名称
    • KMS_KEY_NAME:密钥的名称
    • KMS_KEY_VERSION:密钥版本
  2. 对证明签名并创建证明:

    gcloud

    输入以下命令:

    gcloud beta container binauthz attestations sign-and-create \
        --project="${ATTESTATION_PROJECT_ID}" \
        --artifact-url="${IMAGE_TO_ATTEST}" \
        --attestor="${ATTESTOR_NAME}" \
        --attestor-project="${ATTESTOR_PROJECT_ID}" \
        --keyversion-project="${KMS_KEY_PROJECT_ID}" \
        --keyversion-location="${KMS_KEY_LOCATION}" \
        --keyversion-keyring="${KMS_KEYRING_NAME}" \
        --keyversion-key="${KMS_KEY_NAME}" \
        --keyversion="${KMS_KEY_VERSION}"
    

    REST API

    1. 使用您在上文中设置的环境变量创建名为 /tmp/generated_payload.json 的载荷文件:

      cat > /tmp/generated_payload.json << EOM
      {
        "critical": {
          "identity": {
            "docker-reference": "${IMAGE_PATH}"
          },
          "image": {
            "docker-manifest-digest": "${IMAGE_DIGEST}"
          },
          "type": "Google cloud binauthz container signature"
        }
      }
      EOM
      
    2. 对载荷文件签名:

      curl \
        --header "Content-Type: application/json" \
        --header "Authorization: Bearer $(gcloud auth print-access-token)" \
        --header "x-goog-user-project: ${ATTESTOR_PROJECT_ID}" \
        --data '{"digest":  {"DIGEST_ALGORITHM": "'$(openssl dgst -sha256 -binary /tmp/generated_payload.json | openssl base64)'" }}' \
      https://cloudkms.googleapis.com/v1/projects/${KMS_KEY_PROJECT_ID}/locations/${KMS_KEY_LOCATION}/keyRings/${KMS_KEYRING_NAME}/cryptoKeys/${KMS_KEY_NAME}/cryptoKeyVersions/${KMS_KEY_VERSION}:asymmetricSign?alt=json
      

      DIGEST_ALGORITHM 替换为用于提取输入摘要的算法。本指南中的示例使用 sha256 摘要。您可以使用 sha256sha384sha512

      在此示例中,输出类似于以下内容:

      {
        "signature": "<var>SIGNATURE</var>": "996305066",
        "name": "projects/<var>KMS_KEY_PROJECT_ID</var>/locations/<var>KMS_KEY_LOCATION</var>/keyRings/<var>KMS_KEYRING_NAME</var>/cryptoKeys/<var>KMS_KEY_NAME</var>/cryptoKeyVersions/<var>KMS_KEY_VERSION</var>"
      }
      

      在此输出中,SIGNATURE 是载荷文件的 base64 编码签名。

    3. 将签名存储在环境变量中:

      PAYLOAD_SIGNATURE=PAYLOAD_SIGNATURE
      
    4. 检索您要代表其对证明签名的证明者,并提取存储的公钥 ID 和备注 ID:

      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/"
      

      Binary Authorization 会返回类似于以下内容的 JSON 对象:

      {
        "name": "projects/example-project/attestors/test-attestor",
        "userOwnedGrafeasNote": {
          "noteReference": "projects/example-project/notes/test-attestor",
          "publicKeys": [
            {
              "id": "ni:///sha-256;EwVxs8fNUAHq9FI2AMfh8WNIXVBuuTMeGtPH72U-I70",
              "pkixPublicKey": {
                "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXnpuYEfvLl1kj4fjxViFRwY1a+zC\n5qzlf9LJIK+rnjq42tiKGyyXMbnZKJiYPPdMDGyltnkrABnztg2jJ48aYQ==\n-----END PUBLIC KEY-----\n",
                "signatureAlgorithm": "ECDSA_P256_SHA256"
              }
            }
          ],
          "delegationServiceAccountEmail": "service-363451293945@gcp-sa-binaryauthorization.iam.gserviceaccount.com"
        },
        "updateTime": "2019-06-26T16:58:33.977438Z"
      }
      

      您可以在 idnoteReference 字段中分别找到公钥 ID 和备注 ID。

    5. 将公钥 ID 存储在环境变量中:

      PUBLIC_KEY_ID="PUBLIC_KEY_ID"
      NOTE_URI="NOTE_URI"
      

      替换以下内容:

      • PUBLIC_KEY_ID:证明者的公钥 ID。
      • NOTE_URI:与证明者关联的 Artifact Analysis 备注的 URI。
    6. /tmp/attestation.json 中创建一个描述该证明的 JSON 文件:

      cat > /tmp/attestation.json << EOM
      {
        "resourceUri": "${IMAGE_TO_ATTEST}",
        "note_name": "${NOTE_URI}",
        "attestation": {
           "serialized_payload": "$(base64 --wrap=0 /tmp/generated_payload.json)",
           "signatures": [
               {
                   "public_key_id": "${PUBLIC_KEY_ID}",
                   "signature": "${PAYLOAD_SIGNATURE}"
               }
           ]
        }
      }
      EOM
      
    7. 创建证明:

      curl -X POST \
          -H "Content-Type: application/json" \
          -H "X-Goog-User-Project: ${ATTESTATION_PROJECT_ID}" \
          -H "Authorization: Bearer $(gcloud auth print-access-token)" \
          --data-binary @/tmp/attestation.json \
      "https://containeranalysis.googleapis.com/v1/projects/${ATTESTATION_PROJECT_ID}/occurrences/"
      

您现已创建证明。

验证是否已创建证明

如需验证证明是否已创建,您可以列出与映像关联的证明。

gcloud

如需检索证明列表,请输入以下命令:

gcloud container binauthz attestations list\
    --project="${ATTESTATION_PROJECT_ID}"\
    --attestor="projects/${ATTESTOR_PROJECT_ID}/attestors/${ATTESTOR_NAME}"\
    --artifact-url="${IMAGE_TO_ATTEST}"

REST API

如需请求证明列表,请输入以下命令:

curl -X GET \
    -H "Content-Type: application/json" \
    -H "X-Goog-User-Project: ${ATTESTOR_PROJECT_ID}" \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
https://containeranalysis.googleapis.com/v1/projects/${ATTESTOR_PROJECT_ID}/notes/${NOTE_ID}/occurrences?filter=resourceUrl%3D%22https%3A%2F%2F$(jq -rn --arg x ${IMAGE_TO_ATTEST} '$x|@uri')%22

如果有很多证明,则响应可能包含 nextPageToken 值。在此情况下,您可以通过重复请求并添加 pageToken 查询参数来检索下一页结果,如下所示:

NEXT_PAGE_TOKEN=NEXT_PAGE_TOKEN
curl -X GET \
    -H "Content-Type: application/json" \
    -H "X-Goog-User-Project: ${ATTESTOR_PROJECT_ID}" \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
https://containeranalysis.googleapis.com/v1/projects/${ATTESTOR_PROJECT_ID}/notes/${NOTE_ID}/occurrences?filter=resourceUrl%3D%22https%3A%2F%2F$(jq -rn --arg x ${IMAGE_TO_ATTEST} '$x|@uri')%22&pageToken=${NEXT_PAGE_TOKEN}

NEXT_PAGE_TOKEN 替换为上一个请求响应中的 nextPageToken 值。

如果 nextPageToken 为空,表示没有更多结果。

删除证明

在删除证明之前,您应该执行以下操作:

  1. 了解删除该证明所产生的影响;删除证明最终会禁止部署与该证明关联的容器映像。

  2. 停止与您要删除的证明关联的所有正在运行的容器。

  3. 删除证明在所有可能位置中的所有副本,例如证明在 Artifact Registry 和 Artifact Analysis 代码库中的副本。

  4. 通过尝试重新部署,确保受影响的映像确实已被禁止部署。

如需删除证明,请执行以下命令:

  1. 列出证明:

    gcloud container binauthz attestations list \
      --attestor-project=${ATTESTOR_PROJECT_ID} \
      --attestor=${ATTESTOR_NAME}
    

    证明包含某个发生实例 ID。输出类似于以下内容:

    projects/ATTESTOR_PROJECT_ID/occurrences/OCCURRENCE_ID
    
  2. 保存该发生实例 ID。

    保存要删除的证明的发生实例 ID。

    OCCURRENCE_ID=OCCURRENCE_ID
    
  3. 删除证明:

    curl -H "Authorization: Bearer $(gcloud auth print-access-token)" -X DELETE \
      https://containeranalysis.googleapis.com/v1beta1/projects/${ATTESTATION_PROJECT_ID}/occurrences/${OCCURRENCE_ID}
    

    再次列出证明,以验证证明是否已删除。

后续步骤