自动轮换使用单用户/单密码身份验证的资源的机密Automate the rotation of a secret for resources that use single-user/single-password authentication

向 Azure 服务进行身份验证的最佳方法是使用托管标识,但某些情况下无法做到这一点。The best way to authenticate to Azure services is by using a managed identity, but there are some scenarios where that isn't an option. 在此类情况下,将使用访问密钥或机密。In those cases, access keys or secrets are used. 应定期轮换访问密钥或机密。You should periodically rotate access keys or secrets.

本教程介绍如何定期自动轮换使用单用户/单密码身份验证的数据库和服务的机密。This tutorial shows how to automate the periodic rotation of secrets for databases and services that use single-user/single-password authentication. 具体而言,本教程将使用 Azure 事件网格通知触发的函数来轮换 Azure Key Vault 中存储的 SQL Server 密码:Specifically, this tutorial rotates SQL Server passwords stored in Azure Key Vault by using a function triggered by Azure Event Grid notification:

轮换解决方案示意图

  1. 在机密过期之前的 30 天,Key Vault 会向事件网格发布“即将过期”事件。Thirty days before the expiration date of a secret, Key Vault publishes the "near expiry" event to Event Grid.
  2. 事件网格会检查事件订阅,并使用 HTTP POST 调用已订阅该事件的函数应用终结点。Event Grid checks the event subscriptions and uses HTTP POST to call the function app endpoint subscribed to the event.
  3. 函数应用接收机密信息,生成新的随机密码,然后在 Key Vault 中使用新密码为机密创建新的版本。The function app receives the secret information, generates a new random password, and creates a new version for the secret with the new password in Key Vault.
  4. 函数应用使用新密码更新 SQL Server。The function app updates SQL Server with the new password.

备注

步骤 3 与 4 之间可能会存在滞后现象。There could be a lag between steps 3 and 4. 在此期间,Key Vault 中的机密无法向 SQL Server 进行身份验证。During that time, the secret in Key Vault won't be able to authenticate to SQL Server. 如果任一步骤失败,事件网格将重试两小时。In case of a failure of any of the steps, Event Grid retries for two hours.

创建密钥保管库和 SQL Server 实例Create a key vault and SQL Server instance

第一步是创建密钥保管库、SQL Server 实例和数据库,并将 SQL Server 管理员密码存储在 Key Vault 中。The first step is to create a key vault and a SQL Server instance and database and store the SQL Server admin password in Key Vault.

本教程使用现有的 Azure 资源管理器模板来创建组件。This tutorial uses an existing Azure Resource Manager template to create components. 可在此处找到代码:基本机密轮换模板示例You can find the code here: Basic Secret Rotation Template Sample.

  1. 选择 Azure 模板部署链接:Select the Azure template deployment link:

  2. 在“资源组”下,选择“新建”。Under Resource group, select Create new. 将组命名为 simplerotation。Name the group simplerotation.

  3. 选择“购买”。Select Purchase.

    创建资源组

现在,你已获得一个密钥保管库、一个 SQL Server 实例和一个 SQL 数据库。You'll now have a key vault, a SQL Server instance, and a SQL database. 可以在 Azure CLI 中运行以下命令来验证此设置:You can verify this setup in the Azure CLI by running the following command:

az resource list -o table

结果类似于以下输出:The result will look something the following output:

Name                     ResourceGroup         Location    Type                               Status
-----------------------  --------------------  ----------  ---------------------------------  --------
simplerotation-kv          simplerotation      chinaeast      Microsoft.KeyVault/vaults
simplerotation-sql         simplerotation      chinaeast      Microsoft.Sql/servers
simplerotation-sql/master  simplerotation      chinaeast      Microsoft.Sql/servers/databases

创建函数应用Create a function app

接下来,创建一个使用系统托管标识的函数应用,以及其他所需组件。Next, create a function app with a system-managed identity, in addition to the other required components.

该函数应用需要以下组件:The function app requires these components:

  • 一个 Azure 应用服务计划An Azure App Service plan
  • 一个存储帐户A storage account
  • 一个用于通过函数应用托管标识访问 Key Vault 中的机密的访问策略An access policy to access secrets in Key Vault via function app managed identity
  1. 选择 Azure 模板部署链接:Select the Azure template deployment link:

  2. 在“资源组”列表中选择“simplerotation”。 In the Resource group list, select simplerotation.

  3. 选择“购买”。Select Purchase.

    选择“购买”

完成上述步骤后,你将获得一个存储帐户、一个服务器场和一个函数应用。After you complete the preceding steps, you'll have a storage account, a server farm, and a function app. 可以在 Azure CLI 中运行以下命令来验证此设置:You can verify this setup in the Azure CLI by running the following command:

az resource list -o table

结果类似于以下输出:The result will look something like the following output:

Name                     ResourceGroup         Location    Type                               Status
-----------------------  --------------------  ----------  ---------------------------------  --------
simplerotation-kv          simplerotation       chinaeast      Microsoft.KeyVault/vaults
simplerotation-sql         simplerotation       chinaeast      Microsoft.Sql/servers
simplerotation-sql/master  simplerotation       chinaeast      Microsoft.Sql/servers/databases
simplerotationstrg         simplerotation       chinaeast      Microsoft.Storage/storageAccounts
simplerotation-plan        simplerotation       chinaeast      Microsoft.Web/serverFarms
simplerotation-fn          simplerotation       chinaeast      Microsoft.Web/sites

有关如何创建函数应用和使用托管标识访问 Key Vault 的信息,请参阅从 Azure 门户创建函数应用使用托管标识提供 Key Vault 身份验证For information on how to create a function app and use managed identity to access Key Vault, see Create a function app from the Azure portal and Provide Key Vault authentication with a managed identity.

轮换函数Rotation function

该函数使用事件通过更新 Key Vault 和 SQL 数据库来触发机密轮换。The function uses an event to trigger the rotation of a secret by updating Key Vault and the SQL database.

函数触发器事件Function trigger event

此函数读取事件数据并运行轮换逻辑:This function reads event data and runs the rotation logic:

public static class SimpleRotationEventHandler
{
    [FunctionName("SimpleRotation")]
       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}");

            SeretRotator.RotateSecret(log, secretName, secretVersion, keyVaultName);
        }
}

机密轮换逻辑Secret rotation logic

此轮换方法从机密中读取数据库信息,创建机密的新版本,并使用新机密更新数据库:This rotation method reads database information from the secret, creates a new version of the secret, and updates the database with the new secret:

public class SecretRotator
    {
       private const string UserIdTagName = "UserID";
       private const string DataSourceTagName = "DataSource";
       private const int SecretExpirationDays = 31;

    public static void RotateSecret(ILogger log, string secretName, string secretVersion, string keyVaultName)
    {
           //Retrieve current secret
           var kvUri = "https://" + keyVaultName + ".vault.azure.cn";
           var client = new SecretClient(new Uri(kvUri), new DefaultAzureCredential());
           KeyVaultSecret secret = client.GetSecret(secretName, secretVersion);
           log.LogInformation("Secret Info Retrieved");
        
           //Retrieve secret info
           var userId = secret.Properties.Tags.ContainsKey(UserIdTagName) ?  
                        secret.Properties.Tags[UserIdTagName] : "";
           var datasource = secret.Properties.Tags.ContainsKey(DataSourceTagName) ? 
                            secret.Properties.Tags[DataSourceTagName] : "";
           log.LogInformation($"Data Source Name: {datasource}");
           log.LogInformation($"User Id Name: {userId}");
        
           //Create new password
           var randomPassword = CreateRandomPassword();
           log.LogInformation("New Password Generated");
        
           //Check DB connection using existing secret
           CheckServiceConnection(secret);
           log.LogInformation("Service Connection Validated");
                    
           //Create new secret with generated password
           CreateNewSecretVersion(client, secret, randomPassword);
           log.LogInformation("New Secret Version Generated");
        
           //Update DB password
           UpdateServicePassword(secret, randomPassword);
           log.LogInformation("Password Changed");
           log.LogInformation($"Secret Rotated Succesffuly");
    }
}

可以在 GitHub 上找到完整代码。You can find the complete code on GitHub.

函数部署Function deployment

  1. GitHub 下载函数应用 zip 文件。Download the function app zip file from GitHub.

  2. 将 simplerotationsample-fn.zip 文件上传到 Azure Cloud Shell。Upload the simplerotationsample-fn.zip file to Azure Cloud Shell.

    上传文件

  3. 使用以下 Azure CLI 命令将 zip 文件部署到函数应用:Use this Azure CLI command to deploy the zip file to the function app:

    az functionapp deployment source config-zip -g simplerotation -n simplerotation-fn --src /home/{firstname e.g jack}/simplerotationsample-fn.zip
    

部署该函数后,应会在 simplerotation-fn 下看到两个函数:After the function is deployed, you should see two functions under simplerotation-fn:

SimpleRotation 和 SimpleRotationHttpTest 函数

添加对 SecretNearExpiry 事件的事件订阅Add an event subscription for the SecretNearExpiry event

复制函数应用的 eventgrid_extension 密钥:Copy the function app's eventgrid_extension key:

选择函数应用设置

eventgrid_extension 密钥

在以下命令中使用复制的 eventgrid_extension 密钥和你的订阅 ID,创建对 SecretNearExpiry 事件的事件网格订阅:Use the copied eventgrid_extension key and your subscription ID in the following command to create an Event Grid subscription for SecretNearExpiry events:

az eventgrid event-subscription create --name simplerotation-eventsubscription --source-resource-id "/subscriptions/<subscription-id>/resourceGroups/simplerotation/providers/Microsoft.KeyVault/vaults/simplerotation-kv" --endpoint "https://simplerotation-fn.chinacloudapi.cn/runtime/webhooks/EventGrid?functionName=SimpleRotation&code=<extension-key>" --endpoint-type WebHook --included-event-types "Microsoft.KeyVault.SecretNearExpiry"

将机密添加到 Key VaultAdd the secret to Key Vault

设置访问策略,以向用户授予“管理机密”权限:Set your access policy to grant manage secrets permissions to users:

az keyvault set-policy --upn <email-address-of-user> --name simplerotation-kv --secret-permissions set delete get list

创建一个新机密,该机密的标记包含 SQL 数据库数据源和用户 ID。Create a new secret with tags that contain the SQL database data source and the user ID. 包含一个设置为明天的过期日期。Include an expiration date that's set for tomorrow.

$tomorrowDate = (get-date).AddDays(+1).ToString("yyy-MM-ddThh:mm:ssZ")
az keyvault secret set --name sqluser --vault-name simplerotation-kv --value "Simple123" --tags "UserID=azureuser" "DataSource=simplerotation-sql.database.chinacloudapi.cn" --expires $tomorrowDate

创建过期时间较短的机密会立即发布 SecretNearExpiry 事件,而该事件又会触发函数来轮换该机密。Creating a secret with a short expiration date will immediately publish a SecretNearExpiry event, which will in turn trigger the function to rotate the secret.

测试和验证Test and verify

几分钟后,sqluser 机密应会自动轮换。After few minutes, the sqluser secret should automatically rotate.

若要验证该机密是否已轮换,请转到“Key Vault” > “机密”: To verify that the secret has rotated, go to Key Vault > Secrets:

转到“机密”

打开“sqluser”机密并查看原始版本和轮换后的版本:Open the sqluser secret and view the original and rotated versions:

打开 sqluser 机密

创建 Web 应用Create a web app

若要验证 SQL 凭据,请创建一个 Web 应用。To verify the SQL credentials, create a web app. 此 Web 应用将从 Key Vault 获取机密,从机密中提取 SQL 数据库信息和凭据,然后测试与 SQL Server 的连接。This web app will get the secret from Key Vault, extract SQL database information and credentials from the secret, and test the connection to SQL Server.

该 Web 应用需要以下组件:The web app requires these components:

  • 一个使用系统托管标识的 Web 应用A web app with system-managed identity
  • 一个用于通过 Web 应用托管标识访问 Key Vault 中的机密的访问策略An access policy to access secrets in Key Vault via web app managed identity
  1. 选择 Azure 模板部署链接:Select the Azure template deployment link:
  2. 选择“simplerotation”资源组。Select the simplerotation resource group.
  3. 选择“购买”。Select Purchase.

部署 Web 应用Deploy the web app

可以在 GitHub 上找到该 Web 应用的源代码。You can find source code for the web app on GitHub.

若要部署 Web 应用,请完成以下步骤:To deploy the web app, complete these steps:

  1. GitHub 下载函数应用 zip 文件。Download the function app zip file from GitHub.

  2. 将 simplerotationsample-app.zip 文件上传到 Azure Cloud Shell。Upload the simplerotationsample-app.zip file to Azure Cloud Shell.

  3. 使用以下 Azure CLI 命令将 zip 文件部署到函数应用:Use this Azure CLI command to deploy the zip file to the function app:

    az webapp deployment source config-zip -g simplerotation -n simplerotation-app --src /home/{firstname e.g jack}/simplerotationsample-app.zip
    

打开 Web 应用Open the web app

转到部署的应用程序并选择 URL:Go to the deployed application and select the URL:

选择 URL

当应用程序在浏览器中打开时,你会看到“生成的机密值”,并会看到“数据库已连接”的值为“true”。When the application opens in the browser, you will see the Generated Secret Value and a Database Connected value of true.