ALBの443/8443リスナーで「端末認証あり」と「Cognito MFA」を1台で分けた話 ― なぜポートで分けるのか
AWS Application Load Balancer(ALB)を1台だけ使い、同じドメインに対して 「端末証明書が必要なアクセス」 と 「端末証明書は不要だが Cognito MFA を使うアクセス」 の2つの入口を用意する構成を実装しました。
443番ポートと8443番ポートでリスナーを分け、それぞれ認証方式を変えています。
https://example.com/(443) : mTLS 端末認証ありhttps://example.com:8443/(8443) : mTLS 端末認証なし + Cognito MFA あり
この記事では、単なる手順だけでなく 「なぜ1台のALBで、しかもサブドメインではなくポートで分けたのか」 という設計判断のところまで踏み込んで整理します。ここが一番わかりにくいところであり、この構成を採る/採らないの判断材料になる部分だからです。

2つのアクセスは「何を確認したいか」が違う
まず、今回分けている2つのアクセスは、確認したい対象がまったく違います。
1. 端末証明書が必要なアクセス(443)
「端末そのもの」が、会社・組織に許可された端末であることを確認したいアクセスです。
ここで守りたいのは「誰か」よりも「どの端末か」です。会社が配布・管理している端末にだけクライアント証明書を入れておき、その証明書を持つ端末以外はそもそも接続させません。
これを実現する仕組みが mTLS(相互TLS)端末認証 です。通常のHTTPSではサーバー証明書だけを確認しますが、mTLSではクライアント側も証明書を提示し、ALBがそれを検証します。ALBのTrust Storeに登録したCA証明書で検証できるクライアント証明書を持つ端末だけが接続でき、証明書が無い/信頼できない端末は、認証情報を入力する画面より手前、TLSハンドシェイクの段階で拒否されます。(具体的な設定や証明書の扱いは、後述の「端末認証の処理の流れと設定のポイント」で説明します。)
具体的なユースケース:
- 社内向けの管理コンソール・運用画面。ID/パスワードが漏れても、未管理の端末(私物PC・ネットカフェ・攻撃者の端末)からはログイン画面にすら到達できないようにしたい。
- 機密データを扱う業務システム。画面やデータを、管理外の端末に一切表示させたくない(=端末経由の持ち出しを構造的に防ぎたい)。
- 攻撃対象領域(アタックサーフェス)を減らしたい。ログインフォーム自体を未管理端末に見せないので、総当たりやクレデンシャルスタッフィングがアプリまで届かない。
2. 端末証明書は不要だが Cognito MFA を使うアクセス(8443)
端末までは限定しないが、「ユーザー本人であること」を強く確認したいアクセスです。
ここで守りたいのは「どの端末か」ではなく「本当に本人か」です。端末は問わない代わりに、ユーザー名・パスワードに加えて MFA でもう一段の本人確認を行います。
今回はこれを Amazon Cognito の Hosted UI と MFA で実現しています。未認証のユーザーはCognitoのログイン画面へ誘導され、パスワードとMFAを通過して初めて背後のサイトへ到達できます。(具体的な設定は、後述の「ユーザー認証の処理の流れと設定のポイント」で説明します。)
具体的なユースケース:
- 社外協力会社・取引先・在宅勤務者など、会社が端末を管理できない/したくない相手。全端末に証明書を配布・更新し続けるのは現実的でない。
- BYOD やモバイルなど、端末が多様で数も多いケース。証明書運用がスケールしない。
- 「どの端末からでもよいが、なりすましだけは強く防ぎたい」アクセス。
まとめると、443は「端末を絞る」入口、8443は「本人を絞る」入口です。守っている軸が違うので、片方だけでは要件を満たせない場面が出てきます。
なぜ「1つのサイト」で入口を分けたいのか
「端末を絞りたいサイト」と「本人を絞りたいサイト」が最初から別システムなら、素直に別々に作ればよい話です。あえて同じドメイン配下で入口を分けたくなるのは、次のような 同一(または密接に関連する)システムに、信頼レベルの違う複数の入口を持たせたい ケースです。
- 同じ業務システムに対して、社内の運用チームは管理端末から入り(443)、社外ユーザーや在宅者は本人確認を強化して入る(8443)。入口ごとに信頼レベルを変えたい。
- 平常時は MFA(8443)で運用し、特権操作や緊急運用のときだけ管理端末限定(443) に切り替える、といった運用の使い分け。
- 小さな社内向けサイトが複数あり、それぞれに ALB を立てるほどではないので、1台のALBに相乗りさせつつ入口の性質だけ分けたい。
逆に言うと、認証後にたどり着く先が完全に別サービスで、URLもそれぞれ独立させたいなら、後述するようにサブドメイン+別ALBのほうが素直です。今回の構成が効いてくるのは「同じ土台の上に、性質の違う入口を安く共存させたい」ときです。
なぜサブドメインではなくポートで分けたのか(この構成の肝)
ここが一番のポイントです。「認証も2種類、転送先も違うなら、最初から mtls.example.com と mfa.example.com のようにサブドメインで分ければいいのでは?」という疑問は当然出てきます。それでもポートで分けているのには、ALB側の制約に根ざした理由があります。
理由①:ALBの mTLS は「リスナー単位」でしか設定できない
ALB の mTLS(相互TLS)は、リスナーに紐づく設定です。Trust Store もリスナーに関連付けます。しかもモードは実質2つしかありません。
- verify … クライアント証明書を必須で検証する。証明書が無い/信頼できない接続はハンドシェイクの時点で拒否。
- passthrough … ALB は検証せず、証明書をそのままバックエンドへ渡すだけ。
Apache の SSLVerifyClient optional のような 「証明書があれば検証、無ければ通してログインへ回す」という中間モードは存在しません。verify なら全アクセスに必須、passthrough なら誰でも通る、の二択です。
つまり 1つの 443 リスナーの中で「証明書あり」と「証明書なし」を混在させることは、ホスト(サブドメイン)でルーティングを分けてもできません。mTLS はルール単位ではなくリスナー単位だからです。
理由②:2つの認証を持たせる=HTTPSリスナーが2つ必要
上記の制約から、mTLSありの入口とmTLSなしの入口を両立させるには、HTTPSリスナーが必ず2つ必要になります。そして、
- 1台のALBでは、HTTPSリスナーを同じ443番に2つ置けません(プロトコル+ポートでリスナーが一意)。
- したがって1台に相乗りさせると、もう一方は別ポート(=8443)にせざるを得ない。
これが「ポート分離」の正体です。奇をてらってポートで分けているのではなく、「1台のALBに2つのHTTPSリスナーを載せる」から必然的にポートが分かれる、という順序です。
理由③:サブドメインで443に揃えたいなら「ALB2台」になる
「URLにポートを出したくない、両方443のきれいなサブドメインにしたい」を実現しようとすると、
mtls.example.com(443・mTLS verify のリスナーを持つALB)mfa.example.com(443・Cognito認証のリスナーを持つALB)
というように、ALBを2台に分けることになります(同一ALBでは443を2つ持てないため)。
ここでコストと運用の話が出てきます。ALB は1台ごとに固定の時間課金+処理量に応じた課金がかかるため、2台にすればおおむね固定費が二重になります。さらに、ターゲットグループ・証明書・DNSレコード・WAFの関連付けなどが、それぞれ2セットぶん増えます。
つまり判断は、ざっくり次のトレードオフに落ちます。
| ポート分離(今回:ALB1台) | サブドメイン分離(ALB2台) | |
|---|---|---|
| ALB台数・固定費 | 1台ぶん | 2台ぶん(およそ倍) |
| 運用対象(TG/証明書/DNS/WAF) | 集約できる | それぞれ2セット |
| URLの見た目 | :8443 が出る |
きれいなサブドメイン(両方443) |
| ユーザーへのポート意識 | 必要 | 不要 |
「同じALB配下でも」認証方式を分けられることの嬉しさは、まさにここにあります。ポートという“見た目の代償”を払う代わりに、ALBを1台に集約し、固定費と運用対象を減らせる、というのが本質的なメリットです。逆に、URLの綺麗さや入口ごとの独立性を優先するなら、素直にサブドメイン+2台にすべきです。どちらが正解というより、「コストと集約」を取るか「URLと独立性」を取るかの判断になります。
理由④:振り分けは「自動」ではなく「意図して選ぶ入口」
ここは誤解されやすい点なので明確にしておきます。この構成は、端末に証明書があるかを見て自動で振り分けているわけではありません。 前述のとおり verify モードには「証明書が無ければMFAへ回す」といったフォールバックが無いため、ALB側で自動判定はできません。
利用者(またはその端末に配られたブックマーク/ショートカット)が、443か8443かを選ぶことで入口=信頼レベルが決まります。 ポートそのものが「どの入口を通るか」の明示的なスイッチになっている、という設計です。
とはいえ、実運用でエンドユーザーがその都度ポートを手打ちするわけではありません。多くの場合、
- 管理端末には、証明書と一緒に
https://example.com/(443)のショートカットを配布する - 社外・在宅ユーザーには、
https://example.com:8443/のリンクを案内する
というように、利用者の立場に応じて“通るべき入口”を最初から配っておく運用になります。ポートはURLに現れますが、ユーザーが毎回意識して選ぶというより、配布時点で入口が決まっているイメージです。
(参考)自動振り分けにしたいなら:passthrough + アプリ側判定
「どうしても1つのURL(1リスナー)で、証明書があればそのまま、無ければMFAへ、と自動で振り分けたい」という要件なら、別のアーキテクチャになります。
- 443リスナーを passthrough にして、クライアント証明書の有無・内容を
X-Amzn-Mtls-Clientcertヘッダとしてバックエンドへ渡す - アプリ側で 証明書の有無を判定し、無ければ Cognito のログインへリダイレクトする
これなら入口は1つにできますが、証明書の検証ロジックがALB(エッジ)からアプリ側へ移るため、
- 「未管理端末はアプリに届く前にハンドシェイクで拒否」という、エッジでの端末ゲートの利点が失われる
- 検証・判定の実装責任がアプリ側に乗る
というデメリットがあります。今回は「端末の遮断はできるだけ手前(ALB)で確実に効かせたい」ことを優先し、あえて verify モードでリスナーを分ける構成を選びました。自動振り分けの手軽さより、エッジで端末を弾ける確実さを取った、という判断です。
補足:2つめのリスナーに何番ポートを使うか(8443を選んだ理由)
2つめのHTTPSリスナーに割り当てるポート番号は、ある程度自由に選べますが、慣例に沿って選ぶのが無難です。ポート番号は用途で3つの範囲に分かれています。
- ウェルノウンポート(0〜1023) … HTTPの80、HTTPSの443など、主要プロトコル用に予約された範囲。
- 登録済みポート/ユーザーポート(1024〜49151) … アプリケーションが用途を登録して使う範囲。
- 動的・プライベートポート(49152〜65535) … 一時的な通信などに使われる範囲。
一般ユーザー権限で動作するサーバーソフトウェアは、ウェルノウンポート(1024未満)を直接バインドできないことが多いため、1024〜49151番(登録済み/ユーザーポート)または 49152〜65535番(動的・プライベートポート)を使うのが一般的です。ALB自体はマネージドサービスなので任意のポートを指定できますが、番号選びは同じ慣例に従っておくと分かりやすくなります。
今回、2つめのHTTPS入口には 8443 を採用しました。8443は登録済みポートの範囲にあり、「代替HTTPS」として広く使われているため、番号を見ればHTTPSの別入口だと連想しやすいのが利点です。(逆に 444 のようなウェルノウンポート内の番号は、本来別プロトコル用に予約されているため避けるのが無難です。)
構成イメージ
利用者ブラウザ
|
+-- https://example.com/ (管理端末に配布)
| |
| +-- ALB HTTPS :443
| |
| +-- mTLS端末認証あり(verifyモード)
| +-- Trust Storeでクライアント証明書を検証
| +-- 証明書が無い/信頼できない端末はハンドシェイクで拒否
| +-- EC2 Windows Server / IISへ転送
|
+-- https://example.com:8443/ (社外・在宅ユーザーに案内)
|
+-- ALB HTTPS :8443
|
+-- mTLS端末認証なし
+-- Cognito Hosted UIでログイン
+-- Cognito MFAで追加認証
+-- EC2 Windows Server / IISへ転送
ALBは1台。HTTPSリスナーを443と8443の2つ作り、リスナー単位で認証方式を分けています。
端末認証の処理の流れと設定のポイント
ここでは、443番ポート(mTLS端末認証あり)の入口について、アクセス時の流れと設定上のポイントを説明します。
443番ポートでは、ALBのHTTPSリスナーで mTLS の verify モードを有効にしています。ブラウザがアクセスすると、ALBはクライアント証明書の提示を求めます。

証明書がない端末、またはTrust Storeで信頼できない証明書を持つ端末は、ALBの段階で拒否されます。そのため、EC2やIISまでリクエストが届く前に、端末単位でアクセス制御できます。

設定のポイント
- ALBでHTTPS化する
- ALBリスナーで mTLS verify モードを有効化する
- Trust StoreにCA証明書を登録する
- 端末にはクライアント証明書をインストールする
- 証明書がない端末はアクセスできない(ハンドシェイクで拒否)
端末証明書の作成方法について
本番向けに考える場合、秘密鍵をエクスポート可能なPFXとして配布するよりも、各Windows端末で秘密鍵を作成し、その端末上でCSRを作る方式が望ましいです。
端末側で秘密鍵を作り、CSRだけを認証局に渡してクライアント証明書を発行します。発行された証明書だけを元の端末へ戻してインポートすれば、秘密鍵を端末外へ出さずに運用できます。
ALB Trust Store に登録する証明書について
ALB Trust Storeに登録するのは、クライアント証明書そのものではなく、それを発行したCA証明書です。
ALBは、ブラウザから提示されたクライアント証明書が、Trust Store内のCAで信頼できるかを確認します。このため、端末ごとの証明書ではなく、信頼する発行元CAを登録する必要があります。
ユーザー認証の処理の流れと設定のポイント
ここでは、8443番ポート(Cognito MFA)の入口について、アクセス時の流れと設定上のポイントを説明します。
8443番ポートでは、mTLS端末認証は使わず、Cognitoによるユーザー認証を使います。端末証明書ではなく、ユーザー名・パスワード・MFAによる本人確認を行う入口です。
ALBのリスナーアクションにCognito認証を設定すると、未認証のユーザーはCognito Hosted UIへリダイレクトされます。ログインとMFAが完了すると、ALB配下のIISサイトへアクセスできます。



設定のポイント
- ALBでHTTPS化する
- mTLS端末認証は無効にする
- ALBリスナーでCognito認証を有効化する
- Cognito User PoolでMFAを有効化する
- ログインとMFA完了後にIISサイトへ転送する
今回使った主なAWSサービス
- Elastic Load Balancing – Application Load Balancer
- AWS Certificate Manager
- Application Load Balancer Trust Store
- Amazon Simple Storage Service
- Amazon Route 53
- Amazon Cognito User Pools
- Amazon EC2 Security Groups
- Amazon EC2 for Microsoft Windows Server / Internet Information Services
まとめ
今回の構成では、ALBのリスナー単位で認証方式を分け、端末を絞る入口(443・mTLS) と 本人を絞る入口(8443・Cognito MFA) を、1台のALB上に共存させました。
設計のキモを整理すると次のとおりです。
- ALBのmTLSは リスナー単位 の設定で、「証明書があれば検証、無ければ通す」中間モードが無い。だから2種類の認証には HTTPSリスナーが2つ 必要になる。
- 1台のALBでは443を2つ持てないため、もう一方は 必然的に別ポート(8443) になる。これが「ポート分離」の理由。
- サブドメインで両方443に揃えたいなら ALB2台 が必要で、固定費・運用対象が増える。ポート分離は 「1台に集約してコストと運用を抑える」 選択肢。
- 振り分けは 自動ではなく、利用者の立場に応じて“通る入口(ポート)”を配る運用が前提。
- 自動振り分けが要件なら passthrough + アプリ側判定という別解もあるが、エッジで端末を弾ける確実さと引き換えになる。
mTLSは端末そのものを制御したいときに、Cognito MFAはユーザー本人確認を強化したいときに有効です。URLの綺麗さ・入口の独立性を重視するならサブドメイン+複数ALB、コストと集約を重視するなら今回のポート分離、というように、要件に合わせて選び分けるのがよいと思います。