为什么 Azure 托管身份取代了存储的凭据:以及 2026 年如何使用它
一位开发者在 Dev.to 上发表文章,详细介绍了 Azure 托管身份(Managed Identity)如何取代传统的存储凭据方式,以及在 2026 年如何正确使用它。文章指出,每个 Azure 项目最终都会面临同一个问题:连接字符串存在哪里?而托管身份提供了一个更安全、更易维护的解决方案。
背景:存储凭据的问题
在 Azure 项目中,几乎每个开发者都会遇到这样的对话:
"连接字符串存在哪里?"
"存在配置文件里。"
"那配置文件会提交到 Git 吗?"
"不会,我们用环境变量。"
"那环境变量在 CI/CD 里怎么设置?"
"存在密钥管理服务里。"
"那密钥管理服务的访问密钥存在哪里?"
这个无限循环的问题,本质上是凭据管理的困境:无论你把凭据存在哪里,都需要另一个凭据来访问它,形成"鸡生蛋"的问题。
传统存储凭据的问题
安全风险:
- 凭据可能被意外提交到代码仓库
- 配置文件可能被未授权访问
- 日志和错误信息可能泄露凭据
- 人员离职后凭据可能未及时轮换
管理复杂性:
- 需要管理多个环境的凭据(开发、测试、生产)
- 凭据轮换需要更新多个地方
- 缺乏统一的凭据生命周期管理
- 审计和合规困难
运维负担:
- 凭据过期导致服务中断
- 紧急轮换凭据需要修改配置和重启服务
- 不同服务的凭据管理方式不一致
- 缺乏自动化的凭据轮换机制
什么是 Azure 托管身份
Azure 托管身份(Managed Identity)是 Azure Active Directory(Azure AD)提供的一项功能,它为 Azure 资源自动管理身份凭据,开发者不需要存储或管理任何密钥。
核心原理
托管身份的核心原理是:
- Azure 为资源(如虚拟机、App Service、函数应用等)自动创建一个 Azure AD 身份
- 这个身份的凭据由 Azure 自动管理和轮换
- 应用程序可以通过 Azure Instance Metadata Service(IMDS)获取访问令牌
- 使用访问令牌向支持 Azure AD 认证的服务(如 Key Vault、Storage、SQL Database 等)进行认证
关键优势
- 无需存储凭据:应用程序中没有任何密钥或连接字符串
- 自动轮换:Azure 自动轮换凭据,无需人工干预
- 细粒度访问控制:通过 Azure RBAC 精确控制身份的权限
- 统一管理:所有资源的身份管理方式一致
- 审计日志:所有身份的操作都有审计记录
- 零信任架构:符合零信任安全模型的要求
托管身份的类型
Azure 提供两种类型的托管身份:
| 类型 | 特点 | 适用场景 |
|---|---|---|
| 系统分配的托管身份 | 与资源生命周期绑定,资源删除时身份也删除 | 单个资源需要独立身份 |
| 用户分配的托管身份 | 独立的 Azure 资源,可以分配给多个资源 | 多个资源共享同一身份,或需要预创建身份 |
托管身份如何取代存储凭据
传统方式 vs 托管身份方式
传统方式:
应用程序 → 读取配置文件中的连接字符串 → 使用连接字符串访问数据库
问题:连接字符串需要存储在某个地方,存在泄露风险。
托管身份方式:
应用程序 → 通过 IMDS 获取 Azure AD 访问令牌 → 使用令牌访问数据库
优势:不需要存储任何凭据,令牌由 Azure 自动管理。
具体场景对比
场景一:访问 Azure Key Vault
传统方式:
# 需要存储访问 Key Vault 的凭据
from azure.keyvault.secrets import SecretClient
from azure.identity import ClientSecretCredential
credential = ClientSecretCredential(
tenant_id=os.environ["AZURE_TENANT_ID"],
client_id=os.environ["AZURE_CLIENT_ID"],
client_secret=os.environ["AZURE_CLIENT_SECRET"] # 这个密钥存在哪里?
)
client = SecretClient(vault_url="https://myvault.vault.azure.net", credential=credential)
secret = client.get_secret("my-secret")
托管身份方式:
# 不需要任何凭据
from azure.keyvault.secrets import SecretClient
from azure.identity import DefaultAzureCredential
credential = DefaultAzureCredential() # 自动使用托管身份
client = SecretClient(vault_url="https://myvault.vault.azure.net", credential=credential)
secret = client.get_secret("my-secret")
场景二:访问 Azure Storage
传统方式:
# 使用连接字符串
from azure.storage.blob import BlobServiceClient
connect_str = os.environ["AZURE_STORAGE_CONNECTION_STRING"] # 包含账户密钥
blob_service_client = BlobServiceClient.from_connection_string(connect_str)
托管身份方式:
# 使用托管身份
from azure.storage.blob import BlobServiceClient
from azure.identity import DefaultAzureCredential
credential = DefaultAzureCredential()
blob_service_client = BlobServiceClient(
account_url="https://myaccount.blob.core.windows.net",
credential=credential
)
场景三:访问 Azure SQL Database
传统方式:
# 使用 SQL 身份验证(用户名密码)
import pyodbc
server = "myserver.database.windows.net"
database = "mydb"
username = os.environ["DB_USERNAME"]
password = os.environ["DB_PASSWORD"] # 密码存在哪里?
conn_str = f"DRIVER={{ODBC Driver 18 for SQL Server}};SERVER={server};DATABASE={database};UID={username};PWD={password}"
conn = pyodbc.connect(conn_str)
托管身份方式:
# 使用 Azure AD 身份验证(托管身份)
import pyodbc
from azure.identity import DefaultAzureCredential
credential = DefaultAzureCredential()
token = credential.get_token("https://database.windows.net/.default")
server = "myserver.database.windows.net"
database = "mydb"
conn_str = f"DRIVER={{ODBC Driver 18 for SQL Server}};SERVER={server};DATABASE={database};Authentication=ActiveDirectoryMsi;Encrypt=yes"
conn = pyodbc.connect(conn_str, attrs_before={1256: bytearray(token.token, "UTF-8")})
2026 年如何使用托管身份
步骤一:启用托管身份
系统分配的托管身份
Azure Portal:
- 进入资源(如 App Service)的页面
- 选择"身份"菜单
- 在"系统分配"标签下,将"状态"设置为"开"
- 点击"保存"
Azure CLI:
# 为 App Service 启用系统分配的托管身份
az webapp identity assign --name myapp --resource-group myrg
# 为虚拟机启用系统分配的托管身份
az vm identity assign --name myvm --resource-group myrg
Azure PowerShell:
# 为 App Service 启用系统分配的托管身份
Set-AzWebApp -Name myapp -ResourceGroupName myrg -AssignIdentity $true
用户分配的托管身份
Azure CLI:
# 创建用户分配的托管身份
az identity create --name myidentity --resource-group myrg
# 获取身份的 client_id
az identity show --name myidentity --resource-group myrg --query clientId
# 将身份分配给 App Service
az webapp identity assign --name myapp --resource-group myrg --identities myidentity
步骤二:授予权限
启用托管身份后,需要为身份授予访问其他资源的权限。
使用 Azure RBAC:
# 为托管身份授予 Storage Blob Data Reader 角色
az role assignment create \
--assignee <managed-identity-principal-id> \
--role "Storage Blob Data Reader" \
--scope /subscriptions/<subscription-id>/resourceGroups/<rg>/providers/Microsoft.Storage/storageAccounts/<account>
# 为托管身份授予 Key Vault Secrets User 角色
az role assignment create \
--assignee <managed-identity-principal-id> \
--role "Key Vault Secrets User" \
--scope /subscriptions/<subscription-id>/resourceGroups/<rg>/providers/Microsoft.KeyVault/vaults/<vault>
使用 Key Vault 访问策略(旧方式):
az keyvault set-policy \
--name myvault \
--object-id <managed-identity-principal-id> \
--secret-permissions get list
步骤三:在应用程序中使用
使用 Azure SDK
Azure SDK 的 DefaultAzureCredential 会自动尝试多种认证方式,包括托管身份:
from azure.identity import DefaultAzureCredential
from azure.storage.blob import BlobServiceClient
# DefaultAzureCredential 会自动:
# 1. 尝试环境变量(ServicePrincipal)
# 2. 尝试托管身份(在 Azure 中运行时)
# 3. 尝试 Azure CLI(本地开发时)
# 4. 尝试 Visual Studio Code(本地开发时)
credential = DefaultAzureCredential()
blob_service_client = BlobServiceClient(
account_url="https://myaccount.blob.core.windows.net",
credential=credential
)
直接获取令牌
如果需要直接获取访问令牌:
import requests
# 通过 Azure Instance Metadata Service (IMDS) 获取令牌
# 仅在 Azure 中运行时可用
def get_access_token(resource):
url = "http://169.254.169.254/metadata/identity/oauth2/token"
params = {
"api-version": "2018-02-01",
"resource": resource
}
headers = {
"Metadata": "true"
}
response = requests.get(url, params=params, headers=headers)
return response.json()["access_token"]
# 获取 Storage 的访问令牌
token = get_access_token("https://storage.azure.com/")
步骤四:本地开发
在本地开发时,没有托管身份,可以使用以下方式:
Azure CLI:登录 Azure CLI,
DefaultAzureCredential会自动使用 CLI 的凭据az loginAzure PowerShell:登录 Azure PowerShell
Connect-AzAccountVisual Studio Code:安装 Azure Account 扩展并登录
环境变量:使用 Service Principal 的环境变量(仅用于本地开发,不要提交到代码仓库)
最佳实践
1. 最小权限原则
- 只为托管身份授予完成任务所需的最小权限
- 使用 Azure RBAC 的细粒度角色,而非 Contributor 或 Owner
- 定期审查权限分配,移除不再需要的权限
2. 使用用户分配的托管身份
在以下场景中,优先使用用户分配的托管身份:
- 多个资源需要共享同一身份
- 需要在创建资源之前预创建身份
- 需要独立于资源生命周期管理身份
- 需要在多个资源之间迁移身份
3. 避免混合使用凭据
- 不要在使用托管身份的同时,又在配置文件中存储凭据
- 全面迁移到托管身份,避免部分使用旧方式
- 定期扫描代码和配置,确保没有硬编码的凭据
4. 监控和审计
- 启用 Azure AD 审计日志,监控托管身份的操作
- 使用 Azure Monitor 监控身份的使用情况
- 设置异常行为告警(如异常时间、异常地点的访问)
5. 灾难恢复
- 了解托管身份在区域故障时的行为
- 对于关键应用,考虑使用用户分配的托管身份,以便在区域间迁移
- 测试身份相关的故障场景
常见问题
Q: 托管身份可以跨租户使用吗?
A: 系统分配的托管身份只能在创建它的租户中使用。用户分配的托管身份也只能在创建它的租户中使用,但可以分配给该租户中的任何资源。
Q: 托管身份可以访问本地资源吗?
A: 托管身份是 Azure AD 身份,可以访问支持 Azure AD 认证的云资源。对于本地资源,需要通过 Azure AD Application Proxy 或其他方式集成。
Q: 托管身份的令牌有效期是多久?
A: 访问令牌的有效期通常为 1 小时。Azure SDK 会自动处理令牌的刷新,不需要手动管理。
Q: 可以在容器中使用托管身份吗?
A: 可以。在 Azure Kubernetes Service (AKS) 中,可以使用 Azure AD Workload Identity 为 Pod 分配托管身份。在 Azure Container Apps 中,也支持托管身份。
Q: 托管身份会产生费用吗?
A: 托管身份本身是免费的,不产生额外费用。
总结
Azure 托管身份提供了一种更安全、更易维护的方式来管理 Azure 资源的身份认证,彻底解决了"凭据存在哪里"的困境。
核心要点:
- 无需存储凭据:开发者不需要存储或管理任何密钥,消除了凭据泄露的风险
- 自动轮换:Azure 自动管理和轮换凭据,无需人工干预
- 细粒度控制:通过 Azure RBAC 精确控制身份的权限
- 统一管理:所有资源的身份管理方式一致,降低了管理复杂性
- 本地开发友好:
DefaultAzureCredential在本地和 Azure 中都能正常工作
在 2026 年,托管身份已经成为 Azure 开发的最佳实践。对于新的 Azure 项目,应该从一开始就使用托管身份,而不是传统的存储凭据方式。对于现有项目,也应该逐步迁移到托管身份,提高安全性和可维护性。
正如文章所说,每个 Azure 项目最终都会面临"连接字符串存在哪里"的问题。而托管身份给出的答案是:哪里都不需要存。
原文链接:https://dev.to/carlosjcastrog/why-azure-managed-identity-replaces-stored-credentials-and-how-to-use-it-in-2026-29cj