手当たり次第に書くんだ

飽きっぽいのは本能

PEM 形式の証明書・秘密鍵を 1 行に整形する方法 – SAML、Kubernetes Secret、環境変数で扱う

SAML、OIDC、Kubernetes Secret、Ansible 変数、JSON / YAML の設定値などで、PEM 形式の証明書や秘密鍵を 1 行の文字列として扱いたい場面があります。

ただし、「PEM を 1 行にする」と言っても、実際には 2 つの意味があります。1 つは BEGIN / END 行を除いた Base64 本体だけを 1 行にすることです。もう 1 つは BEGIN / END 行を含む PEM 全体を、改行をエスケープした文字列として扱うことです。この 2 つを混同すると、SAML 設定、Kubernetes Secret、アプリケーション設定で失敗しやすくなります。

PEM 形式の構造

PEM 形式の証明書は、BEGIN 行、Base64 本体、END 行で構成されます。

-----BEGIN CERTIFICATE-----
MIID...複数行の Base64...
-----END CERTIFICATE-----

秘密鍵も同じように PEM 形式で表現されます。ただし、ヘッダーは鍵の種類によって異なります。

-----BEGIN PRIVATE KEY-----
MIIE...複数行の Base64...
-----END PRIVATE KEY-----

ここで大事なのは、BEGIN / END 行も含めて PEM 形式であるという点です。証明書を扱う設定項目によっては、Base64 本体だけを求めるものもあれば、BEGIN / END 行を含む PEM 全体を求めるものもあります。

Base64 本体だけを 1 行にする場合

SAML の証明書設定などでは、BEGIN / END 行を除き、Base64 本体だけを 1 行にして貼り付ける形式があります。この場合は、PEM 全体ではなく、証明書本体の Base64 文字列だけが必要です。

awk 'NF && $0 !~ /-----BEGIN/ && $0 !~ /-----END/ { printf "%s", $0 }' server.crt

この処理では、空行、BEGIN 行、END 行を除外し、Base64 本体だけを改行なしで連結します。SAML IdP / SP の管理画面で証明書欄に貼り付ける場合などは、この形式が求められることがあります。

PEM 全体を 1 行の文字列として扱う場合

一方で、環境変数、JSON、YAML、アプリケーション設定では、BEGIN / END 行を含む PEM 全体を 1 つの文字列として渡したい場合があります。この場合は、改行を削除するのではなく、改行文字を \n としてエスケープします。

python3 -c 'import pathlib; print(pathlib.Path("server.crt").read_text().replace("\\n", "\\\\n"))'

この形式では、文字列としては 1 行ですが、アプリケーション側で \n を実際の改行として解釈できる必要があります。単に貼り付ければよいのか、アプリケーション側で復元処理が必要なのかは、利用する製品やライブラリの仕様に依存します。

要求形式を先に確認する

PEM を 1 行に整形するときは、先に「何を要求されているのか」を確認します。Base64 本体だけを要求している設定に、BEGIN / END 行を含めて貼り付けると失敗します。逆に、PEM 全体を求めている設定から BEGIN / END 行を削ってしまうと、証明書や秘密鍵として読み込めません。

要求される形式渡す内容代表例
Base64 本体のみBEGIN / END 行を除外し、改行も除去するSAML の一部設定、証明書欄
PEM 全体BEGIN / END 行を含める証明書ファイル、秘密鍵ファイル
PEM 全体の文字列BEGIN / END 行を含め、改行を \n として表現する環境変数、JSON、YAML の値

Kubernetes Secret では base64 と PEM を混同しない

Kubernetes Secret では、マニフェスト上の data フィールドに base64 エンコードした値を入れます。これは PEM の中身が Base64 であることとは別の話です。PEM ファイル全体を Secret に入れる場合は、PEM ファイルの内容をさらに base64 エンコードして格納することになります。

kubectl create secret tls example-tls \
  --cert=server.crt \
  --key=server.key \
  --dry-run=client -o yaml

Secret の tls.crttls.key は、Kubernetes 上では base64 文字列として保存されます。しかし、Pod にマウントされた後は通常の PEM ファイルとして見えます。つまり、保存形式と利用時の形式を分けて考える必要があります。

秘密鍵を 1 行化するときの注意

証明書と違い、秘密鍵は漏えいした時点で影響が大きくなります。1 行化すると、環境変数、CI/CD の変数、チャット、チケット、ドキュメントへ貼り付けやすくなりますが、それは同時に漏れやすくなるということでもあります。

秘密鍵を扱う場合は、値の整形方法だけではなく、どこに保存するのか、誰が参照できるのか、ログに出ないか、バックアップや監査ログに残らないかを確認します。整形は作業上の都合ですが、秘密鍵管理は設計上の問題です。

まとめ

PEM 形式の証明書や秘密鍵を 1 行に整形する場合は、Base64 本体だけが必要なのか、BEGIN / END 行を含む PEM 全体が必要なのか、PEM 全体をエスケープ済み文字列として渡すのかを先に確認します。

特に SAML、Kubernetes Secret、環境変数では、同じ「1 行化」でも意味が変わります。証明書や秘密鍵は、文字列として整形できればよいものではありません。どの形式で、どの境界に渡し、どこで復元されるのかを意識して扱う必要があります。

参考
書籍
参考書籍

暗号技術入門 第 3 版 秘密の国のアリス

公開鍵暗号、電子署名、証明書など、TLS や内部 PKI の前提になる暗号技術を確認したい場合の参考書籍です。価格や在庫はリンク先で確認してください。

Amazon で見る

このリンクは Amazon アソシエイトリンクです。

関連する記事

あわせて読みたい:

PEM 形式の証明書・秘密鍵を 1 行に整形する方法 – SAML、Kubernetes Secret、環境変数で扱う

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

トップへ戻る