針對使用一組驗證認證的資源,將秘密的輪替自動化

向 Azure 服務進行驗證的最佳方式是使用受控識別,但在某些情況下並無法使用此選項。 在這類情況下,應使用存取金鑰或祕密。 您應該定期輪替存取金鑰或祕密。

本教學課程示範如何針對使用一組驗證認證的資料庫和服務自動執行定期的秘密輪替。 具體而言,此教學課程會使用 Azure 事件方格通知所觸發的函式,來輪替儲存在 Azure Key Vault 中的 SQL Server 密碼:

Diagram of rotation solution

  1. 在密鑰過期日期前 30 天,Key Vault 會將「即將過期」事件發佈到事件網格。
  2. 事件網格檢查事件訂閱並使用 HTTP POST 調用訂閱事件的函數應用程式端點。
  3. 函數應用程式接收祕密資訊,產生新的隨機密碼,並使用 Key Vault 中的新密碼為祕密建立新版本。
  4. 函數應用程式程式使用新密碼更新 SQL Server。

注意

步驟 3 和 4 之間可能會有延遲。 在這段期間內,Key Vault 中的祕密無法向 SQL Server 進行驗證。 若有任何步驟失敗,事件方格會重試 2 小時。

必要條件

如果您沒有現有的 Key Vault 和 SQL Server,即可使用此部署連結:

Image showing a button labeled

  1. 在 [資源群組] 下,選取 [新建]。 為群組命名,我們會在本教學課程中使用 akvrotation
  2. 在 [SQL 管理員登入] 底下,輸入 SQL 管理員登入名稱。
  3. 選取 [檢閱 + 建立]。
  4. 選取 [建立]

Create a resource group

您現在會有 Key Vault 和 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 App Service 方案
  • 具有 SQL 密碼輪替函式 (含事件觸發程序和 http 觸發程序) 的函數應用程式
  • 函數應用程式觸發程式管理所需的儲存體帳戶
  • 供函數應用程式受控識別存取 Key Vault 中秘密的存取原則
  • SecretNearExpiry 事件的事件方格事件訂用帳戶
  1. 選取 Azure 範本部署連結:

    Image showing a button labeled

  2. 在 [資源群組] 清單中,選取 [akvrotation]

  3. 在 [SQL Server 名稱] 中,輸入要輪替密碼的 SQL Server 名稱

  4. 在 [Key Vault 名稱] 中,輸入金鑰保存庫名稱

  5. 在 [函數應用程式名稱] 中,輸入函式應用程式名稱

  6. 在 [秘密名稱] 中,輸入要儲存密碼的秘密名稱

  7. 在 [存放庫 URL] 中,輸入函式程式碼 GitHub 位置 (https://github.com/Azure-Samples/KeyVault-Rotation-SQLPassword-Csharp.git)

  8. 選取 [檢閱 + 建立]。

  9. 選取 建立

Select Review+create

完成上述步驟之後,您將會有儲存體帳戶、伺服器陣列和函式應用程式。 您可以執行下列命令,在 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

如需如何建立函式應用程式和使用受控識別來存取 Key Vault 的相關資訊,請參閱從 Azure 入口網站建立函式應用程式如何使用 App Service 和 Azure Functions 的受控識別以及使用 Azure 入口網站指派 Key Vault 存取金鑰

輪替函式

前一個步驟中部署的函式會透過更新 Key Vault 和 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 上找到完整的程式碼。

將秘密新增至 Key Vault

設定存取原則,將「管理秘密」權限授與使用者:

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

建立新祕密,其中標籤包含 SQL Server 資源識別碼、SQL Server 登入名稱,以及祕密的有效期間 (以天為單位)。 提供密碼的名稱、SQL 資料庫中的初始密碼 (我們範例中的 "Simple123"),並包含設為明天到期的到期日。

$tomorrowDate = (get-date).AddDays(+1).ToString("yyy-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 事件,進而觸發函式進行秘密輪替。

測試和驗證

若要確認密碼是否已輪替,請移至 Key Vault>秘密

Screenshot that shows how to access Key Vault > Secrets.

開啟 sqlPassword 秘密,並檢視原始和已輪替的版本:

Go to Secrets

建立 Web 應用程式

若要確認 SQL 認證,請建立 Web 應用程式。 此 Web 應用程式會從 Key Vault 中取得秘密、從祕密中解壓縮 SQL 資料庫資訊和認證,並測試 SQL 的連線。

Web 應用程式需要以下元件:

  • 具有系統管理身分識別的 Web 應用程式
  • 透過 Web 應用程式受控識別存取 Key Vault 所含秘密的存取原則
  1. 選取 Azure 範本部署連結:

    Image showing a button labeled

  2. 選取 akvrotation 資源群組。

  3. 在 [SQL Server 名稱] 中,輸入要輪替密碼的 SQL Server 名稱

  4. 在 [Key Vault 名稱] 中,輸入金鑰保存庫名稱

  5. 在 [秘密名稱] 中,輸入儲存密碼的秘密名稱

  6. 在 [存放庫 URL] 中,輸入 Web 應用程式碼 GitHub 位置 (https://github.com/Azure-Samples/KeyVault-Rotation-SQLPassword-Csharp-WebApp.git)

  7. 選取 [檢閱 + 建立]。

  8. 選取 建立

開啟 Web 應用程式

移至已部署的應用程式 URL:

'https://akvrotation-app.azurewebsites.net/'

當應用程式在瀏覽器中開啟時,您會看到 [產生的密碼值] 以及值為 true 的 [資料庫已連線]

深入了解