複数の up スクリプトという警告はスケジュールの不満のように読めるため、明白な修正はそれが消えるまで行を並べ替えることです。しかしスケジュールの不満ではありません。後から来た --up 定義が、その段階のためにすでに保存されていたコマンドを置き換え、パーサーもそう告げます。つまり、二つのスクリプトのうち実際に実行されたのは正確に一つだけです。もう一つはその後ろで順番待ちしているのではなく、消えています。

だからこそ、致命的ではないのにこの警告は注意に値します。それが予告しているのは、静かに起きなくなった DNS 更新やルート変更だからです。

警告は順序の話ではない

OpenVPN は up 段階のためにユーザースクリプトのコマンドを一つだけ保存します。パーサーがプロファイルやインクルードされたファイル、コマンドラインから別の定義に出会うと、すでに保持していたものを置き換え、警告を出します。何も連結されず、何も二度実行されず、順序の問いも存在しません。生き残るのはパーサーが最後に見たコマンドであり、だからこそ行を動かすと勝者が変わり、もう一つのスクリプトは死んだままになります。

同じパターンは他のスクリプト段階にも当てはまります。それぞれに一つのコマンドです。二つの作業を両方行う必要があるなら、一覧のように見える二つの指示ではなく、単一の入口が必要です。

実際の起動で両方の定義を見つける

編集したプロファイルではなく、デーモンが実際に受け取ったものから始めてください。ps -ef とユニットの ExecStart はコマンドラインを示し、そこにはコンテナのエントリポイントやラッパーから --up が追加されていることがあります。ディストリビューションの init ファイルも同じことをします。systemctl cat openvpn-server@server はサービス自体が何を加えているかを明らかにし、設定ディレクトリ上の再帰的な grep がファイルレベルの定義を見つけます。重複は通常、異なる層から来るので、一つのファイルを編集しても何も変わらないのです。

スクリプトを別のディレクトリにコピーしたり名前を変えたりしても、指示は消えません。パーサーはファイルではなく定義を数えます。

一つのフックに作業を任せる

持続する修正は、二つの動作を意図した順序で実行する単一のディスパッチャーです。set -eu を備えた短いシェルスクリプトが、必要な統合処理を呼び、続いてローカルの動作を呼び、引数の境界が保たれるように "$@" を転送することで、振る舞いは検証可能な一か所に収まります。引数の転送は引数を保つだけで、二つのヘルパーが同じインターフェースを期待していることは証明しません。だからそれぞれの契約を読んでください。失敗したときに何をすべきか、部分的な変更を元に戻す必要があるかを決めてください。

起動側がサポートされた拡張フックを提供しているなら、手作りの連結よりそれを優先してください。コンテナイメージやベンダーのパッケージには追加作業のための文書化された場所があることが多く、それを使えばアップグレードがディスパッチャーを上書きしません。

後片付けは対応する down 段階に属します。DNS を書き換えたりルートを追加したりする up の動作には、文書化された取り消しが必要です。そして 起動だけを扱うディスパッチャーは設計の半分です。

静けさではなく統合を確認する

重複警告を取り除くのは簡単な部分で、統合はまだ機能しなければなりません。接続後に resolvectl status で、または /etc/resolv.conf を読んでリゾルバの状態を確認し、ip route でルートを確認してください。その後いったん切断して再接続します。急いで連結したフックは前のセッションから何かを残しがちだからです。journalctl -u openvpn-server@server -b はディスパッチャーが実行されたか、何を出力したかを示します。

フックの権限はあるべき場所に保ってください。script-security を上げたり、デーモンをより多くの権限で動かしたりすることは、置き換えられたフックの修正ではありません。将来のあらゆるスクリプト、攻撃者が名前を付けるスクリプトまでもができることを広げてしまいます。

修正が本物である証拠は、ログの静けさではありません。二回の再接続の後も、DNS の応答、ルートの項目、後片付けがすべて正しく振る舞うことです。

関連記事