OpenVPN が証明書と鍵を解決する仕組み:インライン PEM かパスか
同じディレクティブが、ファイルパスか埋め込み PEM オブジェクトのどちらかを運びます。証明書を動かす前に、読み込まれたプロファイルがどちらを使うのかを確認してください。
メッセージは OpenVPN がインライン証明書を読み込めないと言いますが、頭に残っているファイル名は別のことを告げています。cert ディレクティブがまったく異なる二種類の値を受け取るため、ファイルシステムに何があるかよりも、パーサーが何を受け取ったかのほうが重要です。ひとつは開くパス、もうひとつは設定の中に入って届いた PEM テキストです。実行中のクライアントがどちらの形を受け取ったかを知るまでは、どんな修正も推測にすぎません。
二つの保存形式、一つのディレクティブ
cert、key、ca の各ディレクティブは、パスかインライン・ブロックを受け取ります。値がパスなら、OpenVPN はそのファイルを開き、ディスクからオブジェクトを読み取ります。設定が cert タグで区切られたブロックを含む場合は、同じディレクティブがそのタグの間の内容を使い、別のファイルは関与しません。
どちらの形式も最終的に同じ種類のオブジェクトを生み出すので、動作している配備はほかの変更なしに両者を行き来できます。クライアント証明書と秘密鍵を埋め込んだプロファイルは自己完結しており、証明書ディレクトリを一緒にコピーしなくても別のマシンへコピーできます。
逆は成り立ちません。自分のデータを埋め込むプロファイルの隣に client.crt を置いても、設定の中の何もそのファイルを参照していないので何も変わりません。明らかに存在するファイルが無視されているように見える最も一般的な理由がこれです。
インライン・ブロックがオブジェクトになるまで
インラインの内容は設定から取り出され、テキストとして PEM パーサーに渡されます。そのパーサーは通常の境界、つまり BEGIN 行、base64 のペイロード、対応する END 行を期待します。ブロックが失敗したコピーで切り詰められたり、ダウンロード・ページによって HTML で包まれたり、ダッシュを正規化したエディタで開かれたりすると、パーサーは存在しているように見える内容で失敗します。
<cert>
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
</cert>
エラーの文言が誤解を招くのも同じ理由です。インラインという語は読み込み側がどこを見たかを述べており、そこで何を見つけたかではありません。設定で名前を挙げたファイルとそこに埋め込まれたオブジェクトは、基底のバイトが使えないとき同じ苦情を生み出します。
読み込まれたプロファイルが実際にどちらの形を使っているかを、エディタが偶然開いたファイルではなく確認してください:
grep -nE '^(ca|cert|key) |^<(ca|cert|key)>' client.ovpn
パス参照が解決される仕組み
パスの値は、設定を含むディレクトリではなく、クライアントの作業ディレクトリを基準に開かれます。systemd の下ではその作業ディレクトリはユニットが設定したものであり、シェルからの対話的な実行はまったく別のものを引き継ぎます。だから同じ設定ファイルが手作業のテストでは動き、サービスとしては失敗するのです。
相対パスも同じ曖昧さを引き継ぎます。裸のファイル名を見たら、ターミナルと一致していると決めつけずに、本番でプロセスの現在のディレクトリが何かを尋ねてください。
別に保存された証明書については、その上で何かをデバッグする前に、オフラインの解析がオブジェクトを確認します:
openssl x509 -in client.crt -noout -subject -issuer -dates
openssl pkey -in client.key -noout -check
これらのコマンドは、ファイルが読めて構造的に有効であることを証明します。相手が発行者を信頼していること、証明書がまだ有効期間の中にあること、鍵がそれに属していることは証明しません。
パーサーのエラーが伝えられることと伝えられないこと
解析の失敗は、問題を一つの入力と一つの段階に絞り込みます。クライアントが二つの保存形式のどちらを使ったかは述べませんし、オブジェクトが受け入れられたかどうかも述べません。それらは別々の証拠を持つ別々の問いです。
解析が成功したあと、次の失敗はより後の段階に属します。信頼の拒否、用途の不一致、鍵の不一致は、読み込み側ではなく相手か TLS 層が報告します。同じファイルを何度も置き換えても、そのエラーは動きません。
調査中は機密の半分を公開レポートの外に置いてください。ディレクティブ名、エラーのテキスト、ブロックの構造を共有し、鍵の素材と識別可能なペイロードは取り除きます。openvpn(8) のマニュアルは、ファイル・ディレクティブの両方の形式とその背後にある作業ディレクトリの挙動を記述しています。