Created
November 26, 2019 10:41
Backup & Restore Key Vault Secrets via Azure Functions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public async Task<List<BackupSecretResult>> BackupSecretsAsync(List<string> secrets) | |
{ | |
// Declares a KeyVaultClient instance. | |
var azureServiceTokenProvider = new AzureServiceTokenProvider(); | |
var kv = new KeyVaultClient( | |
new KeyVaultClient.AuthenticationCallback( | |
azureServiceTokenProvider.KeyVaultTokenCallback)); | |
// Performs the backup and add the result into the list. | |
var results = new List<BackupSecretResult>(); | |
var baseUri = "https://my-keyvault.vault.azure.net/"; | |
foreach (var name in secrets) | |
{ | |
var result = await kv.BackupSecretAsync(baseUri, name) | |
.ConfigureAwait(false); | |
results.Add(result); | |
} | |
// Returns the backup results. | |
return results; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[FunctionName(nameof(BackupSecrets))] | |
public async Task<IActionResult> BackupSecrets( | |
[HttpTrigger(AuthorizationLevel.Function, "post", Route = "secrets/backup")] HttpRequest req, | |
ILogger log) | |
{ | |
log.LogInformation("C# HTTP trigger function processed a request."); | |
// Gets the list of secrets. | |
var secrets = await this.GetSecretsAsync().ConfigureAwait(false); | |
// Performs the backup. | |
var results = await this.BackupSecretsAsync(secrets).ConfigureAwait(false); | |
// Uploads the backup data. | |
var uploaded = await this.UploadAsync(results).ConfigureAwait(false); | |
return new OkObjectResult(results); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public async Task<List<BackupSecretResult>> DownloadAsync(string timestamp) | |
{ | |
// Declares the BlobClient instance. | |
var connectionString = Environment.GetEnvironmentVariable("AzureWebJobsStorage"); | |
var client = CloudStorageAccount.Parse(connectionString) | |
.CreateCloudBlobClient(); | |
// Gets the Blob container. | |
var containerName = "backups"; | |
var container = client.GetContainerReference(containerName); | |
// Gets the Blob. | |
var blobName = $"{timestamp}.json"; | |
var blob = container.GetBlockBlobReference(blobName); | |
// Downloads the Blob content. | |
var downloaded = await blob.DownloadTextAsync().ConfigureAwait(false); | |
// Deserialises the contents. | |
var results = JsonConvert.DeserializeObject<List<BackupSecretResult>>(downloaded); | |
// Returns the result. | |
return results; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public async Task<List<string>> GetSecretsAsync() | |
{ | |
// Declares a KeyVaultClient instance. | |
var azureServiceTokenProvider = new AzureServiceTokenProvider(); | |
var kv = new KeyVaultClient( | |
new KeyVaultClient.AuthenticationCallback( | |
azureServiceTokenProvider.KeyVaultTokenCallback)); | |
// Gets the list of secrets. | |
var baseUri = "https://myu-keyvault.vault.azure.net/"; | |
var secrets = await kv.GetSecretsAsync(baseUri) | |
.ConfigureAwait(false); | |
// Returns the list of secret names. | |
return secrets.Select(p => p.Identifier.Name).ToList(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public async Task<List<string>> RestoreSecretsAsync(string key, List<BackupSecretResult> secrets) | |
{ | |
// Declares a KeyVaultClient instance. | |
var azureServiceTokenProvider = new AzureServiceTokenProvider(); | |
var kv = new KeyVaultClient( | |
new KeyVaultClient.AuthenticationCallback( | |
azureServiceTokenProvider.KeyVaultTokenCallback)); | |
// Performs the restore and add the result into the list. | |
var results = new List<SecretBundle>(); | |
var baseUri = "https://my-keyvault.vault.azure.net/"; | |
foreach (var secret in secrets) | |
{ | |
var result = await kv.RestoreSecretAsync(baseUri, secret.Value) | |
.ConfigureAwait(false); | |
results.Add(result); | |
} | |
// Returns the list of secret names. | |
return results.Select(p => p.SecretIdentifier.Name).ToList(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[FunctionName(nameof(RestoreSecrets))] | |
public async Task<IActionResult> RestoreSecrets( | |
[HttpTrigger(AuthorizationLevel.Function, "post", Route = "secrets/restore/{timestamp}")] HttpRequest req, | |
string timestamp, | |
ILogger log) | |
{ | |
log.LogInformation("C# HTTP trigger function processed a request."); | |
// Downloads the backup of the given timestamp. | |
var secrets = await this._blob.DownloadAsync(timestamp).ConfigureAwait(false); | |
// Performs the restore from the backup. | |
var results = await this._secret.RestoreSecretsAsync("restore", secrets).ConfigureAwait(false); | |
return new OkObjectResult(results); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public async Task<bool> UploadAsync(List<BackupSecretResult> results) | |
{ | |
// Declares the BlobClient instance. | |
var connectionString = Environment.GetEnvironmentVariable("AzureWebJobsStorage"); | |
var blob = CloudStorageAccount.Parse(connectionString) | |
.CreateCloudBlobClient(); | |
// Gets the Blob container. | |
var containerName = "backups"; | |
var container = blob.GetContainerReference(containerName); | |
await container.CreateIfNotExistsAsync().ConfigureAwait(false); | |
// Gets the Blob. | |
var blobName = $"{DateTimeOffset.UtcNow.ToString("yyyyMMdd")}.json"; | |
var blob = container.GetBlockBlobReference(blobName); | |
// Serialises the backup result. | |
var serialised = JsonConvert.SerializeObject(results); | |
// Uploads the backup result to Blob Storage. | |
await blob.UploadTextAsync(serialised).ConfigureAwait(false); | |
// Returns true, if everything is OK. | |
return true; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment