创建和自定义工作负载

工作负载由工作负载作者创建,用于处理数据协作者想要处理的机密数据。

工作负载作者需要将以下资源组合在一起才能创建工作负载:

  • 一个应用,用于处理机密数据。您可以使用所选的任何语言编写应用,前提是您构建了支持该语言的容器映像。

  • 容器映像,用于使用 Docker 将应用打包到其中。

  • Artifact Registry 中的代码库,用于存储 Docker 映像。

  • 在容器映像上设置的启动政策,用于控制工作负载的运行方式,并限制恶意工作负载操作者的行为。

为了部署工作负载,工作负载操作员会基于 Confidential Space 映像运行机密虚拟机。此命令会从 Artifact Registry 中检索容器化映像并运行该映像。

数据协作者必须先验证工作负载的证明,然后工作负载才能访问其数据。

准备工作

为 Confidential Space 编写工作负载不仅仅是编写代码和调试。您还需要与数据协作者沟通,评估他们的需求,设置环境,将代码打包到容器映像中,并与工作负载操作员合作,确保一切正确部署。

与数据协作者沟通

在开始编写应用之前,您需要与数据协作者讨论他们希望您处理的私密数据。您可以提出以下问题:

  • 涉及哪些组织 ID?

  • 涉及的项目编号是什么?

  • 我需要访问哪些 Google Cloud 资源,它们的 ID 和名称是什么?

  • 是否有我需要访问但不受 Google CloudIAM 管理的资源?

  • 您要使用哪种证明服务:Google Cloud Attestation 还是 Intel Trust Authority?

  • 应用应如何比较和处理私密数据?

  • 输出应采用什么格式?

  • 输出应存储在何处?是否应加密?

  • 所有数据协作者看到的结果是否相同,还是每个协作者看到的结果都是唯一的?

此外,每个数据协作者可能也有您需要满足的独特隐私权要求。确保工作负载不会导致任何私密数据泄露,这一点至关重要。

构建 Confidential Space 解决方案

设置两个(或更多)具有适当权限的项目作为测试环境会很有用,如创建您的第一个 Confidential Space 环境中所述。请尽可能模拟数据协作者的项目设置。这样,您就可以获得跨项目权限方面的经验,并从特定 Google Cloud 资源中检索所需的数据。此外,您还可以了解工作负载操作员和数据协作者角色及其职责。

在早期构建阶段,遵循以下做法会很有帮助:

  • 作为数据协作者,为了提高开发速度,请尽量减少证明验证。

  • 作为工作负载操作员,在部署工作负载时,请使用 Confidential Space 调试映像,而不是生产映像。这样,您就可以通过更多方式排查工作负载问题。

随着应用日趋成熟,其状态变得更可预测,您可以使用证明验证和启动政策来进一步锁定解决方案,并切换到生产 Confidential Space 映像。

在测试环境中正确运行工作负载后,您可以切换到在数据协作者的项目中使用真实资源但虚假数据进行测试,以便向数据协作者演示一切如何运作。此时,您可能会开始与独立工作负载运营商合作。

当一切正常且输出符合预期时,您就可以开始对生产数据进行测试。测试完成且所有各方都对结果表示认可后,工作负载就可以投入生产环境了。

请谨慎对待输出

在测试代码时,您可能会想通过输出到 STDOUT 或 STDERR 来进行调试。如果您选择这样做,请注意不要公开其他方可以通过访问日志读取的私密数据。在代码开始在生产环境中运行之前,请确保它不会输出任何不必要的内容。

最终输出也是如此。仅提供不会泄露原始数据的隐私和敏感性的最终结果。

使用 Docker 构建容器映像

应用需要打包到由 Docker 构建的容器映像中,该映像存储在 Artifact Registry 中。部署工作负载后,Confidential Space 映像会从 Artifact Registry 代码库中拉取 Docker 映像并运行,然后应用便可以开始处理相应的项目资源。

构建 Docker 映像时,请考虑以下事项:

其他 Linux 功能

Confidential Space 工作负载在 Linux 容器中使用 containerd 运行。此容器使用默认 Linux 功能运行。

如需添加功能,您可以使用 tee-added-capabilities。

磁盘和内存限制

使用较大的启动磁盘大小时,Confidential Space 会自动调整启动磁盘有状态分区的大小。分区大小大约为启动磁盘大小减去 5 GB。

作为 Confidential Space 完整性文件系统保护的一部分,Confidential Space 会将磁盘完整性标记存储在内存中。每个磁盘字节大约会产生 1% 的内存开销。例如,100 GB 的磁盘需要 1 GB 的内存,10 TB 的磁盘需要 100 GB 的内存。

请确保不要超出虚拟机内存限制。交换内存已在 Confidential Space 虚拟机上停用,这意味着过度使用内存可能会导致工作负载崩溃。 验证您选择的机器除了支持磁盘完整性开销之外,还支持工作负载内存用量。

安全关停

当操作员请求关停 Confidential Space 虚拟机时,Confidential Space Launcher 会尝试通过发送 SIGTERM 信号来正常关停工作负载。收到该信号后,工作负载最多有 120 秒的时间来执行清理,然后 Confidential Space Launcher 就会启动关停流程。未实现 SIGTERM 信号处理的工作负载会在收到信号后立即终止。

内存中暂存装载

Confidential Space 支持添加内存中暂存空间。这会使用 Confidential Space 虚拟机中的可用内存。由于暂存空间使用机密虚拟机的内存,因此它具有与机密虚拟机相同的完整性和机密性属性。

您可以使用 tee-dev-shm-size 增加工作负载的 /dev/shm 共享内存装载的大小。/dev/shm 大小以 KB 为单位。

您可以使用 tee-mount 通过英文分号分隔的配置在正在运行的容器中指定 tmpfs 装载。type 和 source 始终为 tmpfs。destination 是装载点,它会与 tee.launch_policy.allow_mount_destinations 启动政策进行交互。您可以选择指定 tmpfs 大小(以字节为单位)。默认大小为虚拟机内存的 50%。

入站端口

默认情况下,Confidential Space 虚拟机使用防火墙规则来阻止所有入站端口。使用 230600 或更高版本的 Confidential Space 映像时,可以在构建工作负载映像时指定入站端口在 Dockerfile 中保持打开状态。

如需打开端口,请将 EXPOSE 关键字添加到 Dockerfile,以及要保持打开状态的端口号和可选协议 tcp 或 udp。如果未指定端口的协议,则允许 TCP 和 UDP。以下是公开入站端口的示例 Dockerfile:

FROM alpine:latest
EXPOSE 80
EXPOSE 443/tcp
EXPOSE 81/udp
WORKDIR /test
COPY salary /test
ENTRYPOINT ["/test/salary"]
CMD []

根据您使用的基础映像,某些端口可能已经公开。您的 Dockerfile 仅公开其他端口;它无法阻止基础映像已打开的端口。

工作负载运维人员应确保在运行工作负载之前,其 VPC 防火墙中已打开公开的端口。端口号可由工作负载作者提供,也可以从 Docker 映像信息中提取。

公开的端口会记录在控制台中,并在使用 tee-container-log-redirect 元数据变量时重定向到 Cloud Logging。

启动政策

启动政策会替换工作负载操作员设置的虚拟机元数据变量,以限制恶意操作。工作负载作者可以在构建容器映像的过程中使用标签设置政策。

例如,在 Dockerfile 中:

LABEL "tee.launch_policy.allow_cmd_override"="true"

在 Bazel BUILD 文件中:

container_image(
    ...
    labels={"tee.launch_policy.allow_cmd_override":"true"}
    ...
)

可用的启动政策如下表所示:

政策 类型 说明

tee.launch_policy.allow_capabilities

互动对象:

布尔值(默认值为 false) 确定工作负载操作员是否可以向工作负载容器添加其他 Linux 功能。

tee.launch_policy.allow_cgroups

互动对象:

布尔值(默认值为 false) 确定是否允许工作负载容器在 /sys/fs/cgroup 处包含命名空间 cgroup 装载。

tee.launch_policy.allow_cmd_override

互动对象:

布尔值(默认值为 false) 确定工作负载容器的 Dockerfile 中指定的 CMD 是否可被工作负载操作员使用 tee-cmd 元数据值替换。

tee.launch_policy.allow_env_override

互动对象:

以逗号分隔的字符串 允许工作负载操作员使用 tee-env-ENVIRONMENT_VARIABLE_NAME 元数据值设置的允许环境变量名称构成的字符串(以逗号分隔)。

tee.launch_policy.allow_mount_destinations

互动对象:

  • 工作负载操作员: tee-mount 元数据变量。
以英文冒号分隔的字符串

以英文冒号分隔的字符串,表示允许工作负载操作员使用 tee-mount 装载的装载目录。

例如:/run/tmp:/var/tmp:/tmp

tee.launch_policy.log_redirect

互动对象:

定义的字符串

确定在工作负载操作员将 tee-container-log-redirect 设置为 true 时日志记录的工作方式。

有效值如下:

  • debugonly(默认):仅在使用调试映像时允许 stdout 和 stderr 重定向。
  • always:始终允许 stdout 和 stderr 重定向。
  • never:一律不允许 stdout 和 stderr 重定向。

tee.launch_policy.monitoring_memory_allow

互动对象:

定义的字符串

确定在工作负载操作员将 tee-monitoring-memory-enable 设置为 true 时,工作负载内存用量监控的工作方式。

有效值如下:

  • debugonly(默认):仅在使用调试映像时允许监控内存用量。
  • always:始终允许监控内存用量。
  • never:一律不允许监控内存用量。

tee.launch_policy.nonroot_container

互动对象:

定义的字符串

确定是否限制容器的执行权限。

有效值如下:

  • unrestricted(默认):工作负载作者允许容器以根用户或非根用户身份运行。工作负载操作员选择使用 tee-nonroot-container。
  • nonrootonly:工作负载作者要求容器以非根用户身份运行。工作负载操作员必须将 tee-nonroot-container 设置为 true,否则虚拟机无法启动工作负载。

多个工作负载运行

如需重新运行工作负载,工作负载操作员必须重启虚拟机实例。这会在尽可能干净的环境中启动工作负载,并使用新的临时密钥加密虚拟机实例的磁盘。

重启可防范在下载和衡量磁盘上的工作负载映像之后对其进行修改的攻击途径。不过,这也会增加启动时间和将工作负载映像拉取到每个工作负载运行等开销。如果这些开销对工作负载性能的影响太大,您可以将一个工作负载重启操作编码到工作负载中,但代价是所承担的风险也会相应增加。

命名空间型 cgroup

默认情况下,Confidential Space 工作负载在没有 cgroup 装载的情况下运行。

如需在工作负载容器中管理 cgroup,您可以使用 tee-cgroup-ns。此元数据键指示虚拟机实例在容器文件系统中的 /sys/fs/cgroup 处创建装载。

非 root 容器执行

您可以选择以非根用户身份运行容器,以减少容器逃逸的影响。启用非根容器执行后,Confidential Space 会为工作负载配置 Linux 用户命名空间和网络命名空间。容器 UID 和 GID 0-65535 映射到机密虚拟机上从 100000 开始的非特权 ID。在容器内以根用户身份运行或逃逸容器的进程仅具有对虚拟机的非特权访问权限。您无需向 Dockerfile 添加 USER 指令。

非 root 执行需要 Confidential Space 映像 confidential-space-261001 或更高版本。您可以将其配置为可选或必填:

  • 工作负载作者:在容器映像中使用 tee.launch_policy.nonroot_container 启动政策标签。如果将此政策设置为 nonrootonly,则工作负载操作员必须以非根用户身份运行容器。

  • 工作负载操作员:在创建虚拟机时传递 tee-nonroot-container=true 元数据变量。如果工作负载作者设置了 nonrootonly,则此元数据变量是必需的,否则虚拟机将无法启动工作负载。

可重现的容器映像

以可重现的方式构建容器映像有助于增强相关方之间的信任。您可以使用 Bazel 构建可重现的映像。

不受 Google Cloud IAM 管理的资源

如需访问不受 Google Cloud IAM 管理的资源,您的工作负载需要指定自定义受众群体。

如需了解详情,请参阅访问不受 Google Cloud IAM 管理的资源。

已签名的容器映像

您可以使用公钥对容器映像进行签名,然后数据协作者可以使用该公钥进行证明,而无需在其 WIP 政策中指定映像摘要。

这意味着,数据协作者无需在每次更新工作负载时更新其 WIP 政策,并且工作负载可以继续不间断地访问受保护的资源。

您可以使用 Sigstore Cosign 对容器映像进行签名。为了让 Confidential Space 提取签名,工作负载操作员必须在部署工作负载之前将签名信息添加到 tee-signed-image-repos 元数据变量中。

在运行时,签名会发送到证明服务进行验证。认证服务会返回一个认证声明令牌,其中包含经过验证的签名声明。以下是一个特征签名声明示例:

"image_signatures": [
  {
    "key_id": "hexadecimal-sha256-fingerprint-public-key1",
    "signature": "base64-encoded-signature",
    "signature_algorithm": "RSASSA_PSS_SHA256"
  },
  {
    "key_id": "hexadecimal-sha256-fingerprint-public-key2",
    "signature": "base64-encoded-signature",
    "signature_algorithm": "RSASSA_PSS_SHA256",
  },
  {
    "key_id": "hexadecimal-sha256-fingerprint-public-key3",
    "signature": "base64-encoded-signature",
    "signature_algorithm": "RSASSA_PSS_SHA256",
  }
]

如需配置容器映像签名,请参阅已签名的容器映像 Codelab。