Azure MCP托管服务

一个基于Terraform、Azure DevOps和工作负载身份联合的Microsoft Azure上的生产级MCP服务器托管基础设施解决方案。

  • by okaneconnor
  • HCL
  • 本地部署
  • 4 星标
  • 更新于
在 GitHub 查看 okaneconnor/Remote-MCP-Pattern-Azure

使用说明

Azure上的远程MCP托管模式

一种生产就绪的基础架构模式,用于使用Terraform、Azure DevOps和工作负载身份联合在Microsoft Azure上托管模型上下文协议(MCP)服务器。

先决条件

  • 具有所有者/贡献者访问权限的Azure订阅
  • Azure CLI已安装并通过身份验证
  • 地形>=1.5
  • Azure DevOps组织(或GitHub Actions/Jenkins)

入门指南

步骤1:创建资源组和托管身份

首先,我们创建将在Terraform之外管理的基础资源。我们使用工作负载身份联合进行身份验证,它提供:

  • 无需管理或轮换客户端机密
  • 无泄密风险
  • 零信任安全原则
  • 微软推荐的CI/CD方法

设置环境变量

SUBSCRIPTION_ID="<your-subscription-id>"
RESOURCE_GROUP="<your-resource-group>"          # e.g., rg-mcp-pipeline
LOCATION="<your-location>"                       # e.g., uksouth, eastus
IDENTITY_NAME="<your-identity-name>"             # e.g., id-mcp-pipeline

创建资源

az account set --subscription $SUBSCRIPTION_ID

az group create \
  --name $RESOURCE_GROUP \
  --location $LOCATION

az identity create \
  --name $IDENTITY_NAME \
  --resource-group $RESOURCE_GROUP \
  --location $LOCATION

获取身份详细信息

IDENTITY_CLIENT_ID=$(az identity show --name $IDENTITY_NAME --resource-group $RESOURCE_GROUP --query clientId -o tsv)
IDENTITY_PRINCIPAL_ID=$(az identity show --name $IDENTITY_NAME --resource-group $RESOURCE_GROUP --query principalId -o tsv)

echo "Client ID: $IDENTITY_CLIENT_ID"
echo "Principal ID: $IDENTITY_PRINCIPAL_ID"

保存这些值-在接下来的步骤中您将需要它们。


步骤2:配置Azure DevOps

创建ADO组织和项目

  1. 引导到 Azure DevOps 并创建您的组织
  2. 为您的MCP基础设施创建新项目

创建服务连接

首选 项目设置 > 服务连接 > 新建服务连接:

设置 值
类型 Azure资源管理器
身份类型 管理身份
订阅 <your-subscription-id>
资源组 <your-resource-group>
管理身份 <your-identity-name>
服务连接名称 <your-service-connection-name>

创建联合凭据并分配权限

# Set variables (use values from Step 1)
ADO_ORG="<your-ado-org>"
ADO_PROJECT="<your-ado-project>"
SERVICE_CONNECTION_NAME="<your-service-connection-name>"

# Create Federated Credential
az identity federated-credential create \
  --name "ado-federation" \
  --identity-name $IDENTITY_NAME \
  --resource-group $RESOURCE_GROUP \
  --issuer "https://vstoken.dev.azure.com/${ADO_ORG}" \
  --subject "sc://${ADO_ORG}/${ADO_PROJECT}/${SERVICE_CONNECTION_NAME}" \
  --audiences "api://AzureADTokenExchange"

# Assign Contributor role
az role assignment create \
  --assignee-object-id $IDENTITY_PRINCIPAL_ID \
  --assignee-principal-type ServicePrincipal \
  --role "Contributor" \
  --scope "/subscriptions/$SUBSCRIPTION_ID"

# Assign User Access Administrator (required for Terraform RBAC)
az role assignment create \
  --assignee-object-id $IDENTITY_PRINCIPAL_ID \
  --assignee-principal-type ServicePrincipal \
  --role "User Access Administrator" \
  --scope "/subscriptions/$SUBSCRIPTION_ID"

分配参赛者ID权限

管道需要应用程序管理员角色和Microsoft Graph权限:

MI_OBJECT_ID=$(az identity show \
  --name $IDENTITY_NAME \
  --resource-group $RESOURCE_GROUP \
  --query principalId -o tsv)

# Assign Application Administrator role
az rest --method POST \
  --uri "https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignments" \
  --headers "Content-Type=application/json" \
  --body "{
    \"@odata.type\": \"#microsoft.graph.unifiedRoleAssignment\",
    \"principalId\": \"$MI_OBJECT_ID\",
    \"roleDefinitionId\": \"9b895d92-2cd3-44c7-9d02-a6ac2d5ea5c3\",
    \"directoryScopeId\": \"/\"
  }"

# Get Microsoft Graph Service Principal
MSGRAPH_SP_ID=$(az ad sp list --filter "appId eq '00000003-0000-0000-c000-000000000000'" --query "[0].id" -o tsv)

# Grant AppRoleAssignment.ReadWrite.All (for admin consent)
az rest --method POST \
  --uri "https://graph.microsoft.com/v1.0/servicePrincipals/${MI_OBJECT_ID}/appRoleAssignments" \
  --headers "Content-Type=application/json" \
  --body "{
    \"principalId\": \"${MI_OBJECT_ID}\",
    \"resourceId\": \"${MSGRAPH_SP_ID}\",
    \"appRoleId\": \"06b708a9-e830-4db3-a914-8e69da51d44f\"
  }"

# Grant Group.ReadWrite.All (for Entra ID groups)
az rest --method POST \
  --uri "https://graph.microsoft.com/v1.0/servicePrincipals/${MI_OBJECT_ID}/appRoleAssignments" \
  --headers "Content-Type=application/json" \
  --body "{
    \"principalId\": \"${MI_OBJECT_ID}\",
    \"resourceId\": \"${MSGRAPH_SP_ID}\",
    \"appRoleId\": \"62a82d76-70ea-41e2-9197-370581804d09\"
  }"

步骤3:创建远程状态存储

地形状态存储在Azure Blob存储中。出于引导目的,这在Terraform之外进行管理。

创建存储帐户

STORAGE_ACCOUNT="<your-storage-account>"         # e.g., stmcptfstate (must be globally unique)
CONTAINER_NAME="<your-container-name>"           # e.g., tfstate

az storage account create \
  --name $STORAGE_ACCOUNT \
  --resource-group $RESOURCE_GROUP \
  --location $LOCATION \
  --sku Standard_LRS \
  --kind StorageV2 \
  --min-tls-version TLS1_2 \
  --allow-blob-public-access false

# Assign yourself Storage Blob Data Contributor
az ad signed-in-user show --query id -o tsv | az role assignment create \
  --role "Storage Blob Data Contributor" \
  --assignee @- \
  --scope "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.Storage/storageAccounts/$STORAGE_ACCOUNT"

# Create container
az storage container create \
  --account-name $STORAGE_ACCOUNT \
  --name $CONTAINER_NAME \
  --auth-mode login

# Grant Pipeline identity access
az role assignment create \
  --assignee-object-id $IDENTITY_PRINCIPAL_ID \
  --assignee-principal-type ServicePrincipal \
  --role "Storage Blob Data Contributor" \
  --scope "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.Storage/storageAccounts/$STORAGE_ACCOUNT"

初始化地形状态

为了高效部署,基础设施分为两个阶段:

# Stage 1 - ACR and Managed Identity
cd terraform/stage1
terraform init \
  -reconfigure \
  -backend-config="storage_account_name=$STORAGE_ACCOUNT" \
  -backend-config="resource_group_name=$RESOURCE_GROUP" \
  -backend-config="key=stage1.tfstate"

# Stage 2 - Main Infrastructure
cd ../stage2
terraform init \
  -reconfigure \
  -backend-config="storage_account_name=$STORAGE_ACCOUNT" \
  -backend-config="resource_group_name=$RESOURCE_GROUP" \
  -backend-config="key=stage2.tfstate"

步骤4:部署基础设施

配置变量

更新 terraform/environments/dev/terraform.tfvars 与你的价值观。

通过Pipeline部署

触发Azure DevOps管道以部署所有基础设施。

本地部署

如果在本地部署,请执行以下步骤:

第一阶段-部署ACR和托管身份
cd terraform/stage1
terraform plan -var-file="../environments/dev/terraform.tfvars"
terraform apply -var-file="../environments/dev/terraform.tfvars"
构建和推送MCP服务器映像

确保你已经安装并运行了Docker Desktop。

# Set ACR name (from Stage 1 output or terraform.tfvars)
ACR_NAME="<your-acr-name>"  # e.g., acrmcppoddev

# Login to ACR
az acr login --name $ACR_NAME

# Navigate to the mongo-db-server directory
cd mongo-db-server

# Build for Linux AMD64 (required for Azure Container Instances)
docker build --platform linux/amd64 -t ${ACR_NAME}.azurecr.io/mongodb-mcp:latest .

# Push to ACR
docker push ${ACR_NAME}.azurecr.io/mongodb-mcp:latest

# Return to terraform directory
cd ../terraform/stage2
指定密钥保管库权限

在部署阶段2之前,为自己分配密钥保管库管理员角色:

USER_OBJECT_ID=$(az ad signed-in-user show --query id -o tsv)
KEY_VAULT_NAME="<your-keyvault-name>"  # e.g., keyvault-mcp-pod-dev
SUBSCRIPTION_ID="<your-subscription-id>"
RESOURCE_GROUP="<your-resource-group>"

az role assignment create \
  --role "Key Vault Administrator" \
  --assignee $USER_OBJECT_ID \
  --scope "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.KeyVault/vaults/$KEY_VAULT_NAME"
第2阶段-部署主要基础设施
# Initialize terraform (if not already done)
terraform init \
  -backend-config="storage_account_name=$STORAGE_ACCOUNT" \
  -backend-config="resource_group_name=$RESOURCE_GROUP" \
  -backend-config="key=stage2.tfstate"

# Plan and apply
terraform plan -var-file="../environments/dev/terraform.tfvars"
terraform apply -var-file="../environments/dev/terraform.tfvars"

项目结构

.
├── terraform/
│   ├── stage1/                 # ACR & Managed Identity
│   ├── stage2/                 # Main infrastructure
│   ├── environments/
│   │   └── dev/
│   │       └── terraform.tfvars
│   └── modules/
│       ├── acr/                # Azure Container Registry
│       ├── apim/               # API Management
│       ├── app-registration/   # OAuth 2.0
│       ├── container-instance/ # MCP Containers
│       ├── cosmosdb-mongodb/   # Database
│       ├── entra-groups/       # Access Control Groups
│       ├── key-vault/          # Secrets
│       ├── managed-identity/   # Identity
│       ├── monitoring/         # Observability
│       ├── private-endpoint/   # Private Connectivity
│       ├── rbac/               # Role Assignments
│       └── vnet/               # Networking
├── pipelines/                  # Azure DevOps pipelines
└── docs/
    └── diagrams/

证券收益

特点 优点
工作负载身份联合 没有要管理或轮换的秘密
专用端点 数据库仅可在ExpressRoute内访问
OAuth 2.0+Entra ID 企业身份验证
基于组的路由 管理员与只读访问控制
RBAC Everywhere 最低权限访问

支持

对于问题或疑问,请在此存储库中提出问题。