Modern applications depend on numerous secrets, including database connection strings, API keys, OAuth client credentials, encryption keys, certificates, and cloud access tokens. Managing these secrets securely is essential because hardcoded credentials, exposed environment variables, or improperly configured CI/CD pipelines can become entry points for attackers.
In cloud-native environments, secrets often move through multiple systems—from development machines to CI/CD pipelines, Kubernetes clusters, and production applications. A secure secrets management strategy ensures that sensitive information remains protected throughout the entire software delivery lifecycle.
In this article, you'll learn how to build an enterprise secrets management architecture using Azure Key Vault, Kubernetes, and GitHub Actions, along with practical best practices for securing modern .NET applications.
Why Secrets Management Matters
Applications commonly require access to:
Database credentials
API keys
OAuth client secrets
Storage account keys
TLS certificates
Message broker credentials
Encryption keys
Storing these values directly in source code or configuration files creates unnecessary security risks.
Typical Enterprise Architecture
A secure deployment might look like this:
Developer
|
GitHub Repository
|
GitHub Actions
|
Azure Key Vault
|
Kubernetes Cluster
|
ASP.NET Core Application
Secrets are retrieved securely during deployment rather than being stored in the application repository.
Common Security Risks
Poor secrets management can lead to:
| Risk | Example |
|---|---|
| Hardcoded credentials | Password committed to Git |
| Shared secrets | Same API key across environments |
| Expired certificates | Application outage |
| Excessive permissions | Unnecessary administrative access |
| Secret leakage | Credentials exposed in logs |
Reducing these risks requires centralized secret management.
Azure Key Vault Overview
Azure Key Vault securely stores:
Secrets
Certificates
Cryptographic keys
Applications retrieve secrets at runtime instead of embedding them in configuration files.
Example architecture:
Application
|
Azure Key Vault
|
Secrets
This approach improves both security and operational flexibility.
Creating a Key Vault Client
Install the required package.
dotnet add package Azure.Security.KeyVault.Secrets
Create a client.
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
var client =
new SecretClient(
new Uri(vaultUrl),
new DefaultAzureCredential());
DefaultAzureCredential allows applications to authenticate using supported Azure identity mechanisms.
Retrieving a Secret
Access a stored secret.
KeyVaultSecret secret =
await client.GetSecretAsync(
"DatabaseConnection");
Applications should retrieve secrets only when necessary and avoid logging sensitive values.
Using Configuration Providers
ASP.NET Core can integrate secrets into configuration.
builder.Configuration
.AddAzureKeyVault(
new Uri(vaultUrl),
new DefaultAzureCredential());
This enables applications to access secrets through the standard configuration API.
Secrets in Kubernetes
Kubernetes provides a Secret resource for storing sensitive values.
Example:
apiVersion: v1
kind: Secret
metadata:
name: app-secret
type: Opaque
data:
connectionString: BASE64_VALUE
Applications reference the secret rather than embedding credentials inside container images.
Base64 encoding is not encryption. Additional protections such as encryption at rest and access controls should be used where supported.
Consuming Kubernetes Secrets
Mount a secret as an environment variable.
env:
- name: ConnectionString
valueFrom:
secretKeyRef:
name: app-secret
key: connectionString
This keeps sensitive values outside application code.
Synchronizing Azure Key Vault and Kubernetes
Many organizations centralize secrets in Azure Key Vault while allowing Kubernetes workloads to consume them.
Azure Key Vault
|
Secret Synchronization
|
Kubernetes Secret
|
Application
This reduces duplication while keeping Key Vault as the authoritative source.
GitHub Actions and Secrets
CI/CD pipelines also require credentials.
GitHub Actions stores sensitive values separately from workflow files.
Workflow example:
env:
API_KEY:
${{ secrets.API_KEY }}
Using repository or organization secrets prevents credentials from being committed to source control.
Deploying Without Hardcoding Credentials
A deployment workflow might look like this:
GitHub Actions
|
Authenticate
|
Retrieve Secrets
|
Deploy Application
Credentials remain outside the application repository throughout the deployment process.
Secret Rotation
Long-lived credentials increase security risk.
A recommended lifecycle:
Create Secret
|
Use Secret
|
Rotate Secret
|
Update Applications
Applications should be designed to handle secret rotation with minimal disruption.
Principle of Least Privilege
Applications should receive only the permissions they require.
Instead of:
Application
Full Key Vault Access
Use:
Application
Read Database Secret
Read Storage Secret
Restricting access reduces the impact of compromised identities.
Avoid Logging Secrets
Never log sensitive values.
Avoid:
logger.LogInformation(
connectionString);
Prefer:
logger.LogInformation(
"Database connection initialized.");
Operational logs should contain metadata rather than confidential information.
Monitoring Secret Usage
Useful operational metrics include:

Join the conversation! Your thoughts help the community grow.