ALB経由でWindows認証をしたら起きたこと

目的

お客様環境でALB経由でADFS(Active Directory Federation Service)での証明書Web登録を行っており、証明書Web登録にはWindows認証を経る必要があるのですが、その際に思わぬ想定外の事態が発生しました。これはALBとWindows認証の相性が悪いことに起因する不具合です。

そこでその起きてしまった事象を教訓とし、アイレット社内での知見として共有して広めておき、再発防止を強化する目的で、今回奇遇にもインシデントを通してセキュリティに関する注意点や、対策を共有するインシデント供養祭という場を与えられたため、LTとして発表してみようと思いました。

今回の事象はセキュリティインシデントと言うと少し大袈裟かもしれませんが、情報も少なく、ぜひ共有しておきたいノウハウとなります。

アジェンダ

  1. 起きた事象
  2. 事象の再現方法
  3. 原因及び対策
  4. 改善策
  5. まとめ

(予備知識)Windows認証とは

(統合)Windows認証とは、Active Directoryのユーザーアカウントを使用して接続先サービスにて認証するIISの機能です。あるWebサイト配下の特定のパスに対して認証を要求するように設定します。IISサーバーとアクセスするWindowsクライアントの双方が同じADドメイン環境配下に存在している場合は、手動でのユーザー情報の入力をする必要がないこと以外は、基本(Basic)認証と同じです。

制限事項として、以下の2点があります。

  • 通信経路上にHTTPプロキシが存在している場合は利用できません。
  • Microsoft 社のソフトウェア間でのみ実装可能となっています。

ネットワーク構成

  1. ADFSにIIS+ADCS(+証明機関Web登録)サービスをインストール
  2. test01ユーザーはALB経由でIISのページ(https://〜/certsrv)にアクセスする時に、ADを通してWindows認証を受ける
  3. その後、test01用のクライアント証明書が発行される

このとき、何が起きたか?

この証明書発行サービスの運用が一部ユーザーに本格稼働してから数日後、お客様から次のような報告が寄せられました。

利用者から「発行したユーザーIDとは異なるユーザーの証明書がインストールされている」との問い合わせを受けております。ユーザーID test01のユーザーに、test02の証明書がインストールされています。
現象が発生したユーザーに状況をヒアリングしたところ、「異なる2つのPCに同一ユーザーIDの証明書を発行、インストールしようとしていたところ、発行先が異なるIDのものがインストールされた。」という情報も得ました。
複数のユーザーから同様の問い合わせを受けております。

つまり、他人のクライアント証明書が誤発行されている!
例えば、test02ユーザーに対して発行されてはいけないtest01のクライアント証明書が発行されてしまっているということ。

事象再現

  1. 利用者test-01がnozaki-bastionでtest01ユーザーでcertsrvにログインしておく
  2. 利用者test-02がnozaki-WAPでブラウザのキャッシュ等全て削除しておき、1.のあとアイドルタイムアウトの60秒以内にcertsrvにアクセスする
  3. Windows認証が出るが、無視してリロードを繰り返す
  4. やがて認証なしで証明書を発行できるようになるので、証明書を発行する
  5. するとnozaki-WAPのブラウザで、ユーザーtest02にtest01ユーザー用の証明書が発行される

ちなみにALBを介していないIISで同様の方法を試しましたが、こちらは再現しませんでした。

原因とその対策方法(参考になったサイト)

ALBではプロキシサーバみたいな動きをします。ターゲットインスタンスへ接続情報を渡す際に、IPアドレスなどがALBとなります。そのためWebサーバは「こっちで持っているユーザ情報と一致しない」状況となってしまいます。仮に接続出来たとしても「ALBさんいらっしゃい」と全ユーザ共通で出てしまうのです。

  • Windows Authentication fails with AWS Application ELB」

(翻訳)
ALBを構成しているときに、Windows認証に関連する奇妙な問題に遭遇しました。HTTPリスナーで構成された内部ALBを経由すると、ターゲットWebサーバー (IIS) は常に資格情報の入力を要求し、正しい資格情報を受け入れず、ログオンの問題が発生したり、他のユーザーのセッションに接続したりすることがありました。いくつかの調査の後、最初に使用したALBの代わりに新しいNLBを作成したところ、機能し始めました。

Windows認証 (Kerberos または NTLM フォールバック) では、認証を維持するためにTCP接続が同じ送信元ポートを維持する必要があります。これはHTTPでは発生せず、ブラウザが送信元ポートを切り替えると、新しいTCPセッションが作成され、古いポートを介してWebサーバーにプロキシされ、認証が無効になります。これは、レイヤ4の「ネットワーク」ロードバランサーでは発生しません。レイヤ7の「アプリケーション」ロードバランサーを介したWindows認証はできません

(翻訳)
Windows認証では、クライアントからサーバーへの接続で送信元ポートが保持される必要がありますTCP リスナーを備えたNLBは、負荷分散された接続の送信元ポートを保持します。このため、Windows認証を使用する場合は、NLBを使用してください

改善できるところがあるとすれば

  • ALBはプロキシのような動作をするので、ALBを選定する際、その送信元IPアドレスとポート番号が変わる動作が既存の構成に支障を与えないかもう少し配慮しておく必要があった。
  • 今回検証段階でWindows認証が無事通ってしまい、ALBのプロキシ動作がたまたま悪さをしなかったために、この不具合に気付くことができなかった。
  • ALBとWindows認証の相性の悪さを伝えている日本語のサイトが1つか2つくらいしかヒットしなかった。AWSの公式ドキュメントは、「ALB Windows Authentication」と英語だけで検索すればヒットした。AWSの公式docsはまだまだ英語のみの情報が多いため、英語キーワードだけで検索する癖を付けておきたい。

まとめ

  • Windows認証では、TCP接続が同じ送信元ポートを維持する必要がある
  • Windows認証は、HTTPプロキシと相性が悪い
  • ALBはプロキシサーバのような動作をする
  • ALBを経由してWindows認証を行うと、正しい資格情報でログオンできなかったり、他のユーザーのセッションに接続したりする
  • レイヤ7のALBを介したWindows認証はできない
  • NLBは、送信元ポート番号を保持するため、Windows認証を使用する場合はNLBを使用する
  • ALBを使うなら、今ならALBの相互認証(mTLS)によるクライアント証明書認証を使うという手も