《containerd 系列》一文了解 containerd 中的镜像加解密

内容节选自《containerd 原理剖析与实战》,新书内购中,点击阅读原文,限时 69.9 元购买

1. containerd 中的镜像解密

OCI 镜像规范中,一个镜像是由多层镜像层构成的,镜像层可以通过加密机制来加密机密数据或代码,以防止未经授权的访问。如下图所示。

图 镜像加密原理

OCI 镜像加密原理主要是在原来的 OCI 镜像规范基础上,添加了一种新的 mediaType,表示数据文件被加密;同时在 annotation中添加具体加密相关信息。镜像层没加密前的原始数据如下。

json 复制代码
"layers":[
  {
    "mediaType":"application/vnd.oci.image.layer.v1.tar+gzip",
    "digest":"sha256:7c9d20b9b6cda1c58bc4f9d6c401386786f584437abbe87e58910f8a9a15386b",
    "size":760770
  }
]

加密之后的数据如下。

json 复制代码
"layers":[
  {
    "mediaType":"application/vnd.oci.image.layer.v1.tar+gzip+encrypted",
    "digest":"sha256:c72c69b36a886c268e0d7382a7c6d885271b6f0030ff022fda2b6346b2b274ba",
    "size":760770,
    "annotations": {
      "org.opencontainers.image.enc.keys.jwe":"eyJwcm90ZWN0Z...",
      "org.opencontainers.image.enc.pubopts":"eyJjaXBoZXIiOi..."
    }
  }
]

在启动容器时, containerd 通过解密信息来解密这些加密镜像。这些解密信息包括密钥、选项和加密元数据。这些信息配置在 CRI Plugin 的 image_decryption 配置项中。此外,还需要设置正确的密钥模型并确保已正确配置 stream processorscontainerd imgcrypt 解码器。

下面介绍如何在 containerd 的 CRI Plugin 中配置镜像解密。在介绍 CRI Plugin 中的镜像解密前,先介绍 k8s 中的镜像加解密containerd 中的 stream_processor

1.k8s 生态的镜像加解密

首先介绍镜像加密模式,Kubernetes 社区共支持两种镜像加密模式:

  1. Node Key Model,将密钥放在 Kubernetes 工作节点上,以节点为粒度实现解密,参考图4.21 所示。

  2. Multi-tenancy Key Model,多租户模型,以集群粒度实现解密(当前社区还未实现)。

图 镜像解密模式 Node Key Model

containerd 中当前支持的 是 Node Key Model ,如上图所示,这种模式下 containerd 会在可信的 Node 上进行拉取镜像并利用私钥进行解密镜像。具体配置如下。首先是 containerd 中配置 CRI Pluging 的 image_decryption 选项,

ini 复制代码
version = 2
[plugins."io.containerd.grpc.v1.cri".image_decryption]
  key_model = "node"

在 containerd 及以后的版本中, key_model = "node"是默认的配置,如果是 1.4 以及以前的配置,则需要手动配置上述信息并重启 containerd。除此之外,还需要配置 stream_processors 配置项。

2. containerd 中的 stream_processors

stream_processors 是 containerd 中的一种基于内容流的二进制 API。

传入的内容流通过 STDIN 传递给对应的二进制文件,二进制处理后输出 STDOUT 到 stream_processors,如下图所示。

_图 stream\processors 处理流程

streaming_processor 是对二进制的调用,如上图所示,相当于针对每层镜像都进行了 unpiz 操作,等价于:

arduino 复制代码
<tar image layer>=`unpiz -d -c <tar.gzip image layer>`

其中:

  • <tar.gzip image layer> 为输入的 targzip 格式的镜像层。

  • <tar image layer> 则为执行 unpiz -d -c 之后的stdout 输出,即解压的结果。 该示例的 stream_processor 配置如下。

ini 复制代码
version = 2
[stream_processors]
  [stream_processors."io.containerd.processor.v1.pigz"]
 accepts = ["application/vnd.docker.image.rootfs.diff.tar.gzip"]
 returns = "application/vnd.oci.image.layer.v1.tar"
 path = "unpigz"
 args = ["-d", "-c"]

stream_processor 中支持的配置有:

  • ID : 即 示例中的 "io.containerd.processor.v1.pigz",通过 stream_processors.<Process ID> 来指定某个 processor 的配置。

  • accepts: 该 processor 能处理的格式。

  • returns: 该 processor 处理之后的格式。

  • path: 该 processor 对应的可执行二进制文件的路径。

  • args :该 processor 处理时所需的参数。path + args 组成该 processor 的处理步骤,例如上述示例则是 unpigz -d -c

此外,processor 还支持 env 配置,格式为 ["key1=value1","key2=value2"]

3. 配置镜像解密

containerd 中的镜像解密则是利用了 stream_processor 机制,containerd/imgcrypt (https://github.com/containerd/imgcrypt)中的二进制 ctd-decoder 对每层镜像进行解密。具体配置如下。

ini 复制代码
version = 2
[plugins."io.containerd.grpc.v1.cri".image_decryption]
  key_model = "node"
[stream_processors]
  [stream_processors."io.containerd.ocicrypt.decoder.v1.tar.gzip"]
    accepts = ["application/vnd.oci.image.layer.v1.tar+gzip+encrypted"]
    returns = "application/vnd.oci.image.layer.v1.tar+gzip"
    path = "ctd-decoder"
    args = ["--decryption-keys-path", "/etc/containerd/ocicrypt/keys"]
    env= ["OCICRYPT_KEYPROVIDER_CONFIG=/etc/containerd/ocicrypt/ocicrypt_keyprovider.conf"]
  [stream_processors."io.containerd.ocicrypt.decoder.v1.tar"]
    accepts = ["application/vnd.oci.image.layer.v1.tar+encrypted"]
    returns = "application/vnd.oci.image.layer.v1.tar"
    path = "ctd-decoder"
    args = ["--decryption-keys-path", "/etc/containerd/ocicrypt/keys"]
    env= ["OCICRYPT_KEYPROVIDER_CONFIG=/etc/containerd/ocicrypt/ocicrypt_keyprovider.conf"]

上述配置中,利用二进制 ctd-decoder 通过参数 --decryption-keys-path 指定镜像解密私钥,分别对 tar 格式和 tar.gzip 格式进行解密。

以上内容节选自新书 《containerd 原理剖析与实战》

最后,附上本书的购买链接,新书刚刚上架原价 109,限时优惠内购 69.9 元 ,感兴趣的朋友可以尽快入手。内购链接点击左下角**"阅读原文**"

本文使用 文章同步助手 同步

相关推荐
祁同伟.18 分钟前
【OJ】二叉树的经典OJ题
数据结构·c++·算法·容器·stl
爱宇阳10 小时前
离线环境下运行 Docker 容器编排指南
docker·容器·eureka
ZHE|张恒14 小时前
Docker 安装 MinIO(20250422)
运维·docker·容器
victory043116 小时前
krea 智能体自动部署k8s 情况 和k8s入门路径 minikube
云原生·容器·kubernetes
j2001032216 小时前
K8S 概念与安装
云原生·容器·kubernetes
退役小学生呀16 小时前
二十三、K8s企业级架构设计及落地
linux·云原生·容器·kubernetes·k8s
容器魔方18 小时前
Karmada 用户组再迎新成员,Scatter Lab 正式加入!
云原生·容器·云计算
Asuncion00720 小时前
K8s控制器详解:从原理到实战
docker·容器·kubernetes
做运维的阿瑞20 小时前
DevOps 生命周期完全指南
运维·容器·devops
大大大大物~21 小时前
数据结构之HashMap(容器)
java·数据结构·容器