117 lines
5.6 KiB
C#
117 lines
5.6 KiB
C#
using Azure.Security.KeyVault.Secrets;
|
|
using Microsoft.Data.SqlClient;
|
|
using System;
|
|
using Microsoft.Extensions.Logging;
|
|
using Azure.Identity;
|
|
using System.Security.Cryptography;
|
|
|
|
namespace Microsoft.KeyVault
|
|
{
|
|
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");
|
|
}
|
|
|
|
private static void CreateNewSecretVersion(SecretClient client, KeyVaultSecret secret, string newSecretValue)
|
|
{
|
|
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] : "60";
|
|
|
|
//add new secret version to key vault
|
|
var newSecret = new KeyVaultSecret(secret.Name, newSecretValue);
|
|
newSecret.Properties.Tags.Add(CredentialIdTag, credentialId);
|
|
newSecret.Properties.Tags.Add(ProviderAddressTag, providerAddress);
|
|
newSecret.Properties.Tags.Add(ValidityPeriodDaysTag, validityPeriodDays);
|
|
newSecret.Properties.ExpiresOn = DateTime.UtcNow.AddDays(Int32.Parse(validityPeriodDays));
|
|
client.SetSecret(newSecret);
|
|
}
|
|
|
|
private static void UpdateServicePassword(KeyVaultSecret secret, string newpassword)
|
|
{
|
|
var userId = secret.Properties.Tags.ContainsKey(CredentialIdTag) ? secret.Properties.Tags[CredentialIdTag] : "";
|
|
var datasource = secret.Properties.Tags.ContainsKey(ProviderAddressTag) ? secret.Properties.Tags[ProviderAddressTag] : "";
|
|
var dbResourceId = secret.Properties.Tags.ContainsKey(ProviderAddressTag) ? secret.Properties.Tags[ProviderAddressTag] : "";
|
|
|
|
var dbName = dbResourceId.Split('/')[8];
|
|
var password = secret.Value;
|
|
|
|
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
|
|
builder.DataSource = $"{dbName}.database.windows.net";
|
|
builder.UserID = userId;
|
|
builder.Password = password;
|
|
|
|
//Update password
|
|
using (SqlConnection connection = new SqlConnection(builder.ConnectionString))
|
|
{
|
|
connection.Open();
|
|
|
|
using (SqlCommand command = new SqlCommand($"ALTER LOGIN {userId} WITH Password='{newpassword}';", connection))
|
|
{
|
|
command.ExecuteNonQuery();
|
|
}
|
|
}
|
|
}
|
|
|
|
private static string CreateRandomPassword()
|
|
{
|
|
const int length = 60;
|
|
|
|
byte[] randomBytes = new byte[length];
|
|
RNGCryptoServiceProvider rngCrypt = new RNGCryptoServiceProvider();
|
|
rngCrypt.GetBytes(randomBytes);
|
|
return Convert.ToBase64String(randomBytes);
|
|
}
|
|
private static void CheckServiceConnection(KeyVaultSecret secret)
|
|
{
|
|
var userId = secret.Properties.Tags.ContainsKey(CredentialIdTag) ? secret.Properties.Tags[CredentialIdTag] : "";
|
|
var dbResourceId = secret.Properties.Tags.ContainsKey(ProviderAddressTag) ? secret.Properties.Tags[ProviderAddressTag] : "";
|
|
|
|
var dbName = dbResourceId.Split('/')[8];
|
|
var password = secret.Value;
|
|
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
|
|
builder.DataSource = $"{dbName}.database.windows.net";
|
|
builder.UserID = userId;
|
|
builder.Password = password;
|
|
using (SqlConnection connection = new SqlConnection(builder.ConnectionString))
|
|
{
|
|
connection.Open();
|
|
}
|
|
}
|
|
}
|
|
}
|