Skip to content

Instantly share code, notes, and snippets.

@justinyoo
Created February 21, 2021 14:56
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save justinyoo/948385359cc739a48ad5afdf07db932e to your computer and use it in GitHub Desktop.
Save justinyoo/948385359cc739a48ad5afdf07db932e to your computer and use it in GitHub Desktop.
Event-Driven KeyVault Secrets Rotation Management
func new --name DisableSecretHttpTrigger --template HttpTrigger --language C#
public static class DisableSecretHttpTrigger
{
[FunctionName("DisableSecretHttpTrigger")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "POST", Route = "secrets/{name}/disable/{count:int?}")] HttpRequest req,
string name, int? count,
ILogger log)
{
// Get the KeyVault URI
var uri = Environment.GetEnvironmentVariable("KeyVault__Uri");
// Get the tenant ID where the KeyVault lives
var tenantId = Environment.GetEnvironmentVariable("KeyVault__TenantId");
// Set the tenant ID, in case your account has multiple tenants logged in
var options = new DefaultAzureCredentialOptions()
{
SharedTokenCacheTenantId = tenantId,
VisualStudioTenantId = tenantId,
VisualStudioCodeTenantId = tenantId,
};
var client = new SecretClient(new Uri(uri), new DefaultAzureCredential(options));
// Get the all versions of the given secret
// Filter only enabled versions
// Sort by the created date in a reverse order
var versions = await client.GetPropertiesOfSecretVersionsAsync(name)
.WhereAwait(p => new ValueTask<bool>(p.Enabled.GetValueOrDefault() == true))
.OrderByDescendingAwait(p => new ValueTask<DateTimeOffset>(p.CreatedOn.GetValueOrDefault()))
.ToListAsync()
.ConfigureAwait(false);
// Do nothing if there is no version enabled
if (!versions.Any())
{
return new AcceptedResult();
}
if (!count.HasValue)
{
count = 2;
}
// Do nothing if there is only given number of versions enabled
if (versions.Count < count.Value + 1)
{
return new AcceptedResult();
}
// Disable all versions except the first (latest) given number of versions
var candidates = versions.Skip(count.Value).ToList();
var results = new List<SecretProperties>();
results.AddRange(versions.Take(count.Value));
foreach (var candidate in candidates)
{
candidate.Enabled = false;
var response = await client.UpdateSecretPropertiesAsync(candidate).ConfigureAwait(false);
results.Add(response.Value);
}
var res = new ContentResult()
{
Content = JsonConvert.SerializeObject(results, Formatting.Indented),
ContentType = "application/json",
StatusCode = (int)HttpStatusCode.OK,
};
return res;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment