ACK容器环境中通过JCE Provider调用非中国内地密码机

更新时间:
复制 MD 格式

通过在ACK容器环境中集成JCE Provider,可以调用非中国内地GVSM(NIST FIPS)密码机的加密服务,对运行在容器中的应用数据进行加密与解密操作。本文介绍如何制作包含JCE Provider的业务容器镜像,并将其部署到ACK集群中调用密码机。

方案概述

ACK容器环境中,业务应用通过JCE Provider调用密码机的加密服务。容器启动时,hsm_proxy进程会作为HSM客户端代理运行,负责与密码机实例建立安全连接。业务应用通过JCE Provider接口发起加解密请求,JCE Provider将请求转发给hsm_proxy,由hsm_proxy与密码机实例通信完成实际的密码运算。

整体部署流程如下:

  1. 制作业务容器镜像:将HSM客户端工具、JCE Provider和业务应用JAR打包到Docker镜像中。

  2. 推送镜像至ACR:将构建好的镜像推送到阿里云容器镜像服务。

  3. 部署应用到ACK:在ACK集群中创建保密字典存储认证信息,然后部署业务镜像。

重要

ACK集群与密码机实例必须在同一VPC下,否则容器内的hsm_proxy无法连接到密码机实例。

步骤一:制作业务容器镜像

HSM客户端工具、JCE Provider和业务应用打包为Docker镜像,并根据操作系统选择对应的镜像构建方案。

CentOS

  1. 下载安装包

  2. 在业务代码中集成JCE Provider

    1. Java业务代码中集成JCE SDK,调用其加密服务接口进行加解密运算。关于JCE Provider支持的加密算法和接口,请参见支持机制代码示例

    2. 将集成了JCE ProviderJava项目打包为JAR文件(如app.jar),并将其拷贝至镜像构建目录。

  3. 准备文件目录

    将安装包和JAR文件放置到/home/deploy/centos目录,目录结构如下:

    /home/deploy/centos/
    ├── pkg/
    │   ├── hsm-client-v2.03.15.10-1.x86_64.rpm        # 密码机管理工具
    │   ├── hsm-client-jce-v2.03.15.10-2.el8.x86_64.rpm # JCE Provider
    │   └── jdk-8xxxx-linux-x64.rpm                     # JDK(仅centos:7需要)
    ├── app.jar                                          # 业务应用JAR
    └── Dockerfile
  4. 创建Dockerfile

    本文以centos:7作为基础镜像时的Dockerfile的编写方法为例。

    说明

    由于CentOS 7自带的OpenSSL版本较低,需要编译安装OpenSSL 1.1.1d以满足HSM客户端的依赖要求。

    # 使用CentOS 7镜像作为基础镜像
    FROM centos:7
    
    WORKDIR /
    
    # 将安装包和JAR文件拷贝到镜像
    COPY pkg/jdk-8xxxx-linux-x64.rpm .
    COPY pkg/hsm-client-v2.03.15.10-1.x86_64.rpm .
    COPY pkg/hsm-client-jce-v2.03.15.10-2.el8.x86_64.rpm .
    COPY app.jar /app.jar
    
    # 安装依赖和HSM客户端,编译安装OpenSSL 1.1.1d
    RUN yum install -y wget perl gcc zlib-devel make jq \
            /jdk-8xxxx-linux-x64.rpm \
            /hsm-client-jce-v2.03.15.10-2.el8.x86_64.rpm \
            /hsm-client-v2.03.15.10-1.x86_64.rpm && \
        yum clean all && \
        wget https://www.openssl.org/source/old/1.1.1/openssl-1.1.1d.tar.gz && \
        tar -xzf openssl-1.1.1d.tar.gz && \
        cd openssl-1.1.1d && \
        ./config --prefix=/usr --openssldir=/usr/local/openssl shared -pthread && \
        make && make install && \
        cd .. && rm -rf openssl-1.1.1d.tar.gz openssl-1.1.1d
        
    # 修改HSM客户端配置文件
    RUN jq --arg host "$HOSTNAME" --arg crtpath "$CRTPATH" -r \
        '.server.hostname=$host | .client.e2e_owner_crt_path=$crtpath' \
        /opt/hsm/etc/hsm_proxy.cfg > /opt/hsm/etc/hsm_proxy.tmp && \
        mv /opt/hsm/etc/hsm_proxy.tmp /opt/hsm/etc/hsm_proxy.cfg
    
    # 设置启动命令
    RUN echo '#!/bin/sh' > /entrypoint.sh && \
        echo 'printf "%s" "$ISSUERCA" > "$CRTPATH" ' >> /entrypoint.sh && \
        echo '/opt/hsm/bin/hsm_proxy /opt/hsm/etc/hsm_proxy.cfg && sleep 1 && java -classpath "/app.jar:/opt/hsm/java/*" app' >> /entrypoint.sh && \
        chmod +x /entrypoint.sh
    ENTRYPOINT ["/entrypoint.sh"]
  5. 构建镜像

    docker build -t <镜像名称>:<版本号> /home/deploy/centos
  6. 验证镜像是否创建成功

    构建完成后,使用以下命令验证镜像是否创建成功:

    docker images | grep <镜像名称>

Debian

  1. 下载安装包

  2. 在业务代码中集成JCE Provider

    1. Java业务代码中集成JCE SDK,调用其加密服务接口进行加解密运算。关于JCE Provider支持的加密算法和接口,请参见支持机制代码示例

    2. 将集成了JCE ProviderJava项目打包为JAR文件(如app.jar),并将其拷贝至镜像构建目录。

  3. 准备文件目录将安装包和JAR文件放置到/home/deploy/debian目录,目录结构如下:

    /home/deploy/debian/
    ├── pkg/
    │   ├── hsm-client-2.03.15.10-20240710_1.x86_64.deb        # 密码机管理工具
    │   └── hsm-client-jce-2.03.15.10-20240710_1.x86_64.deb     # JCE Provider
    ├── app.jar                                                   # 业务应用JAR
    └── Dockerfile
  4. 创建Dockerfile

    本文以openjdk:8-jdk-jre作为基础镜像时的Dockerfile的编写方法为例。

    # 使用openjdk:8-jre镜像作为基础镜像
    FROM openjdk:8-jre
    
    WORKDIR /
    
    # 将安装包和JAR文件拷贝到镜像
    COPY pkg/hsm-client-2.03.15.10-20240710_1.x86_64.deb .
    COPY pkg/hsm-client-jce-2.03.15.10-20240710_1.x86_64.deb .
    COPY app.jar /app.jar
    
    # 安装依赖和HSM客户端,编译安装OpenSSL 1.1.1d
    RUN apt-get update && \
        apt-get install -y libncurses5 libtinfo5 dpkg wget make perl libtool zlib1g-dev jq && \
        rm -rf /var/lib/apt/lists/* && \
        dpkg -i /hsm-client-2.03.15.10-20240710_1.x86_64.deb \
                /hsm-client-jce-2.03.15.10-20240710_1.x86_64.deb && \
        wget https://www.openssl.org/source/old/1.1.1/openssl-1.1.1d.tar.gz && \
        tar -xzf openssl-1.1.1d.tar.gz && \
        cd openssl-1.1.1d && \
        ./config --prefix=/usr --openssldir=/usr/local/openssl shared -pthread && \
        make && make install && \
        cd .. && rm -rf openssl-1.1.1d.tar.gz openssl-1.1.1d
    
    # 修改HSM客户端配置文件
    RUN jq --arg host "$HOSTNAME" --arg crtpath "$CRTPATH" -r \
        '.server.hostname=$host | .client.e2e_owner_crt_path=$crtpath' \
        /opt/hsm/etc/hsm_proxy.cfg > /opt/hsm/etc/hsm_proxy.tmp && \
        mv /opt/hsm/etc/hsm_proxy.tmp /opt/hsm/etc/hsm_proxy.cfg
    
    # 设置启动命令
    RUN echo '#!/bin/sh' > /entrypoint.sh && \
        echo 'printf "%s" "$ISSUERCA" > "$CRTPATH" ' >> /entrypoint.sh && \
        echo '/opt/hsm/bin/hsm_proxy /opt/hsm/etc/hsm_proxy.cfg && sleep 1 && java -classpath "/app.jar:/opt/hsm/java/*" app' >> /entrypoint.sh && \
        chmod +x /entrypoint.sh
    ENTRYPOINT ["/entrypoint.sh"]
  5. 构建镜像

    docker build --build-arg HOSTNAME=<主密码机IP地址> --build-arg CRTPATH=/opt/hsm/etc/issuerCA.crt -t <镜像名称>:<版本号> /home/deploy/debian
  6. 验证镜像是否创建成功

    构建完成后,使用以下命令验证镜像是否创建成功:

    docker images | grep <镜像名称>

步骤二:推送镜像至ACR镜像仓库

登录容器镜像服务控制台,在容器镜像服务实例中创建镜像仓库。

  1. 创建ACR镜像仓库

  2. 执行以下命令登录镜像仓库并推送镜像

    # 登录ACR镜像仓库
    docker login --username=<用户名> registry.<地域>.aliyuncs.com
    
    # 为镜像设置标签
    docker tag <镜像名称>:<版本号> registry.<地域>.aliyuncs.com/<命名空间>/<镜像仓库>:<版本号>
    
    # 推送镜像
    docker push registry.<地域>.aliyuncs.com/<命名空间>/<镜像仓库>:<版本号>
    说明

    请将<地域>替换为ACK集群所在地域(如cn-hongkong),<命名空间><镜像仓库>替换为在ACR中创建的命名空间和仓库名称。

步骤三:部署应用

创建ACK集群

如果尚未创建ACK集群,请参见创建ACK托管集群,创建时需注意:

重要

ACK集群与密码机集群必须在同一VPC下,否则容器内的hsm_proxy无法连接到密码机实例。

  • 选择与密码机集群相同的专有网络(VPC),确保容器能通过内网访问密码机实例。

  • 确保节点的安全组规则允许访问密码机实例的通信端口。

配置保密字典

业务程序使用JCE Provider时,需要通过密码机中的加密用户(CU)的用户名和密码进行认证。为避免将敏感信息硬编码到部署参数中,建议使用ACK的保密字典(Secret)机制安全存储认证信息。请参考管理保密字典配置ACK集群的保密字典,配置说明如下:

示例值

说明

HSM_USER

crypto_user

密码机加密用户(CU)的用户名。

HSM_PASSWORD

密码机加密用户(CU)的密码。

ISSUERCA

-----BEGIN CERTIFICATE-----

*********

-----END CERTIFICATE-----

创建并激活密码机集群时生成的自签名证书内容。

通过YAML文件创建

  1. Base64编码:使用YAML创建保密字典时,需要先对值进行Base64编码。

    # 生成Base64编码值,以下以生成 HSM_USER为例
    echo -n "crypto_user" | base64
    
    # 创建保密字典
    kubectl apply -f secret.yaml
  2. 创建secret.yaml文件。

    apiVersion: v1
    kind: Secret
    metadata:
      name: app-secret
    type: Opaque
    data:
      HSM_USER: <HSM_USERBase64编码值>
      HSM_PASSWORD: <HSM_PASSWORDBase64编码值>
      ISSUERCA: <ISSUERCA证书内容的Base64编码值>

通过控制台创建

  1. 登录容器镜像服务控制台

  2. 在目标集群的配置管理 > 保密字典> 页面中创建保密字典,逐一添加HSM_USERHSM_PASSWORDISSUERCA三个键值对。

部署镜像

ACR镜像仓库中的业务镜像部署至ACK集群的Pod中,具体操作请参见创建无状态工作负载Deployment

通过YAML文件部署

  1. 创建deployment.yaml文件:在配置中指定保密字典中的数据挂载到/srt目录,并引用环境变量。环境变量参数说明,请参见附录:参数说明

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: hsm-jce-app
      labels:
        app: hsm-jce-app
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: hsm-jce-app
      template:
        metadata:
          labels:
            app: hsm-jce-app
        spec:
          containers:
          - name: jce-app
            image: registry.<地域>.aliyuncs.com/<命名空间>/<镜像仓库>:<版本号>
            env:
            - name: HSM_USER
              valueFrom:
                secretKeyRef:
                  name: app-secret
                  key: HSM_USER
            - name: HSM_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: app-secret
                  key: HSM_PASSWORD
            - name: ISSUERCA
              valueFrom:
                secretKeyRef:
                  name: app-secret
                  key: ISSUERCA
            - name: LD_LIBRARY_PATH
              value: /opt/hsm/lib
            - name: HSM_PARTITION
              value: PARTITION_1
            - name: CRTPATH
              value: /path/to/issuerCA.crt
            - name: HOSTNAME
              value: <hostname>
            volumeMounts:
            - name: secret-volume
              mountPath: /srt
              readOnly: true
          volumes:
          - name: secret-volume
            secret:
              secretName: app-secret
    
  2. 执行以下命令部署应用:

    kubectl apply -f deployment.yaml

通过控制台部署

  1. 登录容器镜像服务控制台

  2. 在目标集群中通过工作负载 > 无状态页面创建Deployment。在镜像配置中指定ACR镜像地址,在环境变量中以保密字典方式引用HSM_USERHSM_PASSWORDISSUERCA

    说明

    请勾选对数据值进行 base64 编码

验证部署

部署完成后,按照以下步骤验证业务容器是否能正常调用密码机的加密服务。

  1. 确认Pod运行状态

    预期输出中,Pod状态为RunningREADY列显示1/1

    kubectl get pods -l app=hsm-jce-app
  2. 检查hsm_proxy连接状态

    进入Pod查看hsm_proxy进程日志,如果日志中显示连接密码机实例成功的信息,表示hsm_proxy已正常运行。

    kubectl exec -it <pod-name> -- cat /opt/hsm/log/hsm_proxy.log
  3. 验证JCE Provider调用

    查看业务应用的运行日志,确认JCE Provider能正常调用密码机的加密服务,如果业务应用能正常完成加解密操作且无异常报错,表示部署成功。

    kubectl logs <pod-name>

常见问题

  • hsm_proxy启动失败,提示连接超时?

    • 确认ACK集群与密码机实例在同一VPC下。

    • 检查安全组规则是否允许ACK节点访问密码机实例的通信端口。

    • 确认Dockerfile中通过--build-arg HOSTNAME传入的是正确的主密码机IP地址。

  • JCE Provider认证失败?

    • 确认保密字典中HSM_USERHSM_PASSWORD的值与密码机中创建的加密用户(CU)凭证一致。

    • 确认保密字典中ISSUERCA的证书内容完整,包含-----BEGIN CERTIFICATE----------END CERTIFICATE-----

    • 如果使用YAML创建保密字典,确认值已正确进行Base64编码。

  • Docker镜像构建失败,提示OpenSSL编译错误?

    • 确认Dockerfile中已安装编译OpenSSL所需的依赖包(gccmakeperlzlib-devel)。

    • 如果编译环境存在网络限制,可先在外部下载OpenSSL源码包,然后通过COPY指令添加到镜像中。

  • Pod启动后立即退出(CrashLoopBackOff)?

    • 检查entrypoint.sh脚本是否正确执行:kubectl logs <pod-name>

    • 确认CRTPATH环境变量指定的路径存在且有写入权限。

    • 确认业务应用JAR文件路径正确且可执行。

附录:参数说明

变量名称

描述

LD_LIBRARY_PATH

/opt/hsm/lib

HSM客户端动态链接库路径。

HSM_PARTITION

PARTITION_1

HSM分区名称。

CRTPATH

示例:/opt/hsm/etc/issuerCA.crt

自签名证书在容器中的存储路径。

HOSTNAME

主密码机实例的IP地址,可在密码机实例控制台查看。