部署要点总结:
- 用containerd imgcrypt的
ctr-enc
进行镜像加密 - 用containerd imgcrypt的
ctd-decoder
对镜像解密 - k8s中部署加密镜像需要做以下配置:
- 将ctd-decoder二进制放到节点的
/usr/local/bin
目录 - 将解密的私钥放到节点的
/etc/containerd/ocicrypt/keys
目录(该目录可以在containerd的配置文件中指定)
以下是在单机上对该方案进行验证的详细步骤。
一、镜像加密
git clone h提提ps://github.com/containerd/imgcrypt.git github.com/containerd/imgcrypt
cd github.com/containerd/imgcrypt && make && make install
make install
会将ctd-decoder
和ctr-enc
二进制安装到/usr/local/bin
:

其中ctr-enc
用于加密,ctd-decoder
用于解密。
- 配置containerd
$ wget h提提ps://github.com/containerd/containerd/releases/download/v1.3.0/containerd-1.3.0.linux-amd64.tar.gz
$ tar -xzf containerd-1.3.0.linux-amd64.tar.gz
$ ls bin/
containerd containerd-shim containerd-shim-runc-v1 containerd-shim-runc-v2 containerd-stress ctr
$ cat <<EOF > config.toml
disable_plugins = ["cri"]
root = "/tmp/var/lib/containerd"
state = "/tmp/run/containerd"
[grpc]
address = "/tmp/run/containerd/mycontainerd.sock"
uid = 0
gid = 0
[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 = "/usr/local/bin/ctd-decoder"
[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 = "/usr/local/bin/ctd-decoder"
EOF
#使以上配置生效
$ bin/containerd -c config.toml &
- 拉取镜像
拉取一个bash镜像作为示例进行后续的加密、解密、部署步骤演示。
chmod 0666 /tmp/run/containerd/mycontainerd.sock
CTR="/usr/local/bin/ctr-enc -a /tmp/run/containerd/mycontainerd.sock"
#拉取镜像
$CTR images pull --platform linux/amd64 docker.io/library/bash:latest
#查看镜像
$CTR images list
- 生成密钥
#私钥
(base) root@ecm-d580:encryption# openssl genrsa --out mykey.pem
Generating RSA private key, 2048 bit long modulus (2 primes)
#公钥
(base) root@ecm-d580:encryption# openssl rsa -in mykey.pem -pubout -out mypubkey.pem
writing RSA key
- 用生成的公钥进行加密
$CTR images encrypt --recipient jwe:mypubkey.pem --platform linux/amd64 docker.io/library/bash:latest docker.io/shaux/bash-enc:latest
docker.io/shaux/bash-enc:latest
即为加密后的镜像。
二、k8s部署加密镜像
- 在本机用minikube创建集群
minikube start --container-runtime='containerd' --kubernetes-version=v1.23.8
#查看节点
kubectl get node
- 不做解密相关的配置,尝试能否部署加密镜像
新建bash-enc.yaml
文件,写入以下内容,选择加密后的镜像docker.io/shaux/bash-enc:latest
apiVersion: v1
kind: Pod
metadata:
name: bash-enc
labels:
name: bash-enc
spec:
containers:
- name: bash-enc
image: docker.io/shaux/bash-enc:latest
imagePullPolicy: Always
command: ['sh', '-c', 'echo "Hello, This is encrypted image" && sleep 3600']
部署pod:
minikube@ecm-d580:~$ kubectl apply -f bash-enc.yaml
pod/bash-enc created
minikube@ecm-d580:/etc/containerd$ kubectl get po
NAME READY STATUS RESTARTS AGE
bash-enc 0/1 ImagePullBackOff 0 7m33s
发生了ImagePullBackOff
,kubectl describe看一下:
kubectl describe po bash-enc
可以看到由于缺少private key,无法对镜像进行解密,导致pod部署失败,接下来介绍如何在节点上进行镜像解密相关的配置。
- 在节点上进行解密相关的配置
-
- 修改节点中的containerd配置
进入minikube节点(minikube的节点本质上是docker容器)
docker exec -it minikube bash
将以下内容加到节点中的/etc/containerd/config.toml
文件末尾
[stream_processors]
[stream_processors."io.containerd.ocicrypt.decoder.v1.tar"]
accepts = ["application/vnd.oci.image.layer.v1.tar+encrypted"]
args = ["--decryption-keys-path", "/etc/containerd/ocicrypt/keys"]
env = ["OCICRYPT_KEYPROVIDER_CONFIG=/etc/containerd/ocicrypt/ocicrypt_keyprovider.conf"]
path = "ctd-decoder"
returns = "application/vnd.oci.image.layer.v1.tar"
[stream_processors."io.containerd.ocicrypt.decoder.v1.tar.gzip"]
accepts = ["application/vnd.oci.image.layer.v1.tar+gzip+encrypted"]
args = ["--decryption-keys-path", "/etc/containerd/ocicrypt/keys"]
env = ["OCICRYPT_KEYPROVIDER_CONFIG=/etc/containerd/ocicrypt/ocicrypt_keyprovider.conf"]
path = "ctd-decoder"
returns = "application/vnd.oci.image.layer.v1.tar+gzip"
注意:
-
-
args = ["--decryption-keys-path", "/etc/containerd/ocicrypt/keys"]
指定了解密密钥在节点中的存放路径,该路径默认没有创建,需手动在节点上创建:path = "ctd-decoder"
是执行解密操作的二进制;
-
执行以下命令使配置生效:
/usr/bin/containerd -c config.toml &
-
- 将解密需要的私钥
mykey.pem
复制到节点中/etc/containerd/ocicrypt/keys
目录,二进制文件ctd-decoder
复制到节点中/usr/local/bin
目录,minikube本质是一个容器,可用docker cp将宿主机文件传进去:(base) root@ecm-d580:bin# docker cp ctd-decoder minikube:/usr/local/bin Successfully copied 27.6MB to minikube:/usr/local/bin (base) root@ecm-d580:encryption# docker cp mykey.pem minikube:/etc/containerd/ocicrypt/keys Successfully copied 3.58kB to minikube:/etc/containerd/ocicrypt/keys
- 将解密需要的私钥
- 再次部署刚才的
bash-enc.yaml
文件
#先删除解密前部署的pod
minikube@ecm-d580:~$ kubectl delete -f bash-enc.yaml
pod "bash-enc" deleted
#再次部署bash-enc.yaml
minikube@ecm-d580:~$ kubectl apply -f bash-enc.yaml
pod/bash-enc created
#查看pod状态
minikube@ecm-d580:~$ kubectl get po
NAME READY STATUS RESTARTS AGE
bash-enc 1/1 Running 0 11s
pod的状态为Running,kubectl describe 看一下:
kubectl describe po bash-enc
可以看到在节点上做好解密相关配置后,用加密镜像部署的pod成功运行。