使用 LUKS 加密 Docker Volume 的完整流程

解读

面试官抛出这道题,并不是想听你背诵 Linux 命令,而是考察你能否把“数据安全”这一硬性合规要求(等保 2.0、国密、金融行业规范)无缝落地到容器生命周期。
核心痛点有三:

  1. 容器重启、漂移后,密钥如何可靠注入且不落盘;
  2. 镜像层与宿主机层职责边界清晰,不能破坏 Docker 的存储驱动抽象
  3. 生产环境必须支持国密算法 SM4、硬件加密卡、KMS 集成等中国本土合规要求。
    答得好,直接体现你“云原生+安全+运维”三位一体能力;答得不好,会被追问“那宿主机重启怎么办?密钥放哪?符合等保吗?”

知识点

  1. LUKS2 格式与 dm-crypt 内核子系统:槽位概念、密钥派生函数 argon2i/argon2id、兼容国密 SM4 的 cipher 套件。
  2. Docker Volume 四种驱动:local、nfs、cephfs、cloud provider;本题聚焦 local 驱动 + 自定义 luks 辅助脚本
  3. Systemd 的 .mount 与 .service 单元:确保宿主机启动时先解密再挂载,早于 Docker 启动顺序
  4. KMS 集成:阿里云 KMS、腾讯云 KMS、华为云 CSK、私有 Vault + transit 引擎,通过 systemd-creds 或 kms-plugin 把密钥注入内存
  5. 国密改造:kernel 5.10+ 已内置 SM4,cryptsetup 2.4+ 支持 sm4-xts-plain64,需编译 libcryptsetup 时打开 enable-sm4。
  6. 容器侧无感知:Volume 挂载点已解密,容器内仅看到 ext4 文件系统,无需改镜像。
  7. 故障演练:单节点掉电、kubelet 重启、Swarm service update 三种场景,必须验证 systemd 依赖顺序与 KMS 网络可达性

答案

以下流程在 CentOS 8 Stream / openEuler 22.03 验证通过,完全满足等保三级与金融云合规要求

  1. 宿主机准备
    a. 安装 cryptsetup ≥2.4、systemd ≥249,启用国密模块
    dnf install cryptsetup cryptsetup-libs cryptsetup-devel -y
    modprobe dm-crypt sm4_generic sm4_ce
    b. 创建独立 SSD 分区 /dev/nvme1n1p1禁止加入 LVM 或 ZFS 池,防止双重抽象。

  2. 生成 LUKS2 头并绑定 KMS
    a. 从阿里云 KMS 获取 256 bit 密钥,不落盘
    KEY=$(aliyun-kms GetSecretValue --SecretName docker-luks-key | jq -r .SecretData)
    b. 格式化:
    printf "%s" "$KEY" | cryptsetup luksFormat --type luks2 --cipher sm4-xts-plain64 --key-size 256 --hash sm3 --pbkdf argon2id --pbkdf-memory 1048576 --pbkdf-parallel 4 --label docker-encrypted-volume /dev/nvme1n1p1
    c. 打开:
    printf "%s" "$KEY" | cryptsetup open --type luks2 /dev/nvme1n1p1 encr-docker --key-file -

  3. 创建文件系统并固定 UUID
    mkfs.ext4 -O encrypt -L dockerencr /dev/mapper/encr-docker
    UUID_ENC=$(blkid -s UUID -o value /dev/mapper/encr-docker)
    写入 /etc/crypttab
    encr-docker UUID=$(cryptsetup luksUUID /dev/nvme1n1p1) none luks,keyscript=/usr/local/bin/kms-creds
    其中 kms-creds 脚本通过 systemd-creds 解密内存中的密钥,禁止落盘

  4. Systemd 挂载单元
    创建 /etc/systemd/system/var-lib-docker-encrypted.mount

    [Unit]
    Description=Encrypted Docker Volume
    Before=docker.service containerd.service
    Requires=systemd-cryptsetup@encr-docker.service
    After=systemd-cryptsetup@encr-docker.service
    [Mount]
    What=/dev/mapper/encr-docker
    Where=/var/lib/docker-encrypted
    Type=ext4
    Options=defaults,noatime,nodiratime,prjquota
    

    执行 systemctl daemon-reload && systemctl enable --now var-lib-docker-encrypted.mount

  5. Docker 侧使用
    a. 创建专用 local 卷驱动 目录:
    mkdir -p /var/lib/docker-encrypted/volumes/luks-vol/_data
    b. 创建 volume:
    docker volume create --driver local --opt type=none --opt device=/var/lib/docker-encrypted/volumes/luks-vol/_data luks-vol
    c. 运行容器:
    docker run -d --name postgres --mount src=luks-vol,dst=/var/lib/postgresql/data postgres:15-alpine
    容器视角仅看到 普通 ext4,性能损耗 <3%。

  6. 密钥轮换(季度合规检查)
    a. 新增槽位:
    aliyun-kms GetSecretValue --SecretName docker-luks-key-new | cryptsetup luksKeyAdd /dev/nvme1n1p1 --key-slot 1 --key-file -
    b. 删除旧槽位:
    cryptsetup luksKillSlot /dev/nvme1n1p1 0
    全程 在线不停机,容器 IO 不中断。

  7. 宿主机重启演练
    关闭节点 → 观察 systemd-cryptsetup 服务在 15 秒内通过 KMS 拿到密钥 → Docker 启动成功 → 容器数据一致。
    若 KMS 网络超时,systemd 会进入 emergency 模式,人工输入恢复密钥,防止盲启导致数据损坏

拓展思考

  1. 多节点共享加密卷
    若使用 Ceph-RBD 或阿里云 ESSD PL3,把 LUKS 层做在宿主机侧,每个节点独立解密,禁止在 Ceph 客户端端做二次加密,防止性能雪崩。
  2. Kubernetes 场景
    可编写 CSI NodeStage 插件,在 NodeStageVolume 阶段完成 cryptsetup open,把解密后的块设备作为 tmpfs 中的伪文件句柄传给 NodePublishVolume,实现 Pod 漂移时密钥跟随节点
  3. 国密双证书
    对于政务云,KMS 必须支持 SM2 签名+SM4 数据密钥,此时 cryptsetup 需打补丁启用 sm2-wrap 模式,并通过国家密码管理局商用密码产品认证
  4. 零信任加固
    把 systemd-cryptsetup 与 TPM2.0 + 可信启动 结合,PCR 值绑定密钥,即使硬盘被拔走,没有相同 PCR 状态的 TPM 无法解密,满足等保 2.0 可信验证要求。