In the previous chapters of the Cloud App Journey series, we explored deployment, containers, scalability, observability, and performance optimization. Now it's time to face one of the most critical topics in any distributed cloud application:
Security.
Here are a few questions you’ve probably asked yourself at some point (or should have):
How can I ensure that only authorized users can access my APIs?
How do I store sensitive secrets (like connection strings) without exposing them in code or config files?
How do I prevent leaked credentials from compromising the entire production environment?
In this episode, we’ll walk through how to address these challenges in Azure using .NET, with practical examples for modern microservices.
1. How do we ensure that only authorized users can access the API?
The standard approach today is to protect APIs using OAuth 2.0 + OpenID Connect, with Azure Entra ID as the identity provider.
The flow is straightforward:
- The user (or another application) obtains a JWT token from Azure Entra ID.
- The token is sent in the request header:
Authorization: Bearer <token>
- The API validates that token and determines whether the request should be served.
Example: API requiring a specific Role
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/reports")]
public class ReportsController : ControllerBase
{
// Only users with the role "admin.app" can access
[HttpGet("financial")]
[Authorize(Roles = "admin.app")]
public IActionResult GetFinancialReport()
{
return Ok("Sensitive financial report...");
}
}
If the token does not include the admin.app role → access is automatically denied.
No manual if checks
No duplicated logic
No custom middleware hacks
How does the API validate tokens?
appsettings.json (or environment variables in containers):
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"ClientId": "api://my-backend-id"
}
Program.cs:
builder.Services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
var azureAd = builder.Configuration.GetSection("AzureAd");
options.Authority = $"{azureAd["Instance"]}{azureAd["TenantId"]}/v2.0";
options.Audience = azureAd["ClientId"];
});
builder.Services.AddAuthorization();
Once configured → your API now only responds to identities recognized and authorized by Azure.
2. How do we securely store sensitive data for microservices?
A common example:
Production database connection strings should not be stored in:
- appsettings.json
- .env files
- repository code
- manually copied configurations
The standard solution is:
Azure Key Vault → secure secret storage.
You store secrets in Key Vault and your application consumes them without exposing the values directly.
Example: Accessing Key Vault secrets in .NET
Program.cs:
using Azure.Identity;
var builder = WebApplication.CreateBuilder(args);
var keyVaultName = builder.Configuration["KeyVaultName"];
var uri = new Uri($"https://{keyVaultName}.vault.azure.net/");
builder.Configuration.AddAzureKeyVault(uri, new DefaultAzureCredential());
Now your connection string can be used like this:
var connectionString = builder.Configuration["DbConnectionString"];
No secrets in code, repository, or pipelines.
3. How do we deliver secrets to containers in production?
When your API is deployed to Azure Kubernetes Service or Azure App Service, Key Vault can be integrated seamlessly using:
Managed Identity (automatic identity for the resource)
No passwords, no keys, no tokens.
What happens:
- The service identifies itself to Azure automatically.
- Azure checks whether it has permission to read from Key Vault.
- Secrets are retrieved securely, without being exposed at any point.
This eliminates:
- .env files leaking in logs
- secrets embedded in build pipelines
- hardcoded credentials
And strengthens:
- Security
- Auditability
- Governance
Conclusion
When it comes to cloud applications, security is not just about “enabling HTTPS.”
It’s about protecting identity, authorization, and secrets consistently across environments.
The good news is:
With .NET and Azure, this strategy can be clear, robust, and maintainable.
Security becomes part of the architecture, not an afterthought.
Top comments (0)