加密与安全加固
本篇汇总两类加固工作:
- 商业化/私有化交付加固清单:交付前对系统、镜像、凭据、源码做的一次性收尾操作。
- containerd 镜像存储加密:基于 containerd
imgcrypt/ocicrypt的镜像层加密,保护镜像在仓库与磁盘上的存储安全。
来源:
install/kubernetes/rancher/加密/系统加密.md、install/kubernetes/rancher/加密/镜像存储加密.md。
一、交付加固清单
商业版交付(私有化、内网环境)前,按以下清单逐项收尾,目的是不泄露源码、不残留可被反向利用的凭据与外网仓库通道。
编译加密版本代码,构建加密代码版本的镜像。 即使用加密后的代码产出业务镜像,避免容器内可直接读到明文源码。镜像构建流程见 06-二次开发 / 镜像构建总览。
对关键镜像做加密。 需要加密的镜像包括:镜像名后缀含
encryption的镜像,以及labelstudio、jupyter、vscode等镜像。加密方式见下文「containerd 镜像存储加密」。关闭外网仓库通道、收紧权限。
- 不使用外网仓库镜像,不在平台中配置仓库账号密码;
- 仅下发有限权限的 token;
- 去除 cluster 版本的 dashboard(避免暴露集群级管理面)。
清理本地拉取的源码,并登出镜像仓库。
docker logout ccr.ccs.tencentyun.comccr.ccs.tencentyun.com/cube-studio/是 CubeStudio 的官方镜像仓库前缀(见myapp/config.py:978REPOSITORY_ORG)。交付环境登出后即无法再从该仓库拉取。清空 shell 历史记录。
history -c && history -w删除 kubeconfig,断开对集群的本地管理入口。
rm -rf ~/.kube/configkubekey 部署的 config 文件在
/etc/kubernetes/admin.conf,如需彻底收紧也要一并处理(注意:删除后本机将无法再用kubectl管理集群,请确认已无后续运维需求)。删除所有下载到本机的代码。
二、containerd 镜像存储加密
⚠️ 重要前提:containerd 镜像加密只能加密存储(仓库里、磁盘上的镜像层是密文)。但镜像一旦在 k8s 中运行起来,仍然可以
kubectl exec进入容器查看其中内容。因此它防的是“镜像被下载/落盘后被窃取源码或资产”,不防“运行态容器内查看”。
加密方案基于 containerd 官方的 imgcrypt(ocicrypt 体系),命令行工具为 ctr-enc。
2.1 为 containerd 安装 imgcrypt 插件
先安装指定版本 Go(按 CPU 架构二选一):
# amd64
apt update
wget https://mirrors.aliyun.com/golang/go1.23.0.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.23.0.linux-amd64.tar.gz
export PATH=/usr/local/go/bin:$PATH
go version
# arm64
apt update
wget https://mirrors.aliyun.com/golang/go1.23.0.linux-arm64.tar.gz
sudo tar -C /usr/local -xzf go1.23.0.linux-arm64.tar.gz
export PATH=/usr/local/go/bin:$PATH
go version
从源码构建 imgcrypt(使用官方 containerd.io 包时通常需要这样自行构建):
git clone -b v2.0.0 https://github.com/containerd/imgcrypt.git
cd imgcrypt
go env -w GOPROXY=https://goproxy.cn,direct
make
sudo make install
2.2 配置 containerd 解密策略
编辑 /etc/containerd/config.toml:
vi /etc/containerd/config.toml
配置解密策略(如果类型是 pod,则需要在 k8s pod 上添加注释并挂载秘钥):
[plugins."io.containerd.grpc.v1.cri".image_decryption]
key_model = "node"
配置解密步骤(stream processors):
[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"]
重载并重启 containerd:
systemctl daemon-reload
systemctl restart containerd
2.3 生成密钥对
openssl genrsa -out mykey.pem
openssl rsa -in mykey.pem -pubout -out mypubkey.pem
mypubkey.pem:公钥,用于加密镜像(推送方持有即可)。mykey.pem:私钥,用于解密镜像(运行节点持有,须保密)。
2.4 加密镜像并推送到仓库
# 拉取原始镜像
ctr-enc --namespace k8s.io images pull ccr.ccs.tencentyun.com/cube-studio/kubeflow-dashboard:2026.07.01
# 用公钥加密镜像,输出一个 -encrypted 标签的镜像
ctr-enc --namespace k8s.io images encrypt \
--recipient=jwe:mypubkey.pem \
ccr.ccs.tencentyun.com/cube-studio/kubeflow-dashboard:2026.07.01 \
ccr.ccs.tencentyun.com/cube-studio/kubeflow-dashboard:2026.07.01-encrypted
# 推送加密镜像
nerdctl --namespace k8s.io push ccr.ccs.tencentyun.com/cube-studio/kubeflow-dashboard:2026.07.01-encrypted
上面的镜像名/标签(
ccr.ccs.tencentyun.com/cube-studio/kubeflow-dashboard:2026.07.01)只是示例,按实际镜像替换。
2.5 验证加解密
# 用私钥解密回明文镜像
ctr-enc --namespace k8s.io images decrypt --key=mykey.pem \
ccr.ccs.tencentyun.com/cube-studio/kubeflow-dashboard:2026.07.01-encrypted \
ccr.ccs.tencentyun.com/cube-studio/kubeflow-dashboard:2026.07.01
# 不提供秘钥直接运行加密镜像 —— 会报错
ctr-enc --namespace k8s.io run --rm \
ccr.ccs.tencentyun.com/cube-studio/kubeflow-dashboard:2026.07.01-encrypted test ls
# 提供秘钥运行加密镜像 —— 正常
ctr-enc --namespace k8s.io run --rm --key mykey.pem \
ccr.ccs.tencentyun.com/cube-studio/kubeflow-dashboard:2026.07.01-encrypted test echo 'Hello World!'
2.6 k8s 节点侧解密配置
在需要运行加密镜像的节点上,把秘钥放到 containerd 约定目录并重启:
mkdir -p /etc/containerd/ocicrypt/keys /run/containerd/ocicrypt/keys/
cp mykey.pem /etc/containerd/ocicrypt/keys/
cp mypubkey.pem /etc/containerd/ocicrypt/keys/
cp -r /etc/containerd/ocicrypt/keys/* /run/containerd/ocicrypt/keys/
systemctl restart containerd
# 节点拉取加密镜像(带私钥)
ctr-enc --namespace k8s.io images pull --key mykey.pem \
ccr.ccs.tencentyun.com/cube-studio/kubeflow-dashboard:2026.07.01-encrypted
2.7 k8s Deployment 示例
节点完成解密配置后,直接像普通镜像一样在 Deployment 中引用加密镜像即可:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 1
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: main
image: ccr.ccs.tencentyun.com/cube-studio/kubeflow-dashboard:2026.07.01-encrypted
imagePullPolicy: IfNotPresent
command: ["sleep","1000000"]