一文了解 containerd 中的鏡像加解密

  1. containerd 中的鏡像解密

OCI 鏡像規範中,一個鏡像是由多層鏡像層構成的,鏡像層可以通過加密機制來加密機密數據或代碼,以防止未經授權的訪問。如下圖所示。

OCI 鏡像加密原理主要是在原來的 OCI 鏡像規範基礎上,添加了一種新的 mediaType,表示數據文件被加密;同時在 annotation 中添加具體加密相關信息。鏡像層沒加密前的原始數據如下。

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

加密之後的數據如下。

"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 processors 和 containerd 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 選項,

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 操作,等價於:

<tar image layer>=`unpiz -d -c <tar.gzip image layer>`

其中:

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 中支持的配置有:

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

  1. 配置鏡像解密

containerd 中的鏡像解密則是利用了 stream_processor 機制,containerd/imgcrypt (https://github.com/containerd/imgcrypt)中的二進制 ctd-decoder 對每層鏡像進行解密。具體配置如下。

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 格式進行解密。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/yM0U-_ZSap59EbnvDRSPtw