課題ははっきりしています。ノート PC が接続したら、そのノート PC 側で何かが変わるべきだ、というものです。しかし編集している設定はサーバーのものであり、想定が崩れるのはまさにこの点です。サーバーのファイルに書かれたパスはそのサーバー上のファイルを指し、どれだけ push しても実行するプロセスは変わりません。二つのフックのどちらを選ぶかは、どのマシンが作業を所有するかを決め、そこから生じる制約を受け入れるという話がほとんどです。

二台のマシン、まず答えるべき二つの問い

まず状態の変化をどこで起こすべきかを問い、次にどのイベントがそれに対応するかを問います。変化がユーザーごとの認可やクライアントごとの設定判断であれば、ユーザーディレクトリが分かっている場所、つまりサーバーに属します。変化が経路であれば、resolver の設定やエンドポイント上のローカルな補助ツールであれば、エンドポイントに属し、エンドポイントだけがそれを実行できます。

この二つの問いを逆の順序で答えると、Windows ノート PC にバッチファイルを push しようとする結末になります。サーバーは誰が接続したかを知っており、ノート PC は自分のネットワークスタックがどうなっているかを知っています。どちらも相手の情報を持たず、その試みは明確なエラーではなく、たいてい静かに失敗します。

どちらよりも先に、三つ目の問いを立てる価値があります。そのフックをプラットフォームがそもそも提供しているのでしょうか。設定を自前で生成するアプライアンスは同じイベント名を用意していないかもしれませんし、.ovpn ファイルを読み込むデスクトップクライアントは、そのファイルが書かれたクライアントと同じとは限りません。プラットフォームを先に確認すれば、そこに存在しないフックを前提に設計する無駄を省けます。目の前のマシンにどの文書が本当に当てはまるかも分かります。

サーバー側の選択肢 — 接続ごとのイベント

client-connect スクリプトは、認証済みのクライアントが接続したときにサーバーのプロセス文脈で実行され、common name や割り当てられたアドレスといった文書化された接続情報を受け取ります。クライアントごとの設定断片を書き、ポリシー判断を強制し、サーバーが所有する状態を記録するのに適した場所です。

見落とされがちな区別は、このフックとサーバーの up フックの違いです。up フックはサーバーがトンネルデバイスを開くときに発火し、複数クライアントのサーバーではデーモン起動時に一度だけ起こります。ログインごとのイベントではなく、そこに置いたコードはユーザーが接続したときではなくサービス起動時に実行されます。

Web インターフェースを持つアプライアンスでは、生成されたデーモンファイルを編集するのではなく、サポートされている拡張の仕組みを使ってください。生成ファイルは次の保存で書き直され、その書き直しが最悪のタイミングで変更を静かに消してしまいます。拡張テキストのコピーをアプライアンスの外に保管しておけば、ファームウェア更新で意図まで失うことはありません。

クライアント側の選択肢 — ローカルで動かす必要のある作業

コミュニティクライアントは、トンネルデバイスが立ち上がったときと、経路がインストールされたときの二回、ローカルスクリプトを実行できます。これは別々のタイミングであり、間違った方を選ぶと、依存する経路が存在する前に補助ツールが起動するという典型的な競合が生じます。

補助ツールはそのクライアント上に存在し、クライアントを実行するアカウントから読み取りと実行ができ、明示的な script-security 設定で許可されている必要があります。管理者としてクライアントを起動したときに動くスクリプトは、ログイン前のサービスや別ユーザーのセッションについて何も教えてくれません。

名前も重要です。up フックはデバイスの作成に、route-up は経路のインストールに対応しますが、プライベートネットワークに到達できることを必要とする作業は、デバイスの作成がすべての経路・resolver エントリ・アプリケーションの準備完了を意味すると決めつけず、到達性を確認すべきです。

実行可能なコードの push が選択肢にない理由

push で送られるオプションは意図的に制限されており、スクリプトを実行するオプションはサーバーが渡してはならない分類に含まれます。この制約があるのは、そうでなければ侵害された、あるいは設定を誤ったサーバーが、接続してきたすべてのクライアントで任意のコマンドを実行できてしまうからです。

ローカルでのスクリプト実行を有効にしてもそれは変わりません。script-security 設定が許可するのは自分で選んだローカルスクリプトであり、サーバーに新しいスクリプトを配布する権限を与えるものではありません。

目的が単に VPN の経路を入れることなら、遠隔実行の仕組みを考案するのではなく、サポートされている経路設定を使ってください。目的が本当にローカルコードを必要とするなら、組織のエンドポイント管理ツールで配布し、ユーザーの権限で動く他のソフトウェアと同じようにレビューしてください。

どちらのフックを信頼する前に確認すること

フックごとに四つを書き出します。どのマシンか、イベント名は何か、どのアカウントで動くか、そして生み出すべき状態変化は何か。そのうえで接続、再接続、後片付けの経路を試します。再接続で状態を漏らすフックは、一度も動かなかったフックより悪いからです。

実際に実行するアカウントで、実際に実行される瞬間に試してください。openvpn(8) のマニュアルは両方のフックファミリーと push の制約を記述しており、配備するプラットフォームはそれらをそもそも公開しているかを記述しています。対話的な管理者ターミナルで成功するスクリプトは仮説であり、検証ではありません。

関連記事