通过


你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

自动轮换使用一组身份验证凭据的资源的机密

若要对Azure服务进行身份验证的最佳方法是使用 托管标识,但在某些情况下,情况并非如此。 在这些情况下,使用访问密钥或机密。 应定期轮换访问密钥或机密。

本教程介绍如何为使用一组身份验证凭据的数据库和服务自动轮换机密。 有关不同资产类型的自动轮换概念及其优势的全面概述,请参阅 Azure 密钥保管库 中对自动轮换的了解。

具体而言,本教程使用由Azure 事件网格通知触发的函数轮换存储在Azure 密钥保管库中的SQL Server密码:

旋转解决方案示意图

  1. 在机密到期日期之前的三十天,密钥保管库将“即将过期”事件发布到事件网格。
  2. 事件网格会检查事件订阅,并使用 HTTP POST 调用已订阅该事件的函数应用终结点。
  3. 函数应用接收机密信息,生成新的随机密码,并在密钥保管库中使用新密码为机密创建新版本。
  4. 函数应用使用新密码更新SQL Server。

注释

步骤 3 和步骤 4 之间可能存在延迟。 在此期间,密钥保管库中的机密将无法对SQL Server进行身份验证。 如果任一步骤失败,事件网格会重试两个小时。

先决条件

如果没有现有的密钥保管库和SQL Server,则可以使用此部署链接:

Image 显示标记为“部署到Azure”的按钮

  1. 在“资源组”下,选择“新建”。 为组命名,我们将在本教程中使用 akvrotation
  2. “SQL 管理员登录名”下,键入 SQL 管理员登录名。
  3. 选择“查看 + 创建”
  4. 选择 创建

创建资源组

现在,你将有一个密钥保管库和一个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 密码轮换函数

重要

此模板要求密钥保管库、SQL Server 和 Azure 函数位于同一资源组中。

接下来,创建具有系统托管标识的函数应用,以及其他必需的组件,并部署 SQL Server 密码轮换函数

函数应用需要以下组件:

  • Azure 应用服务 计划
  • 带有SQL密码轮换功能以及事件触发器和HTTP触发器的Function App
  • 进行函数应用触发器管理时所需的存储帐户
  • 用于函数应用标识访问 密钥保管库 中机密的 Azure RBAC 角色分配
  • “SecretNearExpiry”事件的事件网格事件订阅
  1. 选择Azure模板部署链接:

    Image 显示标记为“部署到Azure”的按钮

  2. 资源组 列表中,选择 akvrotation

  3. SQL Server Name 中,输入要旋转密钥的 SQL Server 名称和密码。

  4. 密钥保管库 Name中,键入key vault名称

  5. 函数应用名称中,键入函数应用名称

  6. 机密名称中,键入将存储密码的机密名称

  7. Repo Url 中,键入函数代码GitHub位置(https://github.com/Azure-Samples/KeyVault-Rotation-SQLPassword-Csharp.git

  8. 选择“查看 + 创建”

  9. 选择 创建

选择“审阅+创建”

完成上述步骤后,你将拥有存储帐户、服务器场和函数应用。 可以通过运行以下命令在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 为 密钥保管库 提供访问权限

旋转函数

在先前步骤中部署的函数使用事件通过更新 密钥保管库 和 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 = (get-date).AddDays(+1).ToString("yyyy-MM-ddThh:mm:ssZ")
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

截图展示如何访问 密钥保管库 > Secrets。

打开 sqlPassword 机密并查看原始版本和旋转版本:

转到“机密”

创建 Web 应用

若要验证 SQL 凭据,请创建 Web 应用。 此 Web 应用将从密钥保管库获取机密,从机密中提取 SQL 数据库信息和凭据,并测试与SQL Server的连接。

Web 应用需要以下组件:

  • 一个使用系统托管标识的 Web 应用
  • 访问策略,用于通过 Web 应用托管标识访问密钥保管库中的机密
  1. 选择Azure模板部署链接:

    Image 显示标记为“部署到Azure”的按钮

  2. 选择 akvrotation 资源组。

  3. 在“SQL Server 名称”中,键入密码需进行轮替的 SQL Server 名称

  4. 密钥保管库 Name中,键入key vault名称

  5. 机密名称中,键入存储密码的机密名称

  6. Repo Url 中,键入 web 应用代码GitHub位置(https://github.com/Azure-Samples/KeyVault-Rotation-SQLPassword-Csharp-WebApp.git

  7. 选择“查看 + 创建”

  8. 选择 创建

打开 Web 应用

转到已部署的应用程序 URL:

“https://akvrotation-app.azurewebsites.net/”

当应用程序在浏览器中打开时,你将看到 “生成的机密值 ”和“ 数据库连接 ”值 true

使用 AI 自定义数据库的旋转函数

本教程演示SQL Server的机密轮换,但你可以针对其他数据库类型调整轮换函数。 VS Code 中的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 常见问题解答

了解详细信息