Azure App Service で「最小受信 TLS バージョン=1.2」に設定しているのに、本番だけ TLS 1.2 接続が弾かれる――よくあるのはカスタム ドメインや SNI の問題と思いがちですが、原因は別にあります。本稿では、Minimum TLS Cipher Suite の不整合がもたらす症状と、実際に有効だった具体的な対処・検証・運用のポイントを一気通貫で整理します。
Azure App Service で TLS 1.2 が「拒否される」症状の全体像
今回のケースの前提は次のとおりです。
- 対象は本番の Azure App Service(プラン P0v3)。
アプリ設定では「最小受信 TLS バージョン=1.2」にしている。 - 開発環境(プラン D1)では同じ設定でも TLS 1.2 で正常に疎通できる。
- Postman で「TLS 1.3 を明示的に無効化」してテストすると、本番だけ失敗する。
- 環境差として、本番にのみカスタム ドメインの SNI バインドが存在する。
| 項目 | 本番(P0v3) | 開発(D1) | 備考 |
|---|---|---|---|
| 最小受信 TLS バージョン | 1.2(設定済み) | 1.2(設定済み) | 両環境で一致 |
| Minimum TLS Cipher Suite | 不適切な値(後述) | 許容側の値 | ここが根本の差分 |
| カスタム ドメイン | あり(SNI バインド) | なし | 直接原因ではなかった |
| Postman(TLS 1.3 無効) | 失敗 | 成功 | 切り分けに有効 |
結論(先に要点)
「最小受信 TLS バージョン=1.2」の設定だけでは足りず、Minimum TLS Cipher Suiteが TLS 1.2 ハンドシェイクに合致する必要があります。今回の事象は、ポータルの[設定]→[構成]→「Minimum TLS Cipher Suite」において不適切な暗号スイートが選ばれていたことが原因でした。
対処として、TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256(一覧の上から 7 番目前後)を選択して保存。およそ1〜2 分で反映され、再テストすると TLS 1.2 で正常に通信できるようになりました。
重要:利用中の証明書アルゴリズム(RSA / ECDSA)と暗号スイートの組み合わせが合っていないと交渉は失敗します。上記は ECDSA 系スイートです。RSA 証明書を使う場合は「…_RSA_…」のスイートを選ぶのが原則です。
なぜ「最小 TLS バージョン」だけでは解決しないのか
App Service では TLS 終端はアプリ プロセスではなくフロントエンド(マネージドなリバースプロキシ層)で行われます。よって、アプリの環境変数変更や再起動の成否は TLS バージョン交渉の可否に影響しません。フロントエンドのポリシーは大きく以下で決まります。
- 「最小受信 TLS バージョン」… 交渉を許すプロトコルの下限(例:1.2 以上)
- 「Minimum TLS Cipher Suite」… 交渉を許す暗号スイートの下限(Azure が定義する優先度リストでの基準点)
クライアントが TLS 1.2 で接続し、かつクライアント側が提示する暗号スイート群に「サーバ側の最小許容より強度が低い(リスト順位が上位=弱い)ものしか含まれない」場合、ハンドシェイクは成立しません。
今回、開発(D1)は「緩め」のスイート下限、本番(P0v3)は「厳しめ」の下限が選ばれており、TLS 1.2 では一致する集合が空になっていたのが敗因でした。
誤解されがちな「カスタム ドメイン」「SNI バインド」の影響
カスタム ドメインや SNI バインドは、同一 IP で複数証明書を切り替えるための仕組みです。SNI は「どのホスト名の証明書を提示するか」を決めるだけで、TLS バージョン/暗号スイートの交渉可否そのものを左右する設定ではありません。
実際に SNI バインディングの再作成(削除→再追加)を行っても、今回の現象は改善しませんでした。カスタム ドメインは直接原因ではないというのがポイントです。
再現と切り分け:最短で原因へ辿り着くチェックリスト
現場で手早く確証を得るための手順を提示します。Postman を例にしていますが、curl / OpenSSL でも同様です。
- クライアント側でTLS 1.3 を無効化して接続テスト。
→ 本番だけ失敗するなら、TLS 1.2 交渉に限定したときのサーバ設定不整合を疑う。 - 同一ドメインに対し、別リージョン/別プランのテスト用 Web Appを作って比較。
→ 差分が「Minimum TLS Cipher Suite」に集約されがち。 - 証明書種別(RSA / ECDSA)を確認。
→ スイート名に_RSA_か_ECDSA_が含まれることを対応付ける。 - ポータルの「Minimum TLS Cipher Suite」を確認し、適切な基準点へ変更。
- 1〜2 分待機後、再度 TLS 1.2 の接続を確認。
(外部診断ツールで受け口のバージョン/スイートも併せて確認)
| 観測結果 | 示唆される原因 | 次アクション |
|---|---|---|
| TLS 1.3 有効では成功、1.2 強制で失敗 | 1.2 の暗号スイート集合が交差しない | Minimum TLS Cipher Suite を緩める/適合させる |
| 同アプリを dev では再現せず | プラン/構成差(特に Cipher Suite) | 両環境の Cipher Suite 設定を比較・統一 |
| SNI バインド作り直しでも変化なし | バインド自体は無関係 | TLS ポリシー側を重点確認 |
対処手順(ポータル中心・確実版)
ポータルでの操作
- 対象の App Service を開く。
- [設定]→[構成]を開き、「Minimum TLS Cipher Suite」のプルダウンを確認。
- 不適切な値が選ばれていた場合、
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256へ変更(本ケースの解決例)。 - [保存]をクリックし、1〜2 分待つ(反映はフロントエンド側)。
- クライアントから TLS 1.2 を明示して再テスト。
補足:ポータルのスイート一覧は UI の更新により表示順が変わる場合があります。「上から 7 番目前後」という目安に依存せず、文字列(スイート名)を確実に確認してください。
CLI / IaC での反映(補足)
現時点では、「最小受信 TLS バージョン」は CLI や IaC で一般的に管理できますが、「Minimum TLS Cipher Suite」はポータル設定が最短・確実です。運用標準としてはポータルで変更し、変更理由と値を記録しておくのが安全です(変更管理テンプレートは後述)。
検証の実際:コマンド例
curl(TLS 1.2 限定)
curl -svo /dev/null https://your.domain.example/ --tlsv1.2 --http1.1
成功時は TLS 1.2 とサーバ証明書の情報が表示されます。失敗時は handshake failure などで切断されます。
OpenSSL(提供可能な環境限定)
openssl s_client -connect your.domain.example:443 -tls1_2 -servername your.domain.example
サーバが提示する証明書の署名アルゴリズム(RSA/ECDSA)と交渉済みスイートを確認できます。証明書アルゴリズムと暗号スイートの整合を必ずチェックしましょう。
「Minimum TLS Cipher Suite」を理解する
この設定は、Azure 側が定義する並び順における許容の下限を選びます。たとえば「TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256」を選ぶと、これより強度が高い(=より新しい)スイートは許容されますが、これより下位(弱い)スイートは拒否されます。結果として、古い TLS 1.2 クライアントで「CBC ベースのみ対応」などの偏りがある場合、サーバ側の基準が厳しすぎると交差がなくなるため接続できなくなります。
なお、一般論としては GCM 系(例:...AES_128_GCM_SHA256)がセキュリティ上の推奨度は高いですが、現場の要件は「業務で必要なクライアントが接続できること」です。本件では互換性確保のため CBC 系に寄せ、接続回復を優先しました。将来的にクライアントを更新できる段階になれば、より強度の高いスイートへ戻す判断が望ましいでしょう。
フロントエンド終端の意味:アプリ再起動は不要
App Service の TLS はアプリではなくフロントエンドで終端されます。したがって、環境変数の変更やアプリ再起動の可否は TLS 成否と無関係です。設定が正しければ、反映待ち(1〜2 分)の後に即座に効果が表れます。トラブル時にアプリ再起動ばかり繰り返すのは避け、フロントエンドの TLS ポリシーを優先的に確認してください。
よくある落とし穴
- 証明書アルゴリズム不一致:RSA 証明書しかないのに
_ECDSA_スイートを最小にすると、TLS 1.2 では交渉が失敗する可能性が高い。 - UI 表示順への依存:UI の並び順(「上から◯番目」)は変更になりうる。必ずスイート名の文字列で判断する。
- 開発と本番のポリシー差:価格プランや構成の流用時に、Cipher Suite の初期値が異なることがある。構成の差分比較を作業手順に組み込む。
- 「TLS 1.3 で動いているから大丈夫」問題:一部のシステム(例:レガシー SDK、組み込み端末、外部サービスの Webhook など)が TLS 1.3 に非対応のままの場合、本番でのみ障害として顕在化する。
運用ガイド:変更前・後での確認ポイント
| カテゴリ | 確認項目 | 目的 | 推奨タイミング |
|---|---|---|---|
| 設定 | 最小受信 TLS バージョン / Minimum TLS Cipher Suite | 交渉の下限を一致させる | 作業前後・リリース前 |
| 証明書 | RSA/ECDSA の種別、失効日、SAN | スイート選択との整合 | 四半期ごと・更新時 |
| 監視 | 失敗率(TLS 握手エラー) | 影響の早期検知 | 常時 |
| テスト | TLS 1.2 強制の合成監視 | 互換性の事前検出 | 毎日・デプロイ後 |
メリット・デメリット(運用面の補足)
| 項目 | TLS 1.2 を許可するメリット | TLS 1.2 を許可しないデメリット |
|---|---|---|
| 互換性 | Microsoft Graph のサブスクリプション通知等、TLS 1.3 非対応のクライアントでも接続可 | 古い IoT デバイスや一部ライブラリが通信不可 |
| 移行の容易さ | 段階的移行が可能(1.2 で一旦回復→1.3 へ計画的移行) | 一気に 1.3 限定にすると影響範囲が読みづらい |
| セキュリティ | 現行でも推奨レベルは満たす構成にできる | 1.3 のみ許可と比べ暗号強度がわずかに劣る可能性 |
将来の方針:TLS 1.3 へ戻す時の観点
- 対象クライアント(SDK、エージェント、Webhook 送信元)が TLS 1.3 と選定スイートに対応しているか。
- 中間装置(プロキシ、IDS/IPS、ロードバランサ)のパススルー方針が TLS 1.3 に適合しているか。
- 段階的移行:テスト用サブドメインで 1.3 限定を先行適用 → KPI(失敗率・遅延)を監視 → 本番へ展開。
実運用で役立つ「変更管理テンプレート」
【変更名】App Service TLS ポリシー調整(Minimum TLS Cipher Suite 見直し)
【目的】TLS 1.2 互換性確保による接続障害の解消
【対象】リソース名・サブスクリプション・リージョン
【現状】最小受信 TLS:1.2、Minimum TLS Cipher Suite:<旧値>
【変更】Minimum TLS Cipher Suite を TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 に変更
【影響】フロントエンドのみ(アプリ再起動不要)。反映に 1〜2 分。
【ロールバック】従前の値へ戻す。影響監視を継続。
【検証】curl/OpenSSL/Postman による TLS 1.2 強制テスト、外部診断での受け口確認
【責任者】(名前)
【承認】(関係者)
FAQ
Q. 環境変数の変更やアプリ再起動で直りますか?
A. いいえ。TLS は App Service のフロントエンドで終了するため、アプリ側の再起動や環境変数は接続可否に影響しません。Minimum TLS Cipher Suiteの調整が肝心です。
Q. カスタム ドメインや SNI バインドが原因では?
A. 本件では直接の原因ではありませんでした。SNI は提示証明書の選択であり、TLS 交渉ポリシーは別設定です。
Q. 何を選べば安全ですか?
A. 原則は「証明書アルゴリズムとクライアント能力に適合し、かつ可能な限り強度が高いスイート」。ただし業務継続上、まずは接続回復を優先し、その後計画的に GCM 系・TLS 1.3 へ段階移行するのが実践的です。
まとめ
- 「最小受信 TLS バージョン=1.2」だけでは不十分。Minimum TLS Cipher Suiteも併せて整合させる必要がある。
- 本件では
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256への変更で回復。反映は 1〜2 分程度。 - アプリ再起動は不要。TLS はフロントで終端される。
- 移行時はクライアント互換性・証明書種別・監視を三位一体で見る。
- 将来的にクライアントが TLS 1.3 に完全対応した段階で、暗号スイートを見直して 1.3 のみへ移行するとよい。
付録:TLS 1.2/1.3 と暗号スイートの基礎(要点)
- ECDHE:前方秘匿性を実現する鍵交換。現行実装の前提。
- RSA / ECDSA:サーバ証明書の署名アルゴリズム。暗号スイート名の
_RSA_/_ECDSA_と対応。 - CBC / GCM:TLS 1.2 では CBC(ブロック暗号)と GCM(AEAD)が併存。GCM が推奨だが、古いクライアントは GCM 非対応のことがある。
- TLS 1.3:スイートの定義が簡素化され、TLS 1.2 のスイートとは互換ではない。よって「1.3 で成功・1.2 で失敗」の組み合わせは起こりうる。
付録:作業前後のチェックシート(現場貼り出し用)
- [ ] 対象 Web App / スロット / リージョンを特定した
- [ ] 証明書(RSA/ECDSA)と SAN を確認した
- [ ] 最小受信 TLS バージョン(1.2 以上)を確認した
- [ ] Minimum TLS Cipher Suite の現在値を控えた
- [ ] 変更先スイートが証明書種別に一致している
- [ ] 変更を保存し、反映待ち 1〜2 分を取った
- [ ] Postman/curl で TLS 1.2 を強制して再テストした
- [ ] 外部診断ツールでバージョン/スイートを確認した
- [ ] 失敗率や遅延の監視を確認した
- [ ] 変更記録(誰が・いつ・何を・なぜ)を残した
最終結論:本事象は、「最小受信 TLS バージョン=1.2」だけでは交渉が通らず、Minimum TLS Cipher Suite の基準が厳しすぎた(あるいは証明書種別と不整合だった)ことが原因でした。TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 を選定して保存したところ復旧。今後はクライアント側の対応状況に合わせ、段階的に TLS 1.3 およびより強いスイート構成へ移行する運用が最も安全です。

コメント