← Back to Article List         
Securely Store Secrets

Securely Store Secrets

Published on 29 Sep 2026     13 min read Microservices
Authentication & Security

How Do You Securely Store Secrets Used by Microservices?

In microservices, secrets should not be hard-coded in source code or committed to configuration files. In production, store them in a dedicated secret-management system and, where possible, avoid secrets entirely by using workload/managed identities.

Examples of secrets include:

Database passwords
Client secrets
API keys
Redis passwords
Message-broker credentials
Signing/private keys
Third-party credentials
Certificates/private keys

A common Azure architecture is:

Microservice
     |
     | Managed Identity
     v
Azure Key Vault
     |
     +--> Database secret
     +--> API secret
     +--> Certificate

The key principle is:

Do not ask, "Where can I hide the secret?" First ask, "Can I eliminate the secret?"


1. Why Do We Need Secret Management?

Consider this configuration:

{
  "ConnectionStrings": {
    "DefaultConnection":
      "Server=prod-db;Database=Orders;User Id=admin;Password=P@ss123;"
  },
  "Payment": {
    "ClientSecret": "abc123"
  }
}

If this is committed to Git:

Developer
   |
   v
appsettings.json
   |
   v
Git Repository
   |
   +--> Database Password
   |
   +--> Client Secret

Anyone who gains access to the repository, its history, build artifacts, logs, or copied configuration may obtain those credentials.

Even deleting the secret in a later commit may not remove it from Git history.


2. What Should Never Be Hard-Coded?

Avoid this:

var password = "P@ssword123";

var apiKey = "ABC-123-SECRET";

var connectionString =
    "Server=prod;User Id=sa;Password=P@ssword123;";

Also avoid storing real production secrets directly in committed:

appsettings.json
appsettings.Production.json
source code
Dockerfile
docker-compose.yml
Git repository
README files
scripts

3. Recommended Strategy by Environment

A practical ASP.NET Core approach is:

Environment Recommended approach
Local development .NET User Secrets
CI/CD Protected pipeline secret/identity
Azure production Managed Identity + Azure Key Vault
Kubernetes Workload Identity + external secret manager
Other cloud Cloud-native secret manager
On-premises Enterprise vault/secret manager

Examples of secret managers include:

Azure Key Vault
AWS Secrets Manager
Google Cloud Secret Manager
HashiCorp Vault

4. Best Option — Avoid the Secret

Before:

Order Service
     |
     | SQL Username
     | SQL Password
     v
Azure SQL

The application has to protect:

SQL Password

A stronger Azure architecture can use:

Order Service
     |
     | Managed Identity
     v
Microsoft Entra ID
     |
     v
Azure SQL

Now there is no SQL password for the application to store.

The same principle can apply to supported Azure resources.

Avoid secret
    >
Store secret securely
    >
Hard-code secret

5. Azure Managed Identity

A Managed Identity gives an Azure-hosted workload an identity in Microsoft Entra ID without requiring you to manage the underlying credential yourself.

For example:

Azure App Service
Order Service
     |
     | Managed Identity
     v
Azure Key Vault

Your code does not need:

ClientSecret = "..."

Instead it requests credentials through Azure's identity infrastructure.


6. Azure Key Vault

Azure Key Vault is commonly used to securely manage:

  • secrets
  • keys
  • certificates

For example:

                  Azure Key Vault
                       |
          +------------+------------+
          |            |            |
          v            v            v
      DB Secret     API Key     Certificate
          ^
          |
    Managed Identity
          |
          |
     Order Service

The application authenticates to Key Vault using its identity, and Key Vault authorizes access.


7. ASP.NET Core + Azure Key Vault

For a .NET application, commonly used packages include:

dotnet add package Azure.Identity
dotnet add package Azure.Extensions.AspNetCore.Configuration.Secrets

appsettings.json

Store only non-secret configuration such as the vault location:

{
  "KeyVault": {
    "VaultUri": "https://my-company-vault.vault.azure.net/"
  }
}

No Key Vault password needs to be stored here when Managed Identity is used.


8. Program.cs

using Azure.Identity;

var builder = WebApplication.CreateBuilder(args);

var keyVaultUri =
    builder.Configuration["KeyVault:VaultUri"];

if (!string.IsNullOrWhiteSpace(keyVaultUri))
{
    builder.Configuration.AddAzureKeyVault(
        new Uri(keyVaultUri),
        new DefaultAzureCredential());
}

builder.Services.AddControllers();

var app = builder.Build();

app.MapControllers();

app.Run();

The important part is:

new DefaultAzureCredential()

9. What Is DefaultAzureCredential?

DefaultAzureCredential tries an ordered chain of supported Azure authentication mechanisms.

This makes the same application code convenient across development and Azure hosting.

Conceptually:

Local Development
      |
      | Developer identity /
      | supported local credential
      v
DefaultAzureCredential
      |
      v
Azure Key Vault

Production:

Azure App Service
      |
      | Managed Identity
      v
DefaultAzureCredential
      |
      v
Azure Key Vault

So the source code can remain essentially the same while the credential source changes with the environment.


10. Store a Secret in Key Vault

Suppose the application needs:

ConnectionStrings:OrderDatabase

Azure Key Vault configuration uses -- to represent configuration nesting in secret names.

For example, the Key Vault secret can be named:

ConnectionStrings--OrderDatabase

with a value such as:

Server=tcp:...;Database=Orders;...

ASP.NET Core configuration can expose it as:

var connectionString =
    builder.Configuration
        .GetConnectionString("OrderDatabase");

Conceptually:

Key Vault

ConnectionStrings--OrderDatabase
               |
               v
ASP.NET Core Configuration

ConnectionStrings:OrderDatabase

11. Using It with EF Core

builder.Services.AddDbContext<OrderDbContext>(
    options =>
    {
        options.UseSqlServer(
            builder.Configuration
                .GetConnectionString("OrderDatabase"));
    });

The application code doesn't need to know whether the value originated from:

appsettings
Environment Variable
User Secrets
Key Vault

It reads from ASP.NET Core's configuration system.


12. Full Simplified Example

Packages

dotnet add package Azure.Identity

dotnet add package Azure.Extensions.AspNetCore.Configuration.Secrets

dotnet add package Microsoft.EntityFrameworkCore.SqlServer

appsettings.json

{
  "KeyVault": {
    "VaultUri":
      "https://my-company-vault.vault.azure.net/"
  }
}

Program.cs

using Azure.Identity;
using Microsoft.EntityFrameworkCore;

var builder =
    WebApplication.CreateBuilder(args);


// ========================================
// Azure Key Vault
// ========================================

var vaultUri =
    builder.Configuration["KeyVault:VaultUri"];

if (!string.IsNullOrWhiteSpace(vaultUri))
{
    builder.Configuration.AddAzureKeyVault(
        new Uri(vaultUri),
        new DefaultAzureCredential());
}


// ========================================
// Database
// ========================================

builder.Services.AddDbContext<OrderDbContext>(
    options =>
    {
        options.UseSqlServer(
            builder.Configuration
                .GetConnectionString(
                    "OrderDatabase"));
    });


builder.Services.AddControllers();


var app = builder.Build();

app.UseHttpsRedirection();

app.MapControllers();

app.Run();

Architecture:

Order Service
      |
      | Managed Identity
      v
Azure Key Vault
      |
      | Authorized secret access
      v
Order Service
      |
      v
EF Core
      |
      v
SQL Server

13. Key Vault Authentication vs Authorization

These are separate.

Authentication

Key Vault asks:

Who are you?

Caller
  =
Order Service Managed Identity

Authorization

Then:

What are you allowed to access?

For example:

Order Service

Read Order DB secret       ✓
Read Payment secret        ✗
Delete secrets             ✗
Manage Key Vault           ✗

Use least privilege.

Don't give every microservice access to every secret.


14. Each Microservice Should Have Its Own Identity

Avoid:

Order Service ------+
                    |
Payment Service ----+----> Same Identity
                    |
Inventory Service --+

Prefer:

Order Service
    |
    +--> OrderService Identity


Payment Service
    |
    +--> PaymentService Identity


Inventory Service
    |
    +--> InventoryService Identity

Then Key Vault permissions can be specific:

Order Service
     |
     +--> Order DB secret


Payment Service
     |
     +--> Payment provider secret


Inventory Service
     |
     +--> Inventory DB secret

This limits the blast radius if one service is compromised.


15. Local Development — .NET User Secrets

For local development, ASP.NET Core provides User Secrets.

Initialize:

dotnet user-secrets init

Set a value:

dotnet user-secrets set \
"ConnectionStrings:OrderDatabase" \
"Server=localhost;Database=Orders;Trusted_Connection=True;"

Read normally:

var connectionString =
    builder.Configuration
        .GetConnectionString("OrderDatabase");

Your code does not need special secret-reading logic.


16. Where Are User Secrets Stored?

They are stored outside the project directory and are associated with the project's UserSecretsId.

Conceptually:

Project
   |
   | UserSecretsId
   v
User profile secret storage

Therefore they are not normally committed with the project.

Important

.NET User Secrets are intended primarily to keep development secrets out of source control.

They are not a production secret vault and should not be treated as one.


17. Environment Variables

Secrets can also be supplied through environment variables.

For example:

ConnectionStrings__OrderDatabase

maps to:

ConnectionStrings:OrderDatabase

Then:

builder.Configuration
    .GetConnectionString("OrderDatabase");

can retrieve it.

Environment variables are useful in containers and deployment systems, but they still require secure injection and operational controls.

They should not automatically be considered equivalent to a dedicated secret manager.


18. Kubernetes Secrets

A basic Kubernetes Secret might look like:

apiVersion: v1
kind: Secret
metadata:
  name: order-service-secret
type: Opaque
stringData:
  DatabasePassword: "..."

However, an important misconception is:

Base64 is not encryption.

Kubernetes secret data may be represented using Base64, but Base64 itself provides no confidentiality.

For stronger production architectures, combine Kubernetes with appropriate controls such as:

Encryption at rest
RBAC
Workload Identity
External secret manager
Secrets Store CSI Driver
Azure Key Vault / cloud secret manager

A stronger model is:

Kubernetes Pod
      |
      | Workload Identity
      v
Azure Key Vault

rather than permanently embedding many long-lived credentials in cluster manifests.


19. Docker Secrets

Avoid baking secrets into an image:

ENV DB_PASSWORD=P@ssword123

Anyone inspecting the image/build history may potentially expose sensitive data.

Instead:

Container Image
     |
     | No production secret
     v
Runtime
     |
     | Inject identity/secret
     v
Application

Secrets should normally be supplied at runtime through the deployment platform.


20. CI/CD Pipeline Secrets

Deployment pipelines also need credentials.

Avoid:

variables:
  DB_PASSWORD: "P@ssword123"

in source-controlled pipeline files.

Prefer:

CI/CD Pipeline
      |
      | Workload/Federated Identity
      v
Cloud Platform

or a protected pipeline secret store when an actual secret is unavoidable.

A modern direction is federated workload identity, which can eliminate long-lived cloud credentials from CI/CD systems.


21. Secret Rotation

Secrets should be rotatable.

Bad design:

Password created
     |
     v
Used for 7 years

Better:

Secret V1
   |
   v
Rotate
   |
   v
Secret V2

Rotation reduces the useful lifetime of a compromised credential.

Where possible, automate rotation and design applications so credentials can change without source-code changes.


22. Secret Versioning

Secret managers often support versions.

Conceptually:

OrderDbPassword

Version 1
   ↓
Version 2
   ↓
Version 3

This helps with:

  • controlled rotation
  • rollback
  • auditing
  • deployment transitions

23. Don't Log Secrets

A perfectly stored secret can still leak through logging.

Avoid:

_logger.LogInformation(
    "Connection string: {ConnectionString}",
    connectionString);

Also avoid logging:

Passwords
Client secrets
API keys
Access tokens
Refresh tokens
Private keys
Full sensitive connection strings

24. Don't Return Secrets in Exceptions

Avoid responses like:

{
  "error": "Could not connect using Password=P@ss123"
}

Production errors should not expose credentials or sensitive configuration.

Use centralized exception handling and safe error responses.


25. Separate Secrets by Environment

Avoid sharing:

Development
SIT
UAT
Production
       |
       v
Same database password

Prefer isolation:

Development
   |
   +--> Development secrets


SIT
   |
   +--> SIT secrets


UAT
   |
   +--> UAT secrets


Production
   |
   +--> Production secrets

A compromise in development should not expose production.


26. Separate Secrets by Microservice

Likewise:

Order Service
     |
     +--> Order DB credential


Payment Service
     |
     +--> Payment credential


Notification Service
     |
     +--> Email/SMS credential

Avoid one giant shared credential:

GlobalMicroservicePassword

used by every service.


27. Least Privilege

Suppose Order Service needs only:

OrderDatabase

Don't grant:

OrderDatabase       ✓

PaymentSecret       ✗
RedisAdminPassword  ✗
SigningPrivateKey   ✗
NotificationSecret  ✗

This is:

Principle of Least Privilege

Every service should receive only the access necessary to perform its job.


28. Secret Storage vs Encryption

These are related but different.

Encryption at rest

Protects stored data:

Secret
   |
   | Encrypt
   v
Encrypted Storage

Encryption in transit

Protects data while being transmitted:

Microservice
    |
    | HTTPS / TLS
    v
Secret Manager

A proper secret-management architecture normally needs both.


29. Secret Storage vs Configuration

Not everything belongs in Key Vault.

Normal configuration

PageSize = 20
RetryCount = 3
ServiceUrl
Feature settings
Logging level

These usually don't require secret storage.

Secrets

Password
Client Secret
Private API Key
Private Key
Sensitive connection credential

These do.

Don't turn your secret manager into a store for every ordinary configuration setting.


30. Production Architecture

A strong Azure microservices design could look like:

                     Microsoft Entra ID
                            |
                  Managed Identities
                            |
             +--------------+--------------+
             |              |              |
             v              v              v
        Order API      Payment API    Inventory API
             |              |              |
             +--------------+--------------+
                            |
                            v
                     Azure Key Vault
                            |
                 +----------+----------+
                 |          |          |
                 v          v          v
             Secrets       Keys    Certificates

Each service should have access only to what it needs.

Even better, supported resources can be accessed directly through identities:

Order Service
     |
     | Managed Identity
     v
Azure SQL

In that case:

No SQL Password
No secret retrieval
No password rotation

for the application.


31. Advantages

Secure secret management provides:

  • centralized secret storage
  • encryption
  • access control
  • auditing
  • easier rotation
  • environment separation
  • reduced source-code exposure
  • improved least privilege
  • easier credential revocation
  • better compliance posture

Managed/workload identities further reduce the number of credentials you need to manage.


32. Disadvantages

There are also operational costs:

  • additional infrastructure
  • IAM configuration
  • service dependency
  • permission management
  • rotation complexity
  • secret-manager cost in some environments
  • development environment differences

You also need to design for temporary secret-manager/network failures where runtime retrieval is involved.


33. Common Mistakes

Mistake 1

Store production password in appsettings.json

Mistake 2

Commit appsettings.Production.json containing secrets

Mistake 3

Hard-code API keys

Mistake 4

Use the same secret for every microservice

Mistake 5

Give every service access to the entire Key Vault

Mistake 6

Log connection strings or tokens

Mistake 7

Never rotate secrets

Mistake 8

Treat Base64 as encryption

Mistake 9

Use client secrets when Managed Identity could remove the secret entirely

34. Key Points

For interviews, remember:

  1. Never hard-code production secrets.
  2. Never commit production secrets to Git.
  3. Use .NET User Secrets for local development.
  4. Use a dedicated secret manager for production secrets.
  5. In Azure, Azure Key Vault is a common choice.
  6. Prefer Managed Identity where supported.
  7. For Kubernetes, prefer Workload Identity + external secret management where appropriate.
  8. Each microservice should have its own identity.
  9. Apply least privilege.
  10. Separate development/SIT/UAT/production credentials.
  11. Rotate secrets.
  12. Never log secrets.
  13. Protect secrets both at rest and in transit.
  14. Use auditing to track secret access.
  15. Prefer eliminating credentials over securely storing long-lived credentials.

35. Interview Questions and Answers

Q1. How do you securely store secrets in Microservices?

Answer:

I don't hard-code secrets or store production secrets in source-controlled configuration. For local development I use .NET User Secrets. In production I use a dedicated secret manager such as Azure Key Vault. On Azure, I prefer Managed Identity so the microservice can authenticate to Key Vault or supported resources without storing a client secret.


Q2. Should passwords be stored in appsettings.json?

Production passwords should not be committed in appsettings.json.

appsettings.json is appropriate for non-sensitive configuration.


Q3. Where do you store secrets during local development?

For ASP.NET Core:

.NET User Secrets

For example:

dotnet user-secrets set \
"Payment:ApiKey" \
"my-development-key"

Q4. Where do you store production secrets in Azure?

A common answer is:

Azure Key Vault

with the application accessing it through:

Managed Identity


Q5. What is Managed Identity?

Managed Identity provides an Azure workload with an identity in Microsoft Entra ID while Azure manages the underlying credentials.

This can eliminate the need to store:

Client ID + Client Secret

for many Azure-to-Azure authentication scenarios.


Q6. What is DefaultAzureCredential?

It is part of:

Azure.Identity

and provides a credential chain that allows applications to authenticate using appropriate available identities across development and Azure environments.


Q7. Should all Microservices use the same Key Vault permissions?

No.

Apply:

Least privilege

For example:

Order Service
   -> Order secrets only

Payment Service
   -> Payment secrets only

Q8. Is Kubernetes Secret encrypted because it uses Base64?

No.

Base64 is encoding, not encryption.

Additional Kubernetes and infrastructure security controls are required.


Q9. How often should secrets be rotated?

There is no universal interval for every credential. Rotation should follow the organization's security requirements and the credential/provider's capabilities.

More importantly, design the application so credentials can be rotated safely, and automate rotation where practical.


Q10. What is better than storing a secret securely?

Not having the secret.

For example:

Before:

Order Service
   |
SQL Username + Password
   |
   v
Azure SQL


Better where supported:

Order Service
   |
Managed Identity
   |
   v
Azure SQL

Short Interview Answer

I never hard-code or commit microservice secrets to source control. For local development, I use .NET User Secrets. In production, I use a dedicated secret manager such as Azure Key Vault, with each microservice having its own identity and least-privilege access. In Azure, I prefer Managed Identity so services can authenticate to Key Vault, databases, or other supported resources without storing long-lived client secrets. I also separate secrets by environment and service, rotate credentials, audit access, and make sure passwords, API keys, tokens, and connection strings are never written to logs.

The architecture to remember is:

                 Best
                  |
                  v
          Eliminate Secret
          Managed Identity
                  |
                  v
       If Secret Is Required
                  |
                  v
          Secret Manager
         Azure Key Vault
                  |
                  v
        Least-Privilege IAM
                  |
                  v
            Microservice


Local Development
       |
       v
.NET User Secrets


Never
  |
  +--> Hard-coded secret
  +--> Git repository
  +--> Production password in appsettings
  +--> Logs

The industry principle is: eliminate secrets where possible; otherwise centralize, restrict, rotate, audit, and never expose them in source code or logs.