错误信息
Unable to load PEM file. See https://cryptography.io/en/latest/faq/#why-can-t-i-import-my-pem-file for more details. MalformedFraming
标识符之前的句子是固定的;标识符指出了出错的地方。MalformedFraming 表示没有找到 BEGIN/END 行;MismatchedTags("PRIVATE KEY", "PUBLIC KEY") 表示两者不匹配;InvalidData(Invalid symbol 92, offset 0.) 表示正文不是 base64——92 是反斜杠,说明其中有字面量 \n 序列。
Python cryptography — ValueError from load_pem_* functions
含义
load_pem_private_key / load_pem_public_key / load_pem_x509_certificate 没有找到完整的 PEM 封装结构,即相互匹配的 BEGIN 行和 END 行,以及夹在中间的 base64 正文。末尾的标识符(这里是 MalformedFraming)是解析器给出的诊断;FAQ 链接就直接附在错误文本里。
原因
PEM 被截断或只复制了一部分
常见缺少 END 行(剪贴板内容不完整、YAML 块标量吞掉了最后一行)会破坏封装结构。每个 PEM 都必须以与之匹配的 -----END ...----- 行结束。空值——未设置的机密——也会产生同样的 MalformedFraming。
来自环境变量或配置的转义换行符
常见通过 .env 文件、docker-compose、Kubernetes 清单或 JSON 传递的 PEM,到达时常常变成一行,其中带有字面量 \n 序列。加载函数会报告同一句话,只是末尾变为 InvalidData(Invalid symbol 92, offset 0.)。
BEGIN 或 END 标记损坏
偶见少了一个短横线的标记,或者从文档编辑器中粘贴过来的形似短横线的字符,都无法再界定这个块;END 标签与 BEGIN 标签不一致时,会报告为 MismatchedTags。cryptography 50 能容忍的情况有:块两侧的引号、YAML 缩进、UTF-8 BOM 和 CRLF 换行符。
拼接的证书包中分隔处损坏
罕见包含多个 PEM 块的证书链文件中,只要有一个块丢了 END 行,整个文件就会加载失败——此时加载函数报告 InvalidData(Invalid symbol 45, …),45 是下一个 BEGIN 行的第一个短横线。加载函数报告的是整个文件而不是具体的块——所以要用二分法排查:拆开证书包,逐个加载每个对象,找出损坏的那一个。
修复方法
- 1.
加载前先规范化
把字节交给加载函数之前,先恢复换行符,去掉多余的空白和引号,并确认第一行无误。
python import os pem = os.environ["PRIVATE_KEY"].replace("\\n", "\n").strip().strip('"').encode() assert pem.startswith(b"-----BEGIN"), pem[:30] from cryptography.hazmat.primitives.serialization import load_pem_private_key key = load_pem_private_key(pem, password=None) - 2.
优先使用文件或原生支持多行的机密
以文件形式挂载的机密完全不存在转义问题;Kubernetes Secret 和大多数机密管理服务都能逐字节原样提供 PEM。
python with open("/run/secrets/signing_key.pem", "rb") as f: key = load_pem_private_key(f.read(), password=None) - 3.
用程序校验封装结构
快速检查 BEGIN/END 行是否存在且相互匹配,就能判断问题出在内容本身还是传输环节。
python lines = pem.decode().splitlines() print(lines[0]) # -----BEGIN PRIVATE KEY----- print(lines[-1]) # -----END PRIVATE KEY-----