Azure API Management(APIM)経由で Azure Functions を呼ぶと「SSL/TLS のセキュア チャネルを作成できません」とだけ表示され、内部モード+VNet 接続+プライベート エンドポイントなど要素が多いと、原因がどこにあるのか分かりにくくなります。本記事では、実際に発生しやすい構成を例に、TLS バージョン不一致を中心とした原因と、切り分け・解決の具体的な手順を整理します。
事象の概要:APIM(内部モード)から Functions を呼ぶと TLS エラー
今回の想定シナリオは次のような構成です。
- Azure API Management:Internal モード(VNet 内部)
- バックエンド:Azure Functions(関数アプリ / App Service)
- APIM の「テスト(Test)」画面からバックエンドを呼び出すと失敗
APIM のトレースログでは、次のようなエラーが記録されます。
forward-request ... "The request was aborted: Could not create SSL/TLS secure channel."
日本語のポータル画面では「SSL/TLS のセキュア チャネルを作成できませんでした」と表示されることもあります。
このメッセージはあくまで「TLS のハンドシェイクが確立できなかった」という意味であり、HTTP レベル(ステータスコード 4xx/5xx)まで到達していません。ネットワーク(VNet / NSG / プライベート エンドポイント)ではなく、TLS レイヤでこけていることがポイントです。
構成の整理:どこで TLS が張られているのか
今回のような構成では、主に下図の TLS 経路を意識する必要があります。
| 経路 | 送信元 | 宛先 | TLS の役割 |
|---|---|---|---|
| ① クライアント → APIM | ブラウザ / アプリ | API Management の公開 FQDN | インターネット経由の TLS。公開証明書。 |
| ② APIM → Functions | APIM(Internal モード) | 関数アプリ(appname.azurewebsites.net など) | 今回ここで失敗。APIM がバックエンドへ HTTPS で接続。 |
テスト画面で実行したリクエストは、最終的に ② の経路で Functions に送られます。したがって、今回のエラーはほぼ確実に 「APIM → Functions 間の TLS」 に起因します。
よくある勘違い:「プライベート エンドポイントがないと TLS に失敗する?」
Internal/VNet 構成だと、どうしても「プライベート エンドポイント周り」を疑いがちです。しかし、今回のような 『SSL/TLS のセキュア チャネルを作成できません』 エラーは、プライベート エンドポイントの有無とは直接関係ありません。
| 観点 | プライベート エンドポイントの役割 | 今回のエラーとの関係 |
|---|---|---|
| 主目的 | トラフィックを VNet 内に閉じる(閉域化・ゼロトラスト強化) | なし(TLS が通る / 通らないは別問題) |
| 通信の可否 | DNS 解決結果とルーティングを変える | 到達不可ならタイムアウト等。TLS エラーとは別タイプ。 |
| TLS ハンドシェイク | 関与しない(暗号処理はサーバ/クライアントの設定次第) | TLS バージョンや証明書設定の方が支配的 |
プライベート エンドポイントは「セキュリティ/到達性」の話であり、今回の TLS エラーの一次原因ではないと考えるのが合理的です。
今回の主因:関数アプリの「最小 TLS バージョン」不一致
もっとも多いパターンが、関数アプリ側で設定している 最小 TLS バージョン と、APIM 側が利用する TLS バージョンが噛み合っていないケースです。
典型的な例:
- 関数アプリの「最小 TLS バージョン」が 1.3 に固定されている
- APIM のアウトバウンド通信が TLS 1.2 までしか話せないリージョン/SKU/内部実装で動いている
- 結果として、APIM → Functions のハンドシェイクが成立せず、
「Could not create SSL/TLS secure channel」が返る
実際の現場では、関数アプリ側の「最小受信 TLS バージョン」を 1.2 に戻した瞬間に問題が解消するケースが非常に多いです。
関数アプリの TLS 設定を確認する手順(ポータル)
Azure ポータルからの確認手順は次の通りです。
- 対象の 関数アプリ を開く
- 左メニューの「設定」→「構成」を選択
- 「全般設定」タブを開く
- 「最小受信 TLS バージョン」 の項目を確認
- 推奨値は TLS 1.2
(APIM と Functions の両方がサポートするバージョンに揃える) - 値を変更したら「保存」→「再起動」が必要な場合は再起動
| 項目 | 変更前(例) | 変更後(例) | 備考 |
|---|---|---|---|
| 最小受信 TLS バージョン | TLS 1.3 | TLS 1.2 | APIM が 1.3 を話せない場合にエラーとなる |
ポータルから変更して反映を待ち、再度 APIM のテスト画面から呼び出して成功するか確認します。
スクリプトから TLS 設定を変更する(補足)
Infrastructure as Code(IaC)運用をしている場合は、CLI で最小 TLS を揃えると管理しやすくなります。例えば Azure CLI の場合:
az functionapp config set \
--resource-group <リソースグループ名> \
--name <関数アプリ名> \
--min-tls-version 1.2
ARM/Bicep/terraform などでも同等のプロパティがあるため、APIM と Functions の両方について「最小 TLS 1.2」に揃えておく設計が安全です。
原因候補その2:相互 TLS(mTLS/クライアント証明書)の要求
Azure Functions 側で クライアント証明書必須(mTLS) にしている場合、APIM がクライアント証明書を提示しなければ TLS ハンドシェイクで失敗します。この場合も「SSL/TLS のセキュア チャネルを作成できません」といったメッセージで見分けがつきにくくなります。
| 設定パターン | APIM | Functions | 結果 |
|---|---|---|---|
| 通常の TLS のみ | 証明書提示なし | クライアント証明書:無視 | 成功(サーバ証明書のみで確立) |
| mTLS だが APIM 側未設定 | 証明書提示なし | クライアント証明書:必須 | ハンドシェイク失敗(今回のようなエラー) |
| mTLS 完全構成 | クライアント証明書提示 | クライアント証明書:必須 | 成功(クライアント証明書で認証) |
Functions 側の mTLS 設定を確認する
関数アプリの mTLS 設定は、ポータルでは次の場所で確認できます。
- 対象の関数アプリを開く
- 「設定」→「構成」→「全般設定」
- 「クライアント証明書モード」 の値を確認
| クライアント証明書モード | 意味 | APIM からのアクセスへの影響 |
|---|---|---|
| 無視 | クライアント証明書を送っても見ない | APIM 側で証明書設定がなくても OK |
| 任意 | 送られてくれば参照するが必須ではない | APIM 側で証明書がなくても TLS 自体は成立 |
| 必須 | クライアント証明書がないと拒否 | APIM から証明書を提示しないと TLS 失敗 |
mTLS が要件として不要であれば、まずは 「無視」 に変更して状況が改善するかを確認するのが手っ取り早いです。
APIM からクライアント証明書を提示する設定例
要件上、Functions 側で mTLS を必須にしたい場合には、APIM にクライアント証明書を登録し、特定のバックエンド呼び出しで提示させる必要があります。
- APIM の「証明書」ブレードでクライアント証明書(.pfx)をアップロード
- 証明書のサムプリント(thumbprint)を控える
- 該当 API のポリシーを編集し、
authentication-certificateを追加
<policies>
<inbound>
<base />
<authentication-certificate thumbprint="<証明書のサムプリント>" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
証明書の CN/SAN と Functions 側で検証するホスト名が一致しているか、ルート CA が信頼されているかも忘れずに確認してください。
原因候補その3:証明書チェーンやホスト名の問題
TLS バージョンや mTLS 設定が正しい場合でも、サーバ証明書側の問題でハンドシェイクが失敗することがあります。
- 独自ドメイン(カスタムドメイン)+独自証明書を利用している
- 中間 CA 証明書が正しく連結されていない
- 証明書の有効期限が切れている
- APIM から見たときのホスト名と証明書の CN/SAN が一致していない
特に多いのが、中間証明書を含まないチェーン不備の証明書です。ブラウザから直接 Functions にアクセスしたときは OS が補完してくれて気づきにくいのに、APIM からの接続では素直に失敗する、というパターンがあります。
| チェック項目 | 確認方法の一例 |
|---|---|
| 証明書の有効期限 | ブラウザ、OpenSSL、証明書ビューアなどで確認 |
| 証明書チェーンの正当性 | OpenSSL の s_client -showcerts などで検証 |
| ホスト名と CN/SAN の一致 | APIM が接続している FQDN と証明書の SAN を突き合わせ |
Azure Functions / App Service の既定ドメイン(.azurewebsites.net)をそのまま使っている場合は、Microsoft 管理の証明書が使われるため、この種の問題は起きにくいですが、カスタムドメイン利用時には必ず確認しておきたいポイントです。
プライベート エンドポイントは「必須」ではないが推奨
繰り返しになりますが、プライベート エンドポイント(PE)がないことが今回の TLS エラーの原因ではありません。しかし、社内システムとして閉域に閉じたいケースでは、関数アプリにも PE を張るのが実運用としてはベストプラクティスです。
プライベート エンドポイントを使う場合のチェックポイント
- Functions 用のプライベート エンドポイントを作成
- ターゲットタイプ:Web サイト(azurewebsites.net)
- 接続先 VNet / サブネットは APIM と同じ、またはルーティングで到達可能なもの
- プライベート DNS ゾーン:
privatelink.azurewebsites.netを作成 - プライベート DNS ゾーンを VNet にリンク(APIM が属する VNet)
- NSG / UDR で 443/TCP がブロックされていないことを確認
| 目的 | 設定 | TLS エラーへの影響 |
|---|---|---|
| 閉域化 | PE + プライベート DNS | 直接の原因にはならないが、到達不能だと別種のエラーになる |
| TLS ハンドシェイク | 証明書、TLS バージョン、mTLS | 今回のエラーの主因はこちら側 |
まとめると、「TLS の合意(バージョン・証明書)」と「ネットワークの到達性(PE / DNS)」は別レイヤの話であり、それぞれを独立して切り分けることが重要です。
切り分けに使えるチェックリスト
実際に調査する際は、次の順番で確認していくと原因に辿り着きやすくなります。
1. 関数アプリの最小 TLS バージョン
- ポータルまたは IaC 定義で 「最小受信 TLS バージョン」= TLS 1.2 になっているか
- 変更した場合は「保存」後に再試行する
- App Service プランを共有する他のアプリにも影響がないか確認
2. mTLS(クライアント証明書)の有無
- クライアント証明書モードが「必須」になっていないか
- mTLS が必要な場合:
- APIM にクライアント証明書を登録済みか
- 該当 API のポリシーで
<authentication-certificate>を設定しているか
- mTLS が不要な場合:
- まずは Functions 側のモードを「無視」にして挙動を確認
3. サーバ証明書/カスタムドメイン設定
- カスタムドメインを使っている場合は、証明書の有効期限・チェーンを確認
- APIM からアクセスしている FQDN と証明書の CN / SAN が一致しているか
- 中間 CA 証明書が欠落していないか(特に手動アップロード時)
4. ネットワーク(プライベート エンドポイント / DNS / NSG)
- APIM と Functions(またはそのプライベートエンドポイント)が同じ VNet、もしくはピアリングされた VNet 内か
- プライベート DNS ゾーン
privatelink.azurewebsites.netが正しく構成・リンクされているか - サブネットの NSG / UDR で 443/TCP がブロックされていないか
APIM のテスト画面以外からの確認も有効
APIM のテスト画面だけを見ていると、「APIM なのか Functions なのか」「TLS なのかネットワークなのか」が切り分けづらいことがあります。VNet 内の別 VM から直接 Functions に対して curl したり、Invoke-WebRequest を投げたりしてみると、問題のレイヤが見えやすくなります。
# 例:VNet 内のテスト VM から
curl -v https://<your-function-app-name>.azurewebsites.net/api/health
ここで同様に TLS エラーが発生する場合は、APIM ではなく Functions 側の証明書/TLS 設定に問題がある可能性が高くなります。一方で、テスト VM からは成功するのに APIM だけ失敗する場合は、APIM の SKU / リージョン特性(サポートする TLS バージョンや暗号スイート)や、APIM 側のネットワークルールを疑うべき状況です。
実運用でのベストプラクティス
今回のようなトラブルを避けるために、設計段階で次のような方針を決めておくと運用が楽になります。
1. 「TLS 1.2 を共通の最低ライン」にする
- APIM、Functions、App Service、他のバックエンドすべてで、最小 TLS 1.2 を前提に設計する
- TLS 1.0 / 1.1 はセキュリティ観点から廃止する方向で統一する
- TLS 1.3 を有効にする場合は、1.2 と併用し「1.3 のみ」にしない
2. mTLS を使う場合は「証明書ライフサイクル」を仕組み化
- クライアント証明書の有効期限をカレンダー/監視に登録
- 更新手順(APIM 側の入れ替え、Functions 側の検証方法など)をドキュメント化
- ステージング環境での疎通確認を自動化(例:APIM から Functions へのヘルスチェック API)
3. プライベート エンドポイントと DNS をテンプレート化
- Functions / Web Apps / Storage など、PE を張るリソースごとに標準テンプレートを用意
- プライベート DNS ゾーンの作成&リンクも IaC 化し、手作業による設定漏れを防ぐ
- APIM の VNet にすべての必要なプライベート DNS ゾーンをリンクしておく
まとめ:調査の優先度とおすすめの進め方
最後に、今回の「Azure APIM 経由で Azure Functions をテストすると『SSL/TLS のセキュア チャネルを作成できません』になる」問題を解決するうえでの、おすすめの調査・対応順を整理します。
- 最小 TLS バージョンを揃える
- まずは関数アプリの「最小受信 TLS バージョン」を TLS 1.2 に設定
- APIM 側も TLS 1.2 を話せる前提で設計
- mTLS(クライアント証明書)の設定を確認
- mTLS が不要なら Functions 側のクライアント証明書モードを「無視」に
- mTLS が必要なら、APIM にクライアント証明書を登録し、ポリシーで
authentication-certificateを設定
- サーバ証明書(特にカスタムドメイン)を再確認
- 有効期限、チェーン、中間証明書、CN/SAN とホスト名の一致をチェック
- ネットワーク(PE / DNS / NSG)の整合性を確認
- プライベート エンドポイントと
privatelink.azurewebsites.netの DNS 設定 - 443/TCP をブロックする NSG / UDR がないか
- プライベート エンドポイントと
重要なのは、「TLS の合意(バージョン・証明書)」を最優先で確認し、そのうえでネットワーク構成(プライベート エンドポイントや DNS)を整理するという順番です。プライベート エンドポイントはセキュリティ強化・閉域化のためには非常に有用ですが、今回のような「SSL/TLS のセキュア チャネルを作成できません」エラーそのものの根本原因ではないことを押さえておきましょう。
この記事が、Azure API Management と Azure Functions を組み合わせた構成で TLS 周りのトラブルに遭遇した際の、原因切り分けと再発防止の一助になれば幸いです。

コメント