一文了解 containerd 中的鏡像加解密
- 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 社區共支持兩種鏡像加密模式:
-
Node Key Model,將密鑰放在 Kubernetes 工作節點上,以節點爲粒度實現解密,參考圖 4.21 所示。
-
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>`
其中:
-
<tar.gzip image layer>
爲輸入的 targzip 格式的鏡像層。 -
<tar image layer>
則爲執行unpiz -d -c
之後的 stdout 輸出,即解壓的結果。 該示例的 stream_processor 配置如下。
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"]
。
- 配置鏡像解密
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