本文へスキップ
ecdsa.com
Python cryptographyPython の cryptography

エラーメッセージ

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 へのリンクは、エラーメッセージ自体に含まれています。

発生する理由

修正方法

  1. 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. 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. 3.

    フレーミングを機械的に検証する

    BEGIN/END 行が存在して一致しているかを手早く確認すれば、問題が内容にあるのか受け渡しにあるのかを絞り込めます。

    python
    lines = pem.decode().splitlines()
    print(lines[0])   # -----BEGIN PRIVATE KEY-----
    print(lines[-1])  # -----END PRIVATE KEY-----

関連するエラー

署名エラーデータベースをすべて見る