どの資格情報ソースを使うべきかは、三つの事柄で決まります。人がコンソールに座っているか、秘密をディスクに置いてよいか、別のプロセスがプロンプトに答える必要があるか、です。選択を誤ると、パスワードは完全に正しいのにクライアントがstdinの問題を報告し、ほとんどの人が理由もなくサーバーへ向かってしまいます。まず経路を選んでください。エラーメッセージは、どの経路がそれを生んだかを知って初めて意味を持ちます。

判断を決める三つの条件

コンソールのプロンプトは人を必要とする唯一の経路であり、systemdユニットやコンテナの中で静かに失敗する唯一の経路でもあります。人がクライアントを起動してパスワードを入力すれば、ファイルは関与せず、機密情報がディスクに残ることもありません。クライアントが起動時に動く場合、同じプロンプトはハングになり、タイムアウトは通常、資格情報エラーではなく一般的な接続失敗として現れます。

資格情報ファイルは、プロセスが無人で起動し、管理された権限セットの下で秘密をディスクに残してよい場合の正解です。秘密をまったく書いてはいけない場合、つまり保管庫のみのポリシーや短命トークンの場合は、クライアントが開けるストリームが必要で、実際にはプロセス置換か、ファイルディスクリプタに書き込むヘルパーになります。管理インターフェースは第四の場合を担当します。トンネルのライフサイクルをすでに管理し、ソケット越しに質問へ答えられるコントローラーです。

  • コンソールに人がいる、自動化なし:対話的なプロンプト。
  • 無人起動、秘密を保存してよい:モード0600の資格情報ファイル。
  • 無人起動、秘密を保存してはいけない:プロセス置換、またはシークレットエージェントが書き込むfd。
  • 別のプロセスがクライアントを所有している:管理インターフェース。

二つの答えが当てはまる場合は、秘密をargvとシェル履歴の外に保つほうを選んでください。プログラム引数として渡したパスワードは、プロセス一覧を通じてすべてのローカルユーザーが読めますし、その露出は取り消しにくいものです。

各入力経路が実際に何をするか

--auth-user-pass は単独ではコンソールでユーザー名とパスワードを尋ねます。ファイル名を渡すと、クライアントは最初の行をユーザー名、二番目の行をパスワードとして扱います。引用符、コメント、キーと値の構文は一切サポートされません。これが形式のすべてなので、INIファイルを期待して編集する人はそれを壊します。インラインの <auth-user-pass> ブロックはプロファイル内に同じ二行を保持し、プロファイル自体を秘密にし、秘密鍵と同じ扱いの分類に入れます。

残る二つの経路はストリームとソケットです。OpenVPNは読み取り可能なファイルディスクリプタだけを必要とするため、プロセス置換、パイプで支えられた /dev/fd のエントリ、実体がFIFOのファイル名を受け入れます。管理インターフェースは性質が異なります。クライアントは自分で読む代わりに、監視プロセスに値を尋ねます。この違いは再接続で重要になります。資格情報ファイル、シークレットヘルパーが再び書き込めるFIFO、管理インターフェースは人なしで再供給できますが、プロセス置換はできません。ディスクリプタが最初の読み取りで消費されるからです。

ファイルはちょうど二行でなければならない

壊れた資格情報ファイルのほとんどは二つの失敗パターンで説明できます。WindowsのエディタがCRLFの行末を残すと、復帰文字がパスワードの一部になり、画面では正しく見える値をサーバーが拒否します。二番目の行が空、つまりパスワードがあるべき場所が空行だと、クライアントは空のパスワードを持ち、画面の値が正しく見えてもサーバーは拒否します。パスワードの後ろの余分な改行は無害です。ファイルはエディタではなくシェルから書き、バイトを確認してください。

install -m 600 /dev/null /etc/openvpn/client.creds
printf '%s\n%s\n' "$VPN_USER" "$VPN_PASS" > /etc/openvpn/client.creds
od -c /etc/openvpn/client.creds | head -3

パスは内容と同じくらい重要です。相対パスはプロセスの作業ディレクトリを基準に解決され、サービスではテストしたディレクトリとほとんど一致しません。絶対パスを使い、ファイルはクライアントを実行するアカウントの所有にし、モード0600を保ってグループや他人が読めないようにしてください。OpenVPN 2.6のマニュアルがディレクティブの受け付けられる形式を列挙しています。三つ目を発明する前に確認してください。

サーバーを責める前にファイルを試してください。openvpn --config client.ovpn --auth-user-pass /etc/openvpn/client.creds --verb 4 を実行すると、ファイルが開かれたか、そして後で資格情報が受け入れられたかが出力され、次にどの層を変えるべきか分かります。

ストリーム、stdin、そしてそれらが生むエラー

パスワードをパイプで流すのは多くの人が最初に試す方法で、最も驚きの多い経路です。プロセス置換が動くのは、クライアントが読み取り可能なディスクリプタだけを必要とするからです。openvpn --config client.ovpn --verb 3 --auth-user-pass <(printf '%s\n%s\n' "$VPN_USER" "$VPN_PASS") 。/dev/stdin を渡すのは、クライアントが尋ねる瞬間にstdinがまだ開いていて読み取り可能な場合に限り動きます。すでに消費したパイプラインではそれは成り立ちません。

ERROR: could not read Auth username from stdin には二つの異なる原因があります。一部の2.3.xクライアントでは、このメッセージはstdin処理の欠陥から来ており、後の2.3リリースが修正しました。それほど古いクライアントはアップグレードでしか改善しません。現行のクライアントでは同じ文言は、クライアントがコンソール入力を求め、stdinが端末ではなかったことを意味します。まさにsystemdユニット、cronジョブ、あるいは -t なしで起動したコンテナの状況です。

auth-nocache は壊れたパスワードに見える第三のループを加えます。使用後に資格情報をメモリから捨てるので、ネットワーク変更で起きた再接続には再生するものがなく、プロンプトが戻ります。これは設計どおりに動いているディレクティブです。auth-nocache が変えるのはクライアントがメモリに保つものであって、サーバーやIDプロバイダーがアカウントについて考えることではありません。だから修正は同じファイルを再供給することであり、再起動時に読み直されます。管理された接続では、その供給は承認されたシークレットストアから来るべきで、スクリプト内のパスワードではありません。

別のプロセスがプロンプトを所有する場合の管理インターフェース

トンネルをすでに監視しているコントローラーは、その質問にも答えられます。クライアントを --management 127.0.0.1 7505 で起動し、状態行を読み、>PASSWORD:Need 'Auth' username/password に注目してください。コントローラーは別々のコマンド行で username "Auth" alice に続けて password "Auth" ... と答えます。'Auth' トークンは要求の識別子をそのまま返し、一致しなければ応答は無視され、クライアントは待ち続けます。

代償は、いま手に入れた状態機械です。接続の順序、クライアントの再起動、そしてホスト上の他のユーザーが到達してはならないローカルソケットです。買うのは実行時に供給される資格情報で、ディスク上のファイルも、ハングしうるプロンプトもありません。スタックの他の何もまだこのプロトコルを話さないなら、この経路は保守すべき部品を一つ増やします。

資格情報の問題に見える障害

決して完了しないTLSハンドシェイクや VERIFY ERROR: depth=0, error=certificate signature failure は信頼の問題で、どのユーザー名も読まれる前に起こります。UDPリスナーに向けた proto tcp クライアントも同じ場所で失敗します。パケットが認証段階に届かないので、どのパスワードも連想で間違って見えるのです。資格情報を送る前に証明書検証を有効にしておいてください。見慣れたプロンプトは、誰がパスワードを受け取るかについて何も語りません。資格情報に触る前に証明書チェーン、コモンネーム、トランスポートを確認してください。

プロファイルを組み立てるスクリプトのshellのバグも、もう一つの偽の手がかりです。[ ! -f "$file" ] の中の空白が抜けると command not found が生じ、スクリプトは途中で止まり、プロファイルは再構築されず、クライアントは前のもので起動します。そのエラーは認証ではなくshellに属し、パスワードを何度打ち直しても消えません。

この流れのすべてのプロンプトがこの資格情報とは限りません。秘密鍵のパスフレーズ、HTTPプロキシのログイン、サービスのパスワードは、異なる段階で尋ねられる三つの別の秘密であり、鍵のパスフレーズは通常auth-user-passではなくクライアントやエージェントが扱います。TLSセッションが確立する前にプロンプトが出るなら、あなたは間違った問いに答えており、アカウントのリセットは助けになりません。間違ったプロンプトを除外したら、残りの確認は最も早い層から始めます。

  • 最後の資格情報行ではなく、最初のプロトコルエラーを読んでください。TLS、次に認証、次にpushです。
  • ファイルが二行であり、復帰文字がなく、絶対パスで参照されていることを確認してください。
  • プロファイルとコマンド行がディレクティブについて食い違っていないことを確認してください。
  • 「資格情報が受け入れられた」と「トラフィックが流れる」を分けてください。ルーティングとDNSは後の層です。

クライアントがpush段階に達したら、資格情報を見るのをやめ、サーバーが送ったルートとDNSサーバーを読み始めてください。それが次の問題で、いま直したパスワードとは何の関係もありません。

関連記事