← Back to list

Building Automated Secret Rotation Using Azure Key Vault and .NET

Securely Manage and Automatically Rotate Secrets Using Azure Key Vault Service

Shivam Lad in Simform Engineering · 2026-05-15 06:00 · 158 claps · 11.1 min read
#azure #azure-key-vault #azure-functions #key-rotation #dotnet
Open on Medium ↗
Wiki topics: ☁️ · DevOps & Cloud

Building Automated Secret Rotation Using Azure Key Vault and .NET

Securely Manage and Automatically Rotate Secrets Using Azure Key Vault Service

Introduction

Imagine your application goes down at 2 AM because a database password expired. Suddenly, APIs start failing, background jobs stop processing, and users begin experiencing errors all without any recent code changes.

This is a common challenge in cloud-based systems where sensitive credentials like database passwords, API keys, and service secrets have expiration policies and must be rotated regularly.

Manually updating these secrets across multiple services is not only time-consuming but also risky. A missed update can lead to unexpected downtime and impact critical business operations.

This is where automated secret rotation becomes essential.

In this article, we will build a fully automated secret rotation system using:

  • Azure Key Vault
  • Azure Event Grid
  • Azure Functions
  • .NET Application (using App Registration)

This approach ensures that secrets are rotated proactively before they expire, while applications continue to function seamlessly by always retrieving the latest version from Azure Key Vault.

This guide is designed for:

.NET developers working with Azure who want to implement secure and automated secret management in real-world applications.

Prerequisites

Before starting, ensure you have the following:

  • Azure Subscription
  • .NET 10 SDK installed
  • Azure CLI installed
  • Basic understanding of Azure Functions

Architecture Overview

The diagram above illustrates how automated secret rotation works using Azure services in a real-world scenario (such as Azure SQL Database password rotation):

  1. Secret Near Expiry Event Azure Key Vault continuously monitors the expiry of stored secrets. When a secret (e.g., an Azure SQL Database password) approaches its expiration date, it emits a Secret Near Expiry event, typically around 30 days before the actual expiry.
  2. Event Routing via Event Grid This event is automatically published to Azure Event Grid, which acts as a central event routing service.
  3. Triggering Azure Function The Azure Function App is subscribed to this event and gets triggered as soon as the event is received.
  4. Password Regeneration The function securely generates a new strong password for the Azure SQL Database.
  5. Updating Database and Key Vault The function updates the Azure SQL Database with the newly generated password and then stores it in Azure Key Vault as a new version of the secret, ensuring both systems remain in sync with proper versioning and traceability.
  6. Seamless Application Access Applications that rely on this secret always fetch the latest version dynamically from Key Vault, ensuring uninterrupted access without any manual updates.

Hands-On Implementation: Building Automated Secret Rotation in Azure

Step-by-Step Implementation Guide

In this section, we will configure Azure services and build an automated system that rotates secrets stored in Azure Key Vault.

Step 1: Create a Resource Group

A Resource Group is a logical container used to organize and manage related Azure resources.

In this demo, all resources such as Key Vault, Function App, and Storage Account will be created inside a single resource group.

az group create \
 - name secret-rotation-demo \
 - location centralindia

Step 2: Create an Azure Key Vault

Azure Key Vault is used to securely store secrets such as passwords, API keys, and certificates.

az keyvault create \
--name kv-secret-rotation-demo \
--resource-group secret-rotation-demo \
--location centralindia \
--sku standard

This command creates a Key Vault named kv-secret-rotation-demo where our application secrets will be stored and managed.

Step 3: Retrieve the User Object ID

Azure uses Object IDs to identify users or service principals when assigning permissions.

Run the following command to get your Azure user object ID:

az ad signed-in-user show --query id -o tsv

Copy the returned value as it will be used to grant permissions to access the Key Vault.

Step 4: Grant Key Vault Access Permissions

To manage secrets in Key Vault, the user must have the appropriate role assigned.

az role assignment create \
--role "Key Vault Secrets Officer" \
--assignee <YOUR_OBJECT_ID> \
--scope /subscriptions/<SUB_ID>/resourceGroups/secret-rotation-demo/providers/Microsoft.KeyVault/vaults/kv-secret-rotation-demo

This command assigns the Key Vault Secrets Officer role, allowing the user to create and manage secrets.

Step 5: Store a Secret with an Expiration Date

Next, we create a secret in Key Vault that represents a database password. We also configure an expiration date so the system can detect when the secret is about to expire.

az keyvault secret set \
--vault-name kv-secret-rotation-demo \
--name DbPassword \
--value "Password@123" \
--expires 2026-03-08T00:00:00Z

This secret will later be automatically rotated by the Azure Function.

Step 6: Create a Storage Account

Azure Functions require a storage account for managing logs, triggers, and runtime state.

az storage account create \
--name kvrotationstorage123 \
--resource-group secret-rotation-demo \
--location centralindia \
--sku Standard_LRS

Step 7: Build the Solution — Function App and .NET Client

In this step, we will create a complete solution that includes:

  • An Azure Function App to handle secret rotation
  • A .NET Client Application to retrieve the latest secret

This separation ensures a clean and scalable architecture where rotation logic and consumption logic are independent.

Solution Architecture

The solution is structured into two main projects to ensure clear separation of concerns between secret rotation and application consumption.

SecretRotationFunction (Solution)
│
├── SecretRotationFunction/        # Azure Function App (Core Rotation Logic)
│   ├── SecretRotationFunction.cs # Event Grid + HTTP trigger functions
│   ├── Program.cs                # Function app startup configuration
│   ├── host.json                 # Function runtime configuration
│   ├── local.settings.json       # Local environment variables
│   └── Dependencies
│
├── KeyVaultSecretReader/         # .NET Client Application
│   ├── Program.cs                # Fetches latest secret from Key Vault
│   ├── appsettings.json          # Configuration (Client ID, Secret, KV URL)
│   └── Dependencies
│
└── Solution Files

Implement the Secret Rotation Function

In this section, we will implement the core logic responsible for handling secret rotation. To make the solution more practical and easy to understand, we will use two functions:

  1. Event Grid Trigger Function → Handles actual secret rotation
  2. HTTP Trigger Function → Helps simulate and test the flow

Responsibilities:

  • Receive event from Event Grid
  • Identify which secret is expiring
  • Generate a new secure password
  • Update Azure SQL Database password
  • Store new password in Key Vault

Function Implementation (SecretRotationFunction.cs)

using Azure.Identity;
using Azure.Messaging.EventGrid;
using Azure.Security.KeyVault.Secrets;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;
using System.Net;

namespace SecretRotationFunction
{
    public class SecretRotationFunction
    {
        private readonly ILogger<SecretRotationFunction> _logger;

        public SecretRotationFunction(ILogger<SecretRotationFunction> logger)
        {
            _logger = logger;
        }

        [Function(nameof(SecretRotationFunction))]
        public async Task Run([EventGridTrigger] EventGridEvent eventGridEvent)
        {
            await RotateSecretAsync(eventGridEvent.Id, eventGridEvent.Subject);
        }

        [Function(nameof(TestRotateSecretAsync))]
        public async Task<HttpResponseData> TestRotateSecretAsync(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req)
        {
            await RotateSecretAsync(eventId: null, eventSubject: null);

            var response = req.CreateResponse(HttpStatusCode.OK);
            response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
            await response.WriteStringAsync("Secret rotation test completed.");
            return response;
        }

        private async Task RotateSecretAsync(string? eventId, string? eventSubject)
        {
            _logger.LogInformation("Secret rotation started. EventId={EventId}, Subject={Subject}", eventId, eventSubject);

            try
            {
                var keyVaultUri = Environment.GetEnvironmentVariable("KEY_VAULT_URI");

                if (string.IsNullOrWhiteSpace(keyVaultUri))
                    throw new InvalidOperationException("Missing required app setting 'KEY_VAULT_URI'.");

                var client = new SecretClient(new Uri(keyVaultUri), new DefaultAzureCredential());

                string newPassword = $"Password@{Random.Shared.Next(1000, 9999)}";
                var expiresOn = DateTimeOffset.UtcNow.AddDays(50);

                var secret = new KeyVaultSecret("DbPassword", newPassword)
                {
                    Properties = { ExpiresOn = expiresOn }
                };

                await client.SetSecretAsync(secret);

                // Uncomment to also update the database user password:
                // UpdateDatabaseUserPassword(newPassword);

                _logger.LogInformation("Secret rotated successfully. Expires={ExpiresOn:O}", expiresOn);
            }
            catch (Azure.RequestFailedException ex)
            {
                _logger.LogError(ex, "Key Vault request failed. Status={Status}", ex.Status);
                throw;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Secret rotation failed unexpectedly.");
                throw;
            }
        }
    }
}

Configuration (local.settings.json)

{
    "IsEncrypted": false,
    "Values": {
        "AzureWebJobsStorage": "UseDevelopmentStorage=true",
        "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
        "KEY_VAULT_URI": "<KEY_VAULT_URL>"
    }
}

.NET Client Application — Fetch Latest Secret

To demonstrate real-world usage, we create a simple .NET application that retrieves the latest secret from Azure Key Vault.

Implementation

using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Configuration;

const int NearExpiryLeadTimeDays = 30;

IConfiguration configuration = new ConfigurationBuilder()
    .SetBasePath(AppContext.BaseDirectory)
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: false)
    .Build();

// Key Vault config
string tenantId     = GetRequired(configuration, "KeyVault:TenantId");
string clientId     = GetRequired(configuration, "KeyVault:ClientId");
string clientSecret = GetRequired(configuration, "KeyVault:ClientSecret");
string keyVaultUrl  = GetRequired(configuration, "KeyVault:Url");
string secretName   = GetRequired(configuration, "KeyVault:SecretName");

// SQL config
string sqlServer   = GetRequired(configuration, "Sql:Server");
string sqlDatabase = GetRequired(configuration, "Sql:Database");
string sqlUserName = GetRequired(configuration, "Sql:UserName");

var credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
var client = new SecretClient(new Uri(keyVaultUrl), credential);

KeyVaultSecret secret = await client.GetSecretAsync(secretName);
SecretProperties props = secret.Properties;

Console.WriteLine($"Secret name   : {secretName}");
Console.WriteLine($"Version       : {props.Version}");
Console.WriteLine($"Last rotated  : {Format(props.UpdatedOn ?? props.CreatedOn)}");
Console.WriteLine($"Expires on    : {Format(props.ExpiresOn)}");
Console.WriteLine($"Near-expiry   : {Format(props.ExpiresOn?.AddDays(-NearExpiryLeadTimeDays))} ({NearExpiryLeadTimeDays} days before expiry)");

var connectionString = new SqlConnectionStringBuilder
{
    DataSource = sqlServer,
    InitialCatalog = sqlDatabase,
    UserID = sqlUserName,
    Password = secret.Value,
    Encrypt = true,
    TrustServerCertificate = false,
    IntegratedSecurity = false,
    PersistSecurityInfo = false
}.ConnectionString;

// Uncomment to validate credentials against the database:
// await using var connection = new SqlConnection(connectionString);
// await connection.OpenAsync();

Console.WriteLine($"\nDB connection string built successfully: {connectionString}");

static string GetRequired(IConfiguration config, string key)
{
    string? value = config[key];
    return !string.IsNullOrWhiteSpace(value)
        ? value
        : throw new InvalidOperationException($"Missing required configuration value: '{key}'");
}

static string Format(DateTimeOffset? value) => value?.ToString("u") ?? "N/A";

Configuration (appsettings.json)

{
  "KeyVault": {
    "TenantId": "<TENANT_ID>",
    "ClientId": "<CLIENT_ID>",
    "ClientSecret": "<CLIENT_SECRET>",
    "Url": "<KEY_VAULT_URL>",
    "SecretName": "<SECRET_NAME>"
  },
  "Sql": {
    "Server": "your-server-name.database.windows.net",
    "Database": "your-database-name",
    "UserName": "your-sql-login"
  }
}

Step 8: Enable Managed Identity for the Function

Managed Identity allows the function to access Azure services without storing credentials.

az functionapp identity assign \
--name kv-rotation-function-demo \
--resource-group secret-rotation-demo

Save the returned:

principalId

Step 9: Grant Function Access to Key Vault

The function needs permission to update secrets in Key Vault.

az role assignment create \
--role "Key Vault Secrets Officer" \
--assignee <principalId> \
--scope /subscriptions/<SUB_ID>/resourceGroups/secret-rotation-demo/providers/Microsoft.KeyVault/vaults/kv-secret-rotation-demo

Step 10: Create an App Registration

Applications accessing Azure resources securely use Azure App Registration.

az ad app create --display-name keyvault-demo-app

Save the returned appId as:

CLIENT_ID

This application identity will be used by our .NET application to retrieve secrets from Key Vault.

Step 11: Create a Service Principal

A Service Principal represents the application identity within Azure Active Directory.

az ad sp create --id <CLIENT_ID>

This allows the application to authenticate with Azure services.

Step 12: Generate a Client Secret

To authenticate the application securely, we generate a client secret.

az ad app credential reset \
--id <CLIENT_ID> \
--append

Save the following values from the output:

CLIENT_SECRET
TENANT_ID

These credentials will be used by the .NET application to authenticate with Azure.

Step 13: Grant Application Access to Key Vault

The application must be granted permission to read secrets from Key Vault.

az role assignment create \
--role "Key Vault Secrets User" \
--assignee <CLIENT_ID> \
--scope /subscriptions/<SUB_ID>/resourceGroups/secret-rotation-demo/providers/Microsoft.KeyVault/vaults/kv-secret-rotation-demo

This role allows the application to retrieve secrets securely.

Step 14: Create and deploy Azure Function App

In this step, we will create and deploy the Azure Function App that handles automated secret rotation.

Step 1: Create an Azure Function App in Azure

The Azure Function will be responsible for rotating the secret automatically when it is about to expire. First, create the Function App using the Azure CLI.

az functionapp create \
--name kv-rotation-function-demo \
--resource-group secret-rotation-demo \
--storage-account kvrotationstorage123 \
--consumption-plan-location centralindia \
--runtime dotnet \
--functions-version 4

Step 2: Deploy Azure Function

Once the Function App is created, we need to deploy our local function project.

Where to Run These Commands?

All the following commands should be executed from your local development machine (your laptop/desktop) using:

  • Command Prompt / PowerShell (Windows)
  • Terminal (macOS/Linux)
  • VS Code Integrated Terminal

Make sure you have:

  • Azure CLI installed
  • Azure Functions Core Tools installed
  • Logged into your Azure account

Step 2.1: Login to Azure

az login

Step 2.2: Navigate to Function Project

Run this from the folder where your function code exists:

cd SecretRotationFunction

Step 2.3: Publish Function to Existing Function App

func azure functionapp publish kv-rotation-function-demo

This command deploys your local function project to the already created Azure Function App using Zip Deployment under the hood.

Step 2.4: Configure Application Settings

Set required environment variables (instead of hardcoding values):

az functionapp config appsettings set \
  --name kv-rotation-function-demo \
  --resource-group secret-rotation-demo \
  --settings KEY_VAULT_URI=<YOUR_KEY_VAULT_URI>/

Step 2.5: Verify Deployment

Stream logs to confirm everything is working:

func azure functionapp logstream kv-rotation-function-demo

Step 15: Configure Event Grid Trigger for Secret Expiry

To automate secret rotation, we need a mechanism that detects when a secret is about to expire and triggers the Azure Function responsible for generating a new secret.

Azure Key Vault emits events such as **Microsoft.KeyVault.SecretNearExpiry, which can be captured using Azure Event Grid**. When this event occurs, Event Grid will trigger the Azure Function that performs the rotation.

First, retrieve the Resource ID of the Key Vault. This ID is required when creating the Event Grid subscription.

az keyvault show \
--name kv-secret-rotation-demo \
--query id -o tsv

Save the returned value as:

VAULT_ID

Next, create an Event Grid subscription that listens for the SecretNearExpiry event and routes it to the Azure Function.

az eventgrid event-subscription create \
--name kv-secret-expiry-event \
--source-resource-id <VAULT_ID> \
--endpoint-type azurefunction \
--endpoint /subscriptions/<SUB_ID>/resourceGroups/secret-rotation-demo/providers/Microsoft.Web/sites/kv-rotation-function-demo/functions/SecretRotationFunction \
--included-event-types Microsoft.KeyVault.SecretNearExpiry

This enables the automatic rotation workflow.

Note: The Microsoft.KeyVault.SecretNearExpiry event is emitted 30 days before the secret’s expiration date, not at the exact moment of expiry. This behaviour allows systems to rotate credentials proactively and avoid service disruptions caused by expired secrets.

When testing secret rotation in a demo environment, make sure the secret’s expiration date is more than 30 days in the future so that the event can be triggered properly.

Step 16: Verify Secret Rotation

To verify that the secret has been rotated, run:

az keyvault secret show \
--vault-name kv-secret-rotation-demo \
--name DbPassword \
--query value -o tsv

If the function runs successfully, a new version of the secret will be created with a new password.

Best Practices for Implementing Automatic Secret Rotation

When implementing automated secret rotation with Azure Key Vault, it is important to follow certain best practices to ensure security, reliability, and smooth application operations.

Use Secret Versioning

Always design applications to retrieve the latest version of a secret from Azure Key Vault. Versioning ensures that when a secret is rotated, applications automatically start using the updated value without requiring configuration changes.

Apply Proper Access Controls

Use Azure Role-Based Access Control (RBAC) to restrict who can:

  • Manage secrets
  • Configure rotation policies
  • Access sensitive data

Limiting permissions reduces the risk of unauthorized access or accidental changes.

Monitor Rotation Events

Enable monitoring and alerts using Azure Monitor and Application Insights to track rotation activities. This helps in:

  • Detecting failed rotations
  • Identifying unexpected behavior
  • Ensuring the rotation process is functioning correctly

Test Rotation Workflows

Before deploying to production, thoroughly test the rotation process. Ensure that:

  • Applications continue to work after secret updates
  • No downtime occurs during rotation
  • All dependent services can handle updated credentials

Define Appropriate Rotation Intervals

Choose rotation frequencies that balance security requirements and operational stability. Rotating secrets too frequently may introduce unnecessary complexity, while rotating too infrequently may increase security risks.

Prepare Fallback Procedures

Document a manual rotation process in case automation fails. Having a clear fallback plan helps quickly restore access to systems during unexpected situations.

Enable Soft Delete and Purge Protection

Enable the following critical security features in Azure Key Vault:

  • Soft Delete: Prevents accidental deletion of secrets by allowing recovery within a retention period
  • Purge Protection: Prevents permanent deletion of secrets until the retention period expires

These features act as a safety net against accidental or malicious data loss and are highly recommended for production environments.

Follow Key Vault Security Recommendations

  • Use Managed Identity instead of storing credentials in code
  • Restrict access using Private Endpoints / Firewall rules
  • Enable diagnostic logging for auditing
  • Regularly review access policies and permissions

Real-World Scenarios for Secret Rotation

Automated secret rotation is useful in many real-world scenarios:

  • Database Password Rotation: Automatically update database credentials without application downtime.
  • API Key Rotation: Ensure external API credentials are rotated periodically.
  • Storage Account Key Rotation: Automatically rotate storage account access keys.
  • Enterprise Security Compliance: Many organizations require periodic credential rotation to comply with security standards.

Source Code

The complete implementation used in this article is available on GitHub.[GitHub Repo Link]

The repository includes:

  • Azure Function App for automatic secret rotation
  • .NET client application for reading secrets from Azure Key Vault

Conclusion

Managing secrets securely is an essential part of building modern cloud applications. Azure provides powerful tools like Azure Key Vault, Event Grid, and Azure Functions to automate secret management and rotation.

By implementing automated secret rotation:

  • Secrets remain secure and up-to-date
  • Applications always retrieve the latest credentials
  • Manual operational effort is minimized

This architecture helps organizations maintain strong security practices while ensuring seamless application functionality.

As a Microsoft Solutions Partner and Azure Expert MSP, Simform helps enterprises modernize and secure Azure environments through cloud-native engineering, reusable accelerators, and structured implementation frameworks built for scalable digital products.

References & Further Reading


메타데이터
post_id
01e0701f0a2e
slug
building-automated-secret-rotation-using-azure-key-vault-and-net-01e0701f0a2e
url
https://medium.com/simform-engineering/building-automated-secret-rotation-using-azure-key-vault-and-net-01e0701f0a2e
canonical_url
https://medium.com/simform-engineering/building-automated-secret-rotation-using-azure-key-vault-and-net-01e0701f0a2e
author_url
https://medium.com/@shivam.lad_21043
status
ok
fetched_at
2026-06-14 11:28:49