你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
向Azure服务进行身份验证的最佳方式是使用托管标识,但某些方案需要访问密钥、密码或其他机密。 定期轮换这些机密,以减少泄露凭据的影响。
本教程介绍如何为使用一组身份验证凭据的数据库和服务自动执行定期机密轮换。 有关不同资产类型中的自动轮换概述,请参阅了解 Azure 密钥保管库 中的自动轮换。
具体而言,本教程使用由Azure 事件网格通知触发的函数轮换存储在Azure 密钥保管库中的SQL Server密码:
Tip
对于 Azure SQL 数据库 和 Azure SQL 托管实例,应优先使用 仅限 Microsoft Entra 的身份验证,而非 SQL 登录。 仅当工作负荷需要 SQL 身份验证时,才在本教程中使用密码轮换模式。
- 在机密到期日期之前的三十天,密钥保管库将“即将过期”事件发布到事件网格。
- 事件网格会检查事件订阅,并使用 HTTP POST 调用已订阅该事件的函数应用终结点。
- 函数应用接收机密信息,生成新的随机密码,并在密钥保管库中使用新密码为机密创建新版本。
- 函数应用使用新密码更新SQL Server。
注释
步骤 3 和步骤 4 之间可能存在延迟。 在该窗口中,密钥保管库中的机密无法向SQL Server进行身份验证。 如果任何步骤失败,事件网格将重试两个小时。
先决条件
- Azure订阅 - 免费创建一个订阅。
- Azure 密钥保管库。
- SQL Server。
如果还没有密钥保管库和SQL Server实例,请使用以下部署链接:
- 在 “资源组”下,选择“ 新建”,并为组命名。 本教程使用 akvrotation。
- 在 SQL 管理员登录名下,输入 SQL 管理员登录名。
- 选择“查看 + 创建”。
- 选择 创建。
现在有一个密钥保管库和一个SQL Server实例。 在Azure CLI中验证此设置:
az resource list -o table -g akvrotation
结果类似于以下输出:
Name ResourceGroup Location Type Status
----------------------- -------------------- ---------- --------------------------------- --------
akvrotation-kv akvrotation eastus Microsoft.KeyVault/vaults
akvrotation-sql akvrotation eastus Microsoft.Sql/servers
akvrotation-sql/master akvrotation eastus Microsoft.Sql/servers/databases
akvrotation-sql2 akvrotation eastus Microsoft.Sql/servers
akvrotation-sql2/master akvrotation eastus Microsoft.Sql/servers/databases
创建和部署SQL Server密码轮换函数
重要
此模板要求 Key Vault、SQL Server 实例和函数应用位于同一资源组中。
接下来,创建具有系统分配的托管标识和其他必需组件的函数应用,并部署SQL Server密码轮换函数。
函数应用需要以下组件:
- Azure 应用服务 的计划。
- 包含具有 Event Grid 触发器和 HTTP 触发器的 SQL 密码轮换函数的函数应用。
- 用于函数应用触发器管理的存储帐户。
- 一个 Azure 角色分配,允许函数应用标识访问密钥保管库中的机密。
- SecretNearExpiry 事件的事件网格事件订阅。
选择Azure模板部署链接:
在 资源组 列表中,选择 akvrotation。
在SQL Server名称中,输入要轮换其密码的SQL Server实例的名称。
在密钥保管库名称中,输入密钥保管库名称。
在 函数应用名称中,输入函数应用名称。
在 机密名称中,输入存储密码的机密名称。
在“存储库 URL”中,输入函数代码的 GitHub 位置:
https://github.com/Azure-Samples/KeyVault-Rotation-SQLPassword-Csharp.git。选择“查看 + 创建”。
选择 创建。
注释
此 ARM 模板使用应用服务源代码管理(Kudu)部署,以从 GitHub 拉取函数代码。 对于生产工作负载,我们建议使用基于包的部署,例如 func azure functionapp publish 或配合 WEBSITE_RUN_FROM_PACKAGE 的 zip 部署。
完成上述步骤后,你有一个存储帐户、服务器场和一个函数应用。 在Azure CLI中验证此设置:
az resource list -o table -g akvrotation
结果类似于以下输出:
Name ResourceGroup Location Type Status
----------------------- -------------------- ---------- --------------------------------- --------
akvrotation-kv akvrotation eastus Microsoft.KeyVault/vaults
akvrotation-sql akvrotation eastus Microsoft.Sql/servers
akvrotation-sql/master akvrotation eastus Microsoft.Sql/servers/databases
cfogyydrufs5wazfunctions akvrotation eastus Microsoft.Storage/storageAccounts
akvrotation-fnapp akvrotation eastus Microsoft.Web/serverFarms
akvrotation-fnapp akvrotation eastus Microsoft.Web/sites
akvrotation-fnapp akvrotation eastus Microsoft.insights/components
有关创建函数应用和使用托管标识访问密钥保管库的详细信息,请参阅从 Azure 门户创建函数应用、如何使用应用服务和Azure Functions的托管标识,以及通过 Azure RBAC 提供对密钥保管库的访问权限。
注释
示例函数面向 Azure Functions 的 .NET 进程内模型。 对于新开发,请使用 .NET 隔离工作器模型,这是未来将持续受支持的模型。
旋转函数
在上一步中部署的函数使用事件来触发机密轮换。 它更新密钥保管库和 SQL 数据库。
函数触发器事件
此函数读取事件数据并运行旋转逻辑:
public static class SimpleRotationEventHandler
{
[FunctionName("AKVSQLRotation")]
public static void Run([EventGridTrigger]EventGridEvent eventGridEvent, ILogger log)
{
log.LogInformation("C# Event trigger function processed a request.");
var secretName = eventGridEvent.Subject;
var secretVersion = Regex.Match(eventGridEvent.Data.ToString(), "Version\":\"([a-z0-9]*)").Groups[1].ToString();
var keyVaultName = Regex.Match(eventGridEvent.Topic, ".vaults.(.*)").Groups[1].ToString();
log.LogInformation($"Key Vault Name: {keyVaultName}");
log.LogInformation($"Secret Name: {secretName}");
log.LogInformation($"Secret Version: {secretVersion}");
SecretRotator.RotateSecret(log, secretName, keyVaultName);
}
}
机密轮换逻辑
此轮换方法从机密中读取数据库信息,创建新版本的机密,并使用新机密更新数据库:
public class SecretRotator
{
private const string CredentialIdTag = "CredentialId";
private const string ProviderAddressTag = "ProviderAddress";
private const string ValidityPeriodDaysTag = "ValidityPeriodDays";
public static void RotateSecret(ILogger log, string secretName, string keyVaultName)
{
//Retrieve Current Secret
var kvUri = "https://" + keyVaultName + ".vault.azure.net";
var client = new SecretClient(new Uri(kvUri), new DefaultAzureCredential());
KeyVaultSecret secret = client.GetSecret(secretName);
log.LogInformation("Secret Info Retrieved");
//Retrieve Secret Info
var credentialId = secret.Properties.Tags.ContainsKey(CredentialIdTag) ? secret.Properties.Tags[CredentialIdTag] : "";
var providerAddress = secret.Properties.Tags.ContainsKey(ProviderAddressTag) ? secret.Properties.Tags[ProviderAddressTag] : "";
var validityPeriodDays = secret.Properties.Tags.ContainsKey(ValidityPeriodDaysTag) ? secret.Properties.Tags[ValidityPeriodDaysTag] : "";
log.LogInformation($"Provider Address: {providerAddress}");
log.LogInformation($"Credential Id: {credentialId}");
//Check Service Provider connection
CheckServiceConnection(secret);
log.LogInformation("Service Connection Validated");
//Create new password
var randomPassword = CreateRandomPassword();
log.LogInformation("New Password Generated");
//Add secret version with new password to Key Vault
CreateNewSecretVersion(client, secret, randomPassword);
log.LogInformation("New Secret Version Generated");
//Update Service Provider with new password
UpdateServicePassword(secret, randomPassword);
log.LogInformation("Password Changed");
log.LogInformation($"Secret Rotated Successfully");
}
}
可以在 GitHub 上找到完整的代码。
将机密添加到密钥保管库
为自己分配密钥保管库机密管理员角色,以便管理保管库中的机密:
az role assignment create --role "Key Vault Secrets Officer" --assignee <email-address-of-user> --scope /subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.KeyVault/vaults/akvrotation-kv
创建包含SQL Server资源 ID、SQL Server登录名和机密有效期(以天为单位)的标记的机密。 设置机密名称、SQL 数据库的初始密码(Simple123 在本示例中),并将过期日期设置为明天,以便立即触发轮换。
tomorrowDate=$(date -u -d "+1 day" +"%Y-%m-%dT%H:%M:%SZ")
az keyvault secret set --name sqlPassword --vault-name akvrotation-kv --value "Simple123" --tags "CredentialId=sqlAdmin" "ProviderAddress=<sql-database-resource-id>" "ValidityPeriodDays=90" --expires $tomorrowDate
将到期时间设置得较短,会在 15 分钟内发布一个 SecretNearExpiry 事件,从而触发该函数轮换机密。
测试和验证
若要验证机密是否已轮换,请转到 密钥保管库>Secrets:
打开 sqlPassword 机密并查看原始版本和旋转版本:
创建 Web 应用
若要验证 SQL 凭据,请创建 Web 应用。 Web 应用从密钥保管库检索机密,从机密中提取 SQL 数据库信息和凭据,并测试与SQL Server的连接。
Web 应用需要以下组件:
- 具有系统分配的托管标识的 Web 应用。
- 一个角色分配,允许 Web 应用的托管标识读取密钥保管库中的机密。
选择Azure模板部署链接:
选择 akvrotation 资源组。
在SQL Server 名称字段中,输入其密码已轮换的 SQL Server 名称。
在密钥保管库名称中,输入密钥保管库名称。
在 机密名称中,输入存储密码的机密名称。
在“存储库 URL”中,输入 Web 应用代码的 GitHub 位置:
https://github.com/Azure-Samples/KeyVault-Rotation-SQLPassword-Csharp-WebApp.git。选择“查看 + 创建”。
选择 创建。
打开 Web 应用
转到已部署的应用程序 URL: https://akvrotation-app.azurewebsites.net/。
当应用程序在浏览器中打开时,页面会显示 生成的机密值 和 数据库连接 值 true。
使用 AI 自定义数据库的旋转函数
本教程演示SQL Server的机密轮换,但你可以针对其他数据库类型调整轮换函数。 GitHub Copilot 可以帮助你修改轮换函数的代码,使其适用于你的数据库或凭据类型。
I'm using the Azure Key Vault secret rotation tutorial for SQL Server. Help me modify the rotation function to work with PostgreSQL instead. The function should:
1. Generate a new secure password
2. Update the PostgreSQL database user password
3. Store the new password in Key Vault
Show me the changes needed to the C# function code, including the correct PostgreSQL connection library and password update command.
Copilot还有助于为其他凭据类型(如 API 密钥、连接字符串或服务帐户密码)调整此模式。
GitHub Copilot由 AI 提供支持,因此可能会带来惊喜和错误。 有关详细信息,请参阅 Copilot 常见问题解答。
了解详细信息
- 使用两组凭据进行资源轮换
- 理解 Azure 密钥保管库 中的自动轮换
- 监控 密钥保管库 使用 Azure 事件网格
- 密钥保管库机密更改时接收电子邮件
- Azure 事件网格 事件架构 for Azure 密钥保管库