You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AWS ECS容器中OpenSSL无法创建写入p12文件问题排查

问题背景
  • 现有两套Docker镜像:一套为基础镜像,另一套基于该基础镜像构建,用于承载Java微服务。基础镜像配置的entrypoint bash脚本会调用Python脚本完成服务启动流程,现有架构可正常启动微服务,无运行异常,初始架构设计逻辑未知。
  • 需求为在Python启动脚本中新增Java SSL相关参数以支持HTTPS流量处理,参考公司内已落地的同类配置,实现逻辑为:在Python脚本中调用openssl,读取AWS SSM参数中存储的证书内容生成证书文件,最终输出整合全量证书的bundle.p12文件。
故障现象
  • 脚本运行时无法创建目标bundle.p12文件;提前在容器内预置空的bundle.p12文件后,openssl仍无法向该文件写入内容,文件始终保持空白。
  • 执行openssl命令后通过ls -la查看./microservice目录,bundle.p12文件大小仍为0字节,后续keytool执行时报错,提示p12文件已存在但内容为空。
  • 相同的openssl和keytool命令在本地环境执行可正常运行,可成功将证书包导入keystore。

故障相关执行代码:

subprocess.run(['sudo', 'openssl', 'pkcs12', '-export', '-password', 'env:PASSWORD', '-in', './microservice/cloudwild.crt', '-certfile', './microservice/cloudchain.pem', '-inkey' ,'./microservice/cloudwild.key', '-name', 'bundle', '-out', './microservice/bundle.p12'])
subprocess.run(['ls','-la','./microservice'])
subprocess.run(['keytool', '-importkeystore', '-noprompt', '-deststorepass', '$PASSWORD', '-srcstorepass', '$KEYSTORE_PASSWORD', '-destkeystore', './microservice/keystore.p12', '-deststoretype', 'pkcs12', '-srckeystore', './microservice/bundle.p12', '-srcstoretype', 'PKCS12'])
已排查信息
  • 初步怀疑openssl执行权限问题:基础镜像Dockerfile中已将p12文件所在目录及p12文件本身的属主配置为用户"bob",且调用entrypoint bash脚本(Python脚本调用入口)前已切换至bob用户运行。
  • 暂无法定位根因,不确定问题是否与双层镜像构建逻辑、容器运行环境特性、p12文件权限配置相关,可补充提供Dockerfile等配置细节。
排查方向与解决方案

按优先级从高到低排查:

  • 第一优先级:修复subprocess调用的逻辑错误(90%概率为根因)

    1. 去掉openssl命令前的sudo:你已经在启动脚本前切换到bob用户,且提前给目录赋了bob的属主权限,根本不需要提权。容器内普通用户默认无sudo权限,就算配置了sudo权限,默认也不会继承当前shell的环境变量,你写的env:PASSWORD根本读不到对应的密码值,openssl会直接卡在密码输入的交互环节,不会向目标文件写入任何有效内容,最终生成0字节文件。
    2. 修复密码传参逻辑:subprocess以列表形式传参时不会自动解析shell变量,你在keytool命令里写的'$PASSWORD'、'$KEYSTORE_PASSWORD'会被当成明文字符串传递,就算p12文件生成成功,后续keytool也会因为密码错误执行失败。直接从Python的os模块读取环境变量传入即可。
    3. 给subprocess加上check=True参数,让命令执行失败时直接抛出异常,不要静默失败方便排查问题。

    修正后的代码参考:

    import os
    import subprocess
    
    # 提前读取环境变量
    export_pass = os.getenv("PASSWORD")
    keystore_pass = os.getenv("KEYSTORE_PASSWORD")
    
    # 移除sudo,直接执行openssl,显式传入密码
    subprocess.run(
        [
            "openssl", "pkcs12", "-export",
            "-password", f"pass:{export_pass}",
            "-in", "./microservice/cloudwild.crt",
            "-certfile", "./microservice/cloudchain.pem",
            "-inkey", "./microservice/cloudwild.key",
            "-name", "bundle",
            "-out", "./microservice/bundle.p12"
        ],
        check=True,
        capture_output=True,
        text=True
    )
    subprocess.run(["ls", "-la", "./microservice"])
    
    # 传入实际读取到的密码值,不要写$变量占位符
    subprocess.run(
        [
            "keytool", "-importkeystore", "-noprompt",
            "-deststorepass", export_pass,
            "-srcstorepass", keystore_pass,
            "-destkeystore", "./microservice/keystore.p12",
            "-deststoretype", "pkcs12",
            "-srckeystore", "./microservice/bundle.p12",
            "-srcstoretype", "PKCS12"
        ],
        check=True,
        capture_output=True,
        text=True
    )
    
  • 第二优先级:排查目录挂载权限问题
    如果./microservice是容器启动时挂载的外部volume(hostPath、EFS、configmap/secret等),就算你在Dockerfile里给目录设置了bob属主,挂载后权限也会被覆盖:尤其是configmap/secret默认以只读方式挂载,根本无法写入文件。
    验证方式:进入运行中的容器切到bob用户,手动在./microservice目录执行touch test.txt,如果创建失败就是挂载权限问题,把p12生成路径改到容器内原生可写目录(比如/tmp/下),生成完成后再复制到目标路径即可。

  • 第三优先级:排查源证书文件的读权限
    从SSM拉取证书写入本地文件时,如果没有显式设置权限,默认生成的文件可能仅root用户可读,bob用户运行openssl时读不到crt、key文件内容,也会导致执行失败不输出有效p12文件。可以在拉取证书写入后显式调用os.chmod给三个证书文件设置600权限,确保属主为bob。

  • 第四优先级:排查双层镜像构建的权限遗漏
    如果你是在基础镜像层执行了chown bob:bob ./microservice,但上层业务镜像构建时又往该目录拷贝了新的证书文件,新拷贝的文件默认属主是root,会覆盖之前的权限配置。需要确认上层镜像Dockerfile中,拷贝证书文件后是否重新执行了属主授权操作。


内容的提问来源于stack exchange,提问作者Neil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 11:45:31