创建证明

本页面介绍了如何通过命令行在 Binary Authorization 中创建证明

本页面上的说明概述了签名者为了使容器映像能够部署而必须执行的步骤。在实际场景中,您可以将这些步骤整合到可由机器进程或真人用户触发的脚本或自动化方法中,而不是在命令行中手动输入它们。

概览

证明是一种数字签名文档,由签名者创建,用于验证流水线中的必需流程已完成且生成的容器映像可在 GKE 中进行部署。证明本身包含指向容器映像注册表中存储的那版容器映像的完整路径,以及通过对用于标识特定容器映像构建的全局唯一摘要签名的方式创建的签名。

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

设置默认项目

如果您尚未设置默认 Google Cloud 项目:

PROJECT_ID=PROJECT_ID
gcloud config set project ${PROJECT_ID}

其中,PROJECT_ID 是您的项目的名称。

设置环境

  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
    PUBLIC_KEY_ID=PUBLIC_KEY_ID
    PRIVATE_KEY_FILE=PRIVATE_KEY_FILE
    IMAGE_TO_ATTEST="${IMAGE_PATH}@${IMAGE_DIGEST}"
    

    其中:

    • ATTESTOR_NAME 是证明者的名称(例如 build-secureprod-qa
    • IMAGE_PATH 是 Container Registry 中要部署的映像的路径(例如 gcr.io/example-project/quickstart-image
    • PUBLIC_KEY_ID 是与您生成的密钥对中的公钥相关联的 ID。公钥本身存储在证明者中。
    • PRIVATE_KEY_FILE 是包含您生成的密钥对中的私钥的文件。证明载荷使用此密钥进行签名。
    • IMAGE_DIGEST 是映像清单的 SHA-256 摘要(例如 sha256:c62ead5b8c15c231f9e786250b07909daf6c266d0fcddd93fea882eb722c3be4)。如需了解如何获取映像摘要,请参阅如何在 Container Registry 中列出映像的版本

每个存储在 Container Registry 或其他注册表中的容器映像都具有其位置的唯一路径,以及唯一标识其版本的 SHA-256 摘要。证明引用了完整的映像路径和摘要,从而让您可以向特定版本的映像授权。

以下是一个完整注册表路径的示例:

gcr.io/example-project/quickstart-image@sha256:bedb3feb23e81d162e33976fd7b245adff00379f4755c0213e84405e5b1e0988

使用本地存储的密钥创建具有 PKIX 签名的证明

对于使用 PKIX 公钥签名的证明,请执行以下操作:

  1. 创建一个引用相应注册表路径的证明载荷,以便发送到 Binary Authorization
  2. 对载荷签名并生成 PKIX 签名文件
  3. 获取公钥 ID
  4. 使用签名文件和公钥 ID 创建证明

创建证明载荷

证明载荷是一个 JSON 格式的文件,用于引用容器映像的位置。

如需创建载荷文件,请按如下所示操作:

gcloud

输入以下内容:

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

载荷文件类似于以下内容:

{
  "critical": {
    "identity": {
      "docker-reference": "gcr.io/google-samples/hello-app"
    },
    "image": {
      "docker-manifest-digest": "sha256:bedb3feb23e81d162e33976fd7b245
adff00379f4755c0213e84405e5b1e0988"
    },
    "type": "Google cloud binauthz container signature"
  }
}

REST

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

cat > /tmp/generated_payload.json << EOM
{
  "critical": {
    "identity": {
      "docker-reference": "${IMAGE_PATH}"
    },
    "image": {
      "${IMAGE_DIGEST}"
    },
    "type": "Google cloud binauthz container signature"
  }
}
EOM

对载荷签名并生成签名文件

创建载荷文件后,您必须使用之前生成的密钥对中的加密私钥对其进行签名。回想一下,相应的公钥存储在关联的证明者中。该证明者中的公钥将在部署时用于验证此签名。

如需查看如何创建证明者,请参阅使用 CLI 创建证明者使用控制台创建证明者

如需查看包含所有这些步骤的端到端示例,请参阅通过 CLI 开始使用通过控制台开始使用

如需为载荷文件签名,请执行以下操作:

  1. 使用本地 PKIX 私钥对载荷签名并输出签名文件:

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

    签名文件是您在前面创建的载荷 JSON 文件的数字签名版本。

获取公钥 ID

在创建证明时,您必须将公钥 ID 与签名文件一起发送到 Binary Authorization。

如需获取公钥 ID,请执行以下操作:

  1. 保存公钥 ID

    要在之后查看证明者的公钥 ID,请使用 gcloud container binauthz attestors describe ${ATTESTOR_NAME}

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

创建证明

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) 证明是否可以由提供的证明者进行验证,请运行以下命令:

gcloud alpha 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

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

REST

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

  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"
    }
    
  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": "KEY_ID",
             "signature": "$(base64 --wrap=0 /tmp/ec_signature)"
             }
         ]
      }
     }
    EOM
    

    其中,KEY_ID 是上一步返回的公钥 ID。

  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 Key Management Service 的 PKIX 签名创建证明

如需使用基于 Cloud Key Management Service 的 PKIX 签名创建证明,请执行以下操作:

  1. 设置环境变量,以存储用于存储证明、证明者和 Cloud Key Management Service 密钥的项目的相关信息,以及关于 PKIX 密钥对的信息:

    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

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

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

      gcloud --project="${KMS_KEY_PROJECT_ID}"  \
          alpha kms asymmetric-sign \
          --location="${KMS_KEY_LOCATION}" \
          --keyring="${KMS_KEYRING_NAME}" \
          --key="${KMS_KEY_NAME}" \
          --version="${KMS_KEY_VERSION}" \
          --digest-algorithm="DIGEST_ALGORITHM" \
          --input-file=/tmp/generated_payload.json \
          --signature-file=/tmp/generated_payload.json.sig
      

      其中,DIGEST_ALGORITHMsha256sha384sha512 中的一个。这是您用于签名的密钥版本的摘要算法。

      此命令会输出名为 /tmp/generated_payload.json.sig 的文件,其中包含数字签名。

    3. 检索您要代表其对证明签名的证明者,并提取存储的公钥 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"
      }
      
    4. 在文本编辑器中,在 /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": "KEY_ID",
                   "signature": "$(base64 --wrap=0 /tmp/generated_payload.json.sig)"
               }
           ]
        }
      
      }
      EOM
      

      其中,KEY_ID 是上一步返回的公钥 ID。

    5. 创建证明:

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

REST

检索证明列表:

curl -X GET \
    -H "Content-Type: application/json" \
    -H "X-Goog-User-Project: ${ATTESTATION_PROJECT_ID}" \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://containeranalysis.googleapis.com/v1/projects/${ATTESTATION_PROJECT_ID}/occurrences?filter=kind%3D%22ATTESTATION%22"

如果有很多证明,响应中可能会返回 nextPageToken。在这种情况下,应重复该请求,但需要将 pageToken 查询参数设置为此 nextPageToken 值,以获取更多证明。如果 nextPageToken 为空,表示没有更多结果。

curl -X GET \
    -H "Content-Type: application/json" \
    -H "X-Goog-User-Project: ${ATTESTATION_PROJECT_ID}" \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
"https://containeranalysis.googleapis.com/v1/projects/${ATTESTATION_PROJECT_ID}/occurrences/?filter=kind%3D%22ATTESTATION%22&pageToken=${NEXT_PAGE_TOKEN}"

后续步骤