1 セットの認証資格情報を使用したリソースを対象にシークレットのローテーションを自動化する

Azure サービスに対する認証を行う最善の方法はマネージド ID を使用することですが、この方法を選択できないシナリオもあります。 このような場合は、アクセス キーまたはシークレットが使用されます。 アクセス キーやシークレットは定期的にローテーションする必要があります。

このチュートリアルでは、1 セットの認証資格情報を使用するデータベースとサービスを対象に、シークレットの定期的なローテーションを自動化する方法について説明します。 具体的には、このチュートリアルでは Azure Event Grid の通知によってトリガーされる関数を使用して、Azure Key Vault に格納されている SQL Server のパスワードをローテーションします。

ローテーション ソリューションの図

  1. シークレットの有効期限が切れる 30 日前に、Key Vault から "有効期限が近づいている" ことを示すイベントが Event Grid に発行されます。
  2. Event Grid がイベント サブスクリプションを確認し、HTTP POST を使用して、このイベントをサブスクライブしている関数アプリ エンドポイントを呼び出します。
  3. 関数アプリがシークレットの情報を受け取り、新たにランダムなパスワードを生成してから、新しいパスワードを使用して Key Vault にシークレットの新しいバージョンを作成します。
  4. 関数アプリが新しいパスワードを使用して SQL Server を更新します。

Note

ステップ 3 とステップ 4 の間にタイム ラグが生じることがあります。 その間、Key Vault 内のシークレットは、SQL Server に対して認証を行うことができません。 いずれかのステップで障害が発生した場合、Event Grid は 2 時間にわたって再試行します。

前提条件

既存の Key Vault と SQL Server がない場合は、次のデプロイ リンクを使用できます。

[Deploy to Azure]\(Azure にデプロイ\) というラベルが付けられたボタンが表示されている画像。

  1. [リソース グループ] で、 [新規作成] を選択します。 グループに名前を付けます。このチュートリアルでは、akvrotation を使用します。
  2. [SQL の管理者ログイン] で、SQL 管理者のログイン名を入力します。
  3. [Review + create](レビュー + 作成) を選択します。
  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 のパスワード ローテーション関数を作成してデプロイする

重要

次のテンプレートでは、Key Vault、SQL Server、Azure 関数が同じリソース グループに含まれている必要があります。

次に、システムマネージド ID を使用して関数アプリとその他の必須コンポーネントを作成し、SQL Server のパスワード ローテーション関数をデプロイします。

関数アプリには次のコンポーネントが必要です。

  • Azure App Service プラン
  • イベント トリガーと HTTP トリガーによる SQL パスワード ローテーション関数を備えた関数アプリ
  • 関数アプリのトリガーの管理に必要なストレージ アカウント
  • Key Vault 内のシークレットにアクセスする関数アプリ ID のアクセス ポリシー
  • SecretNearExpiry イベントの EventGrid イベント サブスクリプション
  1. Azure テンプレートのデプロイのリンクを選択します。

    [Deploy to Azure]\(Azure にデプロイ\) というラベルが付けられたボタンが表示されている画像。

  2. [リソース グループ] 一覧から [akvrotation] を選択します。

  3. [SQL Server 名] に、SQL Server の名前とローテーションするパスワードを入力します。

  4. [Key Vault 名] に、Key Vault の名前を入力します。

  5. [関数アプリ名] に関数アプリの名前を入力します。

  6. [シークレット名] に、パスワードが格納されるシークレットの名前を入力します。

  7. [リポジトリの URL] に、関数コードがある GitHub の場所 (https://github.com/Azure-Samples/KeyVault-Rotation-SQLPassword-Csharp.git) を入力します。

  8. [Review + create](レビュー + 作成) を選択します。

  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

関数アプリを作成し、マネージド ID を使用して Key Vault にアクセスする方法については、「Azure portal から関数アプリを作成する」、App Service と Azure Functions のマネージド ID を使用する方法、および Azure portal を使用した 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 のリソース ID、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]>[シークレット] に移動します。

Key Vault とシークレットにアクセスする方法を示すスクリーンショット。

sqlPassword シークレットを開き、元のバージョンとローテーション後のバージョンを確認します。

[シークレット] に移動する

Web アプリを作成する

SQL の資格情報を確認するために、Web アプリを作成します。 この Web アプリは、Key Vault からシークレットを取得し、SQL データベースの情報と資格情報をシークレットから抽出して、SQL Server への接続をテストします。

Web アプリには次のコンポーネントが必要です。

  • システム マネージド ID が付与されている Web アプリ
  • Web アプリのマネージド ID を使用して Key Vault 内のシークレットにアクセスするためのアクセス ポリシー
  1. Azure テンプレートのデプロイのリンクを選択します。

    [Deploy to Azure]\(Azure にデプロイ\) というラベルが付けられたボタンが表示されている画像。

  2. akvrotation リソース グループを選択します。

  3. [SQL Server 名] に、SQL Server の名前とローテーションするパスワードを入力します。

  4. [Key Vault 名] に、Key Vault の名前を入力します。

  5. [シークレット名] に、パスワードが格納されるシークレットの名前を入力します。

  6. [リポジトリの URL] に、Web アプリのコードがある GitHub の場所 (https://github.com/Azure-Samples/KeyVault-Rotation-SQLPassword-Csharp-WebApp.git) を入力します。

  7. [Review + create](レビュー + 作成) を選択します。

  8. [作成] を選択します

Web アプリを開く

デプロイされたアプリケーションの URL に移動します。

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

アプリケーションをブラウザーで開いている場合、生成されたシークレット値が表示され、データベース接続済みの値が true と表示されます。

詳細情報