OpenVPN がサービス化された後に client-config-dir が無視される
相対パスの client-config-dir はデーモンの作業ディレクトリを基準に解決される。ユニットを読み、パスの権限をたどり、最後にログで参照を確認する。
トンネルは上がりクライアントも接続するのに、固定アドレスとその一人のユーザー向けに定義したプッシュルートが見当たりません。ログには “file not found” と出ておらず、これが原因で証明書を作り直しに向かう人が後を絶ちません。こうした事例の多くでは、デーモンがテストに使ったシェルとは別のディレクトリから動いており、client-config-dir は想定どおりに解決されていません。直すべきはパスの修正であって、資格情報の再設定ではありません。
設定に触る前にユニットを読む
編集したファイルではなく、実際に動いているプロセスから始めます。systemd に実行行、作業ディレクトリ、降格先のアカウントを尋ねてください。この三つの答えで、この種の障害の大半が説明できます:
systemctl show openvpn-server@server -p ExecStart -p WorkingDirectory -p User -p RootDirectory空の WorkingDirectory はユニットが / で起動することを意味するため、相対指定の client-config-dir ccd は /ccd で探されます。そのディレクトリはまず存在せず、デーモンもその不在を致命的とは扱いません。
テスト中に使った対話的な起動と比べてみてください。そこではシェルの現在ディレクトリが設定ディレクトリだったはずです。同じファイル、同じキーワード、結果は二つに分かれます。
相対パスは何を基準に解決されるか
キーワードは、そのオプションが使われる時点のプロセスの作業ディレクトリを基準に解決されます。「--config で渡した設定ファイルの隣」という意味ではありません。OpenVPN は絶対パスの設定を平然と読み、相対値はやはり別の場所で解決します。ここがまさに落とし穴です。OpenVPN 2.6 のマニュアルは、その規則を --client-config-dir と --cd の項で述べています。
cd キーワードは他のファイルを読む前にその文脈を変えるので、cd /etc/openvpn/server を設定し、続けて client-config-dir ccd を置いたユニットは /etc/openvpn/server/ccd に解決されます。cd を足す場合は、ディレクティブの順序を確認し、同じファイル内の他の相対参照すべてに影響することを忘れないでください。
デーモンのアカウントとしてパスをたどる
パスが正しくても読めないことがあります。権限を落とした後、デーモンはもう root ではないため、各親ディレクトリにはそのアカウントの検索権限が、クライアントファイル自体には読み取り権限が必要です。親のどれか一つで実行ビットが欠けるだけでファイルは見えなくなり、症状は既定のプールを受け取るクライアントとして静かに現れます。
namei は各要素の権限を順に表示するので、ディレクトリを一つずつ確認するより速く済みます:
namei -l /etc/openvpn/server/ccd/client1次に、自分自身ではなくサービスのアカウントとして読み取りを試します:
runuser -u openvpn -- test -r /etc/openvpn/server/ccd/client1 && echo readableユニットが chroot を使う場合、ディレクトリは監獄の内側に存在しなければならず、設定のパスは chroot の適用後に解釈されます。監獄の外のホストに置かれたファイルは内側からは見えません。
推測せず参照を確認する
再起動一回分だけログ水準を上げ、クライアント固有のオプションについてサーバーが何を言うかを読みます。verb 4 ではデーモンが取り込んだクライアントごとの設定を報告するので、行がなければその接続でどのファイルも読まれなかった直接の証拠になります。
openvpn --config /etc/openvpn/server.conf --verb 4 --client-config-dir /etc/openvpn/server/ccdそれを空きポートで前面実行し、クライアントを一つ接続します。これで systemd は完全に視界から外れます。ここで上書きが現れ、サービス経由では現れないなら、違いはファイルではなくユニットの文脈です。
どのファイルも一致しないときにどうするかを決めます。ccd-exclusive がなければ、クライアントは全体プールの設定だけで受け入れられ、それが先に述べた静かな失敗です。これを付ければ、ファイル不在は接続拒否になり、その拒否は気づきやすい一方、負荷の下では切り分けが難しくなります。
直し、再起動し、検証する
設定の中のディレクトリを絶対パスにし、そのままにします。相対パスが安全なのはユニットが作業ディレクトリを固定しているときだけで、固定は後から誰かが外す余計な可動部でもあります。
client-config-dir /etc/openvpn/server/ccd
ccd-exclusiveインスタンスを再起動し、既知のクライアントを一つつなぎ直して、受け取ったアドレスとそこへプッシュされたルートを読みます。アドレスがそのクライアントのファイルの ifconfig-push 行と一致していれば、参照は機能しています。まだ全体プールに落ちるなら、ログの行数に戻ってください。取り込みがゼロなら パスか身元が誤りであり、内容の違う取り込みが一つあれば、デーモンが読むのとは別のファイルを編集しています。
以前のユニットと設定をまとめて戻してから再起動し、切り戻します。この一連の作業で証明書を再発行する必要はなく、ディレクトリの問題を資格情報の問題として扱うことが、五分で終わる修正を保守作業の時間帯に変えてしまいます。