Azure Container Apps上の MCP サーバーをセキュリティで保護する

この記事では、Azure Container Appsで実行されている MCP サーバーを認証してセキュリティで保護する方法について説明します。 この方法は、 スタンドアロン コンテナー アプリ をホストするか、動的セッションで プラットフォームで管理される MCP サーバー を使用するかによって異なります。

[前提条件]

認証モデルの概要

Azure Container Appsでは、MCP サーバー用の 2 つの認証モデルがサポートされています。 次の表は、主な相違点をまとめたものです。

アスペクト スタンドアロン コンテナー アプリ 動的セッション MCP
認証メカニズム Microsoft Entra IDを使用した Container Apps の組み込み認証 x-ms-apikey ヘッダー経由の API キー
トークンの種類 OAuth 2.0 ベアラー トークン 不透明な API キー文字列
ID プロバイダー Microsoft Entra ID Azure Resource Manager
キー/トークンのローテーション Microsoft Entra IDによって管理される Azure Resource Manager API を使用して再生成する
認可スコープ アプリケーションごとに構成可能 セッション プール レベル
転送の暗号化 TLS (コンテナアプリの入口) TLS (コンテナー アプリ セッション エンドポイント)

Microsoft Entra ID認証を使用したスタンドアロン コンテナー アプリ

独自の MCP サーバーをコンテナー アプリとしてデプロイする場合は、認証レイヤーを所有します。 container Apps Microsoft Entra IDによってサポートされる組み込み認証機能を使用します。

組み込み認証を構成する

次の手順では、Microsoft Entra ID アプリケーションを登録し、コンテナー アプリで組み込み認証を有効にします。

  1. Microsoft Entra IDにアプリケーションを登録します。

    APP_ID=$(az ad app create \
        --display-name "mcp-server-auth" \
        --sign-in-audience AzureADMyOrg \
        --query appId -o tsv)
    
  2. サービス プリンシパルを作成します。

    az ad sp create --id $APP_ID
    
  3. アプリケーション ID URI を設定し、API スコープを公開します。 これらの設定は、クライアントが MCP サーバーのアクセス トークンを要求できるようにするために必要です。

    az ad app update --id $APP_ID --identifier-uris "api://$APP_ID"
    
    OBJECT_ID=$(az ad app show --id $APP_ID --query id -o tsv)
    SCOPE_ID=$(uuidgen)
    
    az rest --method PATCH \
        --uri "https://graph.microsoft.com/v1.0/applications/$OBJECT_ID" \
        --headers "Content-Type=application/json" \
        --body "{
            \"api\": {
                \"oauth2PermissionScopes\": [{
                    \"id\": \"$SCOPE_ID\",
                    \"adminConsentDescription\": \"Access the MCP server\",
                    \"adminConsentDisplayName\": \"Access MCP Server\",
                    \"isEnabled\": true,
                    \"type\": \"User\",
                    \"userConsentDescription\": \"Access the MCP server\",
                    \"userConsentDisplayName\": \"Access MCP Server\",
                    \"value\": \"access_as_user\"
                }]
            }
        }"
    
  4. クライアント シークレットを追加します。

    CLIENT_SECRET=$(az ad app credential reset --id $APP_ID --query password -o tsv)
    TENANT_ID=$(az account show --query tenantId -o tsv)
    
  5. コンテナー アプリで組み込みの認証を有効にします。

    az containerapp auth microsoft update \
        --name <CONTAINER_APP_NAME> \
        --resource-group <RESOURCE_GROUP> \
        --client-id $APP_ID \
        --client-secret $CLIENT_SECRET \
        --tenant-id $TENANT_ID \
        --issuer "https://login.microsoftonline.com/$TENANT_ID/v2.0" \
        --yes
    
  6. 認証されていないアクションをログインを要求するように設定します。

    az containerapp auth update \
        --name <CONTAINER_APP_NAME> \
        --resource-group <RESOURCE_GROUP> \
        --unauthenticated-client-action Return401
    

ベアラー トークンを使用して MCP クライアントから接続する

MCP サーバーでベアラー トークンが必要な場合は、MCP クライアントでトークンの取得を構成します。 次の例は、GitHub Copilotの .vscode/mcp.json 構成を示しています。

{
    "servers": {
        "my-mcp-server": {
            "type": "http",
            "url": "https://<CONTAINER_APP_NAME>.<REGION>.azurecontainerapps.io/mcp",
            "headers": {
                "Authorization": "Bearer ${input:mcpBearerToken}"
            }
        }
    },
    "inputs": [
        {
            "id": "mcpBearerToken",
            "type": "promptString",
            "description": "Enter your bearer token for the MCP server",
            "password": true
        }
    ]
}

ヒント

開発の場合は、 az account get-access-token --resource api://$APP_ID --query accessToken -o tsv を使用してトークンを取得し、メッセージが表示されたら貼り付けます。 自動化されたワークフローの場合は、組織のトークン管理システムと統合します。

CORS の構成

Web ベースの環境から接続する MCP クライアントには CORS ヘッダーが必要です。 コンテナー アプリで CORS を構成するには、次のコマンドを使用します。

az containerapp ingress cors update \
    --name <CONTAINER_APP_NAME> \
    --resource-group <RESOURCE_GROUP> \
    --allowed-origins "https://vscode.dev" "https://github.dev" \
    --allowed-methods "GET" "POST" "OPTIONS" \
    --allowed-headers "Content-Type" "Authorization" "Mcp-Session-Id" \
    --max-age 3600

次のヘッダーは、許可するために重要です。

  • Content-Type: JSON-RPC 要求に必要です
  • Authorization: ベアラー トークン認証に必要
  • Mcp-Session-Id: ステートフル セッションに MCP クライアントによって使用されます

注

GitHub Copilotは、ブラウザーからではなく、VS Code デスクトップ アプリからリモート MCP サーバーに接続します。 CORS は、ブラウザー ベースの MCP クライアントまたは WEB 用の VS Code をサポートする場合にのみ必要です。 スタンドアロンのチュートリアルでは、わかりやすくするためにワイルドカード CORS のオリジンを使用します。運用環境の場合は、次に示すように、特定の信頼できる配信元に制限します。

スタンドアロン MCP サーバーのセキュリティに関する推奨事項

スタンドアロン MCP サーバーを強化するには、次のベスト プラクティスを適用します。

  • ネットワーク制限: IP 制限 または 仮想ネットワーク統合 を使用して、既知のクライアント IP へのアクセスを制限します。
  • Rate limiting: アプリケーション コードにレート制限を実装するか、Azure API Managementを使用してアプリを前面に表示します。
  • 入力検証: MCP サーバー コード内のすべてのツール引数を検証します。 MCP ツールの入力は任意の JSON です。 信頼されていないものとして扱います。
  • ステートレス設計: セッションハイジャックのリスクを回避するためにステートレス MCP サーバーを使用します。 ほとんどの MCP SDK では、これはサーバー側のセッション ID の生成を無効にすることを意味します (TypeScript では sessionIdGenerator: undefined、Python では stateless_http=True など)。
  • 正常性プローブ: MCP エンドポイントではなく、別のエンドポイント ( /healthz など) で正常性プローブを構成します。 MCP エンドポイントは、JSON-RPC POST 要求を想定し、プレーンな GET プローブのエラーを返します。

API キー認証を使用した動的セッション

Important

動的セッション用のプラットフォームで管理される MCP サーバーは プレビュー段階です。 API バージョンの 2025-02-02-preview プロパティと mcpServerSettings プロパティは変更される可能性があります。

動的セッションのプラットフォームで管理される MCP サーバーでは、API キー認証が使用されます。 キーのスコープはセッション プールであり、プール内のすべてのツールとセッションへのアクセスを許可します。

API キー認証フロー

次の手順では、動的セッションに対する API キー認証のしくみについて説明します。

  1. クライアントは、 x-ms-apikey ヘッダーを使用して JSON-RPC 要求を送信します。
  2. セッション プール プロキシは、Azure コントロール プレーンに対してキーを検証します。
  3. キーが有効な場合、要求はセッションに転送されます。 そうでない場合は、認証エラーが返されます。

API キーを取得する

次のコマンドを使用して、セッション プールの API キーをフェッチします。

API_KEY=$(az rest --method POST \
    --uri "https://management.azure.com/subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP>/providers/Microsoft.App/sessionPools/<SESSION_POOL_NAME>/fetchMCPServerCredentials" \
    --uri-parameters api-version=2025-02-02-preview \
    --query "apiKey" -o tsv)

API キーをローテーションしてキャッシュする

API キーはいつでも再生成できます。 プラットフォームは検証結果を最大 5 分間キャッシュするため、キャッシュの有効期限が切れるまで、以前の有効なキーは再生成後も引き続き機能する可能性があります。

API キーをローテーションするには、セッション プールで regenerateCredentials アクションを呼び出します。

az rest --method POST \
    --uri "https://management.azure.com/subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP>/providers/Microsoft.App/sessionPools/<SESSION_POOL_NAME>/regenerateCredentials" \
    --uri-parameters api-version=2025-02-02-preview

再生成後、前に示したように、 fetchMCPServerCredentials を使用して新しいキーを取得します。

動的セッションのセキュリティに関する推奨事項

動的セッションの MCP デプロイをセキュリティで保護するには、次のベスト プラクティスを適用します。

  • API キー スコープ: API キーは、セッション プール全体へのアクセスを許可します。 キーを持つ任意のクライアントは、環境を作成し、コードを実行できます。 信頼されていないパーティとキーを共有しないでください。
  • Environment isolation: 各セッションは、Hyper-V分離されたコンテナーで実行されます。 あるセッションでのコード実行は、別のセッションのデータにアクセスできません。
  • ネットワーク エグレス: セッションが sessionNetworkConfiguration.statusを使用してインターネットにアクセスできるかどうかを制御します。 セッションに外部ネットワーク アクセスが必要ない場合は、 EgressDisabled に設定します。
  • セッションの有効期間: アイドル状態のセッションを自動的に破棄するように coolDownPeriodInSeconds を構成します。 この設定により、セッションが侵害された場合の公開期間が制限されます。
  • Secret storage: コードまたは構成ファイルではなく、Azure Key Vault または Container Apps シークレットに API キーを格納します。

一般的な認証の不一致

一般的な間違いは、スタンドアロン コンテナー アプリで API キー ヘッダー (x-ms-apikey) を使用するか、セッション MCP エンドポイントでベアラー トークンを使用することです。 次の表は、それらを混在させるとどうなるかを示しています。

ミスマッチ 結果
x-ms-apikey ヘッダーがスタンドアロンアプリに送信される ヘッダーは無視されます。要求が組み込みの認証にヒットし、認証が有効になっている場合は 401 が返されます
Authorization: Bearer がセッション MCP に送信される キーの検証が失敗し、返される 401
公開された API スコープなしで要求されたベアラー トークン トークンの取得が失敗するか、トークンに有効な対象ユーザーが存在しないため、 401

MCP クライアント構成が、デプロイしたホスティング モデルと一致していることを確認します。