1 セットの認証資格情報を使用したリソースを対象にシークレットのローテーションを自動化する
Azure サービスに対する認証を行う最善の方法はマネージド ID を使用することですが、この方法を選択できないシナリオもあります。 このような場合は、アクセス キーまたはシークレットが使用されます。 アクセス キーやシークレットは定期的にローテーションする必要があります。
このチュートリアルでは、1 セットの認証資格情報を使用するデータベースとサービスを対象に、シークレットの定期的なローテーションを自動化する方法について説明します。 具体的には、このチュートリアルでは Azure Event Grid の通知によってトリガーされる関数を使用して、Azure Key Vault に格納されている SQL Server のパスワードをローテーションします。
- シークレットの有効期限が切れる 30 日前に、Key Vault から "有効期限が近づいている" ことを示すイベントが Event Grid に発行されます。
- Event Grid がイベント サブスクリプションを確認し、HTTP POST を使用して、このイベントをサブスクライブしている関数アプリ エンドポイントを呼び出します。
- 関数アプリがシークレットの情報を受け取り、新たにランダムなパスワードを生成してから、新しいパスワードを使用して Key Vault にシークレットの新しいバージョンを作成します。
- 関数アプリが新しいパスワードを使用して SQL Server を更新します。
Note
ステップ 3 とステップ 4 の間にタイム ラグが生じることがあります。 その間、Key Vault 内のシークレットは、SQL Server に対して認証を行うことができません。 いずれかのステップで障害が発生した場合、Event Grid は 2 時間にわたって再試行します。
前提条件
- Azure サブスクリプション - 無料アカウントを作成します。
- Azure Key Vault
- SQL Server
既存の Key Vault と SQL Server がない場合は、次のデプロイ リンクを使用できます。
- [リソース グループ] で、 [新規作成] を選択します。 グループに名前を付けます。このチュートリアルでは、akvrotation を使用します。
- [SQL の管理者ログイン] で、SQL 管理者のログイン名を入力します。
- [Review + create](レビュー + 作成) を選択します。
- [作成]
これで、キー コンテナーと 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 イベント サブスクリプション
Azure テンプレートのデプロイのリンクを選択します。
[リソース グループ] 一覧から [akvrotation] を選択します。
[SQL Server 名] に、SQL Server の名前とローテーションするパスワードを入力します。
[Key Vault 名] に、Key Vault の名前を入力します。
[関数アプリ名] に関数アプリの名前を入力します。
[シークレット名] に、パスワードが格納されるシークレットの名前を入力します。
[リポジトリの URL] に、関数コードがある GitHub の場所 (https://github.com/Azure-Samples/KeyVault-Rotation-SQLPassword-Csharp.git) を入力します。
[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
関数アプリを作成し、マネージド 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]>[シークレット] に移動します。
sqlPassword シークレットを開き、元のバージョンとローテーション後のバージョンを確認します。
Web アプリを作成する
SQL の資格情報を確認するために、Web アプリを作成します。 この Web アプリは、Key Vault からシークレットを取得し、SQL データベースの情報と資格情報をシークレットから抽出して、SQL Server への接続をテストします。
Web アプリには次のコンポーネントが必要です。
- システム マネージド ID が付与されている Web アプリ
- Web アプリのマネージド ID を使用して Key Vault 内のシークレットにアクセスするためのアクセス ポリシー
Azure テンプレートのデプロイのリンクを選択します。
akvrotation リソース グループを選択します。
[SQL Server 名] に、SQL Server の名前とローテーションするパスワードを入力します。
[Key Vault 名] に、Key Vault の名前を入力します。
[シークレット名] に、パスワードが格納されるシークレットの名前を入力します。
[リポジトリの URL] に、Web アプリのコードがある GitHub の場所 (https://github.com/Azure-Samples/KeyVault-Rotation-SQLPassword-Csharp-WebApp.git) を入力します。
[Review + create](レビュー + 作成) を選択します。
[作成] を選択します
Web アプリを開く
デプロイされたアプリケーションの URL に移動します。
'https://akvrotation-app.azurewebsites.net/'
アプリケーションをブラウザーで開いている場合、生成されたシークレット値が表示され、データベース接続済みの値が true と表示されます。