Skip to content
Rehan Akbar
Rehan Akbar
All articles
September 15, 2026·17 min
  • #Security
  • #Software Architecture
  • #ASP.NET Core
  • #Azure
  • #DevSecOps
  • #.NET

Security Should Be Part of Architecture, Not a Final Step

A practical guide to security-by-design in ASP.NET Core and Azure, covering identity, authorization, secrets, validation, rate limiting, encryption, network isolation, least privilege, and DevSecOps.

·
17 min read
·
··· reads
On this page

A common anti-pattern in software engineering is treating security as an afterthought: build the application, deploy it to the cloud, and ask the security team to run a vulnerability scan the week before launch.

That audit-at-the-end approach can catch known vulnerabilities and missing patches, but it is not the same as designing a resilient, secure system.

The Security-by-Design Imperative

Security decisions fundamentally alter your architecture from day one. Retrofitting network isolation, zero-trust token propagation, secretless managed identities, or least-privilege RBAC onto an already-deployed distributed system is orders of magnitude more expensive than building them into the foundation.

Foundational architectural decisions dictate your entire attack surface:

  • Identity & Access: Who can access the system, and how are credentials verified?
  • Granular Authorization: What specific actions can each caller execute?
  • Public Surface Area: Which endpoints and ports are publicly exposed?
  • Secret Management: Where do database keys and API tokens live?
  • Network Boundaries: Which microservices and datastores are allowed to communicate?
  • Data Protection: How is sensitive data protected in transit and at rest?
  • Telemetry & Blast Radius: What happens if a single component or credential is compromised?

Microsoft's Azure Well-Architected Framework recommends embedding security throughout the workload lifecycle rather than treating it as an isolated gate at the end. The goal is not to declare an application "impossible to hack." The goal is to minimize attack surfaces, enforce least privilege, constrain the blast radius, and make malicious activity immediately detectable and remediable.

Blast Radius & Attack Surface ComparisonAttack Surface Minimized
BeforeDirect DB Exposure + Wildcard Subscription Contributor
OptimizedPrivate Endpoints + Managed Identity + Least-Privilege RBAC

Replacing public database ports and over-privileged subscription credentials with private network isolation and scoped managed identities ensures that even a compromised web container cannot pivot to other resources or delete infrastructure.


1. Security Starts With Architecture

A naive, basic application deployment often looks like this:

Architecture Diagram·Mermaid
Rendering architecture diagram...

While straightforward to build and run locally, this design leaves critical questions unanswered: What prevents brute-force credential stuffing? What stops SQL injection or volumetric DDoS attacks? What happens if the database port is scanned on the public internet?

A production-ready cloud architecture establishes defense-in-depth through multi-layered controls:

Architecture Diagram·Mermaid
Rendering architecture diagram...
Context-Driven Architecture

Security controls must align with the workload's specific threat model, regulatory requirements (SOC2, HIPAA, PCI-DSS), data classification, and cost profile. Incorporating WAF inspection, API gateway policies, network segmentation, and managed identities early provides a scalable template.


2. Authentication and Authorization Are Distinct Concepts

One of the most foundational architectural separations is distinguishing identity verification from permission evaluation.

Authentication (AuthN)

Authentication answers the question: "Who are you?"

  • Microsoft Entra ID (Azure AD)
  • OAuth 2.0 / OpenID Connect (OIDC)
  • Client Certificates (mTLS)
  • API Keys / Workload Identity Federation

Authorization (AuthZ)

Authorization answers the question: "What are you allowed to do?"

A valid token does not grant universal access. The application must enforce explicit policies based on roles, claims, or fine-grained scopes:

Architecture Diagram·Mermaid
Rendering architecture diagram...

ASP.NET Core Implementation

In modern ASP.NET Core, configure JWT Bearer authentication and explicit policy-based authorization in Program.cs:

csharp
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
 
var builder = WebApplication.CreateBuilder(args);
 
builder.Services
    .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.Authority = builder.Configuration["Authentication:Authority"];
        options.Audience = builder.Configuration["Authentication:Audience"];
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            RequireSignedTokens = true,
            ValidAlgorithms = new[] { SecurityAlgorithms.RsaSha256 },
            ClockSkew = TimeSpan.FromSeconds(30)
        };
    });
 
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("Orders.Read", policy =>
        policy.RequireClaim("scope", "orders.read"));
 
    options.AddPolicy("Orders.Write", policy =>
        policy.RequireClaim("scope", "orders.write"));
 
    options.AddPolicy("Orders.Admin", policy =>
        policy.RequireRole("PlatformAdmin"));
});

Protect endpoints declaratively:

csharp
[Authorize(Policy = "Orders.Read")]
[HttpGet("/orders")]
public IActionResult GetOrders()
{
    return Ok(new[] { new { Id = 1, Item = "Laptop" } });
}
 
[Authorize(Policy = "Orders.Admin")]
[HttpDelete("/orders/{id:int}")]
public IActionResult DeleteOrder(int id)
{
    return NoContent();
}
Core Rule

Authenticate at the edge or gateway, but always authorize at the domain boundary.

Never allow an authenticated identity to perform actions without validating its permissions against the target resource.

Pin the Signing Algorithm

Never trust the algorithm claimed by the token itself. Explicitly allowlist ValidAlgorithms and set RequireSignedTokens to true—otherwise a crafted token using an unexpected algorithm (such as none or a symmetric key mismatched with an asymmetric key) can bypass signature verification entirely.


3. Secrets Should Never Live in Source Code

Hardcoded passwords, API keys, and connection strings committed to Git repositories remain one of the most common vectors for security incidents.

Avoid placing production secrets directly inside configuration files:

json
// ❌ ANTI-PATTERN: Never commit secrets to source control
{
  "ConnectionStrings": {
    "Database": "Host=prod-db.postgres.database.azure.com;Username=admin;Password=SuperSecretPassword123!"
  },
  "PaymentGateway": {
    "ApiKey": "sk_live_94829384729103847"
  }
}

Non-sensitive configuration (such as base URLs, timeouts, and feature flags) belongs in configuration files:

json
// ✅ SAFE: Non-secret operational settings
{
  "ExternalServices": {
    "PaymentApi": {
      "BaseUrl": "https://api.stripe.com",
      "TimeoutSeconds": 30
    }
  }
}

The Azure Managed Identity Approach

In cloud-native Azure environments, eliminate credentials entirely by using System-Assigned or User-Assigned Managed Identities:

Architecture Diagram·Mermaid
Rendering architecture diagram...

Clean C# Integration with Azure SDK

Using Azure.Identity and DefaultAzureCredential, your code functions identically in local development (using developer credentials) and in Azure (using Managed Identity):

csharp
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
 
// Resolves Managed Identity in Azure, CLI/VS credentials locally
var credential = new DefaultAzureCredential();
 
var secretClient = new SecretClient(
    new Uri("https://kv-production-ecommerce.vault.azure.net/"),
    credential);
 
KeyVaultSecret secret = await secretClient.GetSecretAsync("StripeApiKey");
string apiKey = secret.Value;
'Secretless' Means No Static Secret, Not No Trust Boundary

Managed Identity removes the need for your application to hold or rotate a static credential, which eliminates an entire class of leaks (Git commits, log dumps, config drift). It does not eliminate trust: the Managed Identity's RBAC role assignment and Microsoft Entra ID's token issuance are still the boundary an attacker would target. Scope those roles as tightly as the secrets they replace.


4. Input Validation Is an Architectural Boundary

Authentication confirms identity, but it does not make input trustworthy. An authenticated employee or customer can still submit malformed payloads, excessive string lengths, or malicious parameters.

Architecture Diagram·Mermaid
Rendering architecture diagram...

Multi-Layered Validation in ASP.NET Core

Combine strong schema validation at the HTTP boundary with domain validation in the application core:

csharp
using System.ComponentModel.DataAnnotations;
 
public sealed record CreateOrderRequest(
    [Required, StringLength(50, MinimumLength = 3)]
    string CustomerId,
 
    [Range(1, 100, ErrorMessage = "Quantity must be between 1 and 100.")]
    int Quantity,
 
    [Required, RegularExpression(@"^[A-Z0-9-]{6,12}$", ErrorMessage = "Invalid SKU format.")]
    string ProductSku
);
Defense in Depth for Validation

Attribute validation is your first filter, but it must be supplemented with domain rule checks (e.g., FluentValidation or Rich Domain Aggregates) to prevent logical corruption.


5. Rate Limiting for Availability and Abuse Prevention

An authenticated user or third-party service can still overwhelm your database through automated loops, scraping, or unintentional concurrency bugs.

Architecture Diagram·Mermaid
Rendering architecture diagram...

ASP.NET Core Native Rate Limiting

ASP.NET Core provides built-in rate-limiting middleware:

csharp
using System.Threading.RateLimiting;
using Microsoft.AspNetCore.RateLimiting;
 
var builder = WebApplication.CreateBuilder(args);
 
builder.Services.AddRateLimiter(options =>
{
    options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
 
    options.AddFixedWindowLimiter("PublicApiPolicy", opt =>
    {
        opt.PermitLimit = 100;
        opt.Window = TimeSpan.FromMinutes(1);
        opt.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
        opt.QueueLimit = 0;
    });
 
    options.AddSlidingWindowLimiter("AuthEndpointPolicy", opt =>
    {
        opt.PermitLimit = 10;
        opt.Window = TimeSpan.FromMinutes(1);
        opt.SegmentsPerWindow = 6;
        opt.QueueLimit = 0;
    });
});
 
var app = builder.Build();
 
app.UseRateLimiter();
 
app.MapGet("/products", () => Results.Ok(new { Status = "Available" }))
   .RequireRateLimiting("PublicApiPolicy");
This Limiter Does Not Scale Horizontally

AddFixedWindowLimiter and AddSlidingWindowLimiter track counters in-process memory. The moment your API runs as more than one replica—which the architecture in this article assumes—each instance enforces its own independent limit, so the effective ceiling multiplies by the replica count instead of staying fixed. For a real global limit, either enforce throttling upstream at Azure API Management or Azure Front Door, or back the .NET limiter with a distributed store (e.g., a Redis-based partitioned limiter) so all instances share state.


6. Encryption: In Transit and At Rest

Architectural design must guarantee confidentiality and integrity across the entire data lifecycle.

Architecture Diagram·Mermaid
Rendering architecture diagram...
Do Not Roll Custom Cryptography

Never implement custom hashing or encryption algorithms. Leverage battle-tested framework primitives (System.Security.Cryptography, DataProtectionProvider) and managed cloud encryption services.


7. Network Isolation & Defense in Depth

Relying solely on application-level authentication creates a single point of failure. If an attacker discovers an authorization bypass or a zero-day exploit, an exposed database port allows direct compromise.

Architecture Diagram·Mermaid
Rendering architecture diagram...
Zero-Trust Network Isolation
  • ✓Databases have no public IP addresses and sit behind Private Endpoints.
  • ✓Application tier only communicates with APIM via Virtual Network integration.
  • ✓Network Security Groups (NSGs) restrict egress to approved subnets and endpoints.
  • ✓Microservice boundaries use mTLS and private DNS zones.
Permissive Public Ingress
  • ✗Database exposed to 0.0.0.0/0 with password-only authentication
  • ✗Backend microservices have public URLs accessible directly from the internet
  • ✗Secrets and connection strings transmitted across unencrypted public networks
  • ✗Compromising one container grants unrestricted horizontal network access

8. Preventing Gateway Bypass

When an API Gateway (such as Azure API Management) handles critical concerns—such as authentication, WAF filtering, SSL termination, and rate limiting—the backend services must never be directly reachable from the public internet.

Architecture Diagram·Mermaid
Rendering architecture diagram...

Enforcing Ingress Restrictions in Azure

  1. Private Endpoints: Bind the backend App Service or Container App to a private virtual network.
  2. Access Restrictions: Restrict backend IP firewall rules to allow traffic only from the API Management subnet.
  3. Mutual TLS / Client Certificates: Configure backend APIs to require a verified client certificate issued by the gateway.

Enforce the certificate check in code rather than relying on network placement alone, so a misconfigured firewall rule doesn't become the only line of defense:

csharp
builder.Services
    .AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
    .AddCertificate(options =>
    {
        options.AllowedCertificateTypes = CertificateTypes.Chained;
        options.RevocationMode = X509RevocationMode.Online;
        options.Events = new CertificateAuthenticationEvents
        {
            OnCertificateValidated = context =>
            {
                var thumbprint = context.ClientCertificate.Thumbprint;
                if (thumbprint != builder.Configuration["Gateway:TrustedThumbprint"])
                {
                    context.Fail("Untrusted client certificate.");
                    return Task.CompletedTask;
                }
 
                context.Success();
                return Task.CompletedTask;
            }
        };
    });
 
app.UseAuthentication();
app.MapGet("/internal/orders", () => Results.Ok())
   .RequireAuthorization()
   .RequireHost("*.internal.azurecontainerapps.io");

9. The Principle of Least Privilege

Least privilege dictates that an identity (human, service principal, or managed identity) receives

only the exact permissions required to complete its function—and nothing more.

Architecture Diagram·Mermaid
Rendering architecture diagram...
Avoid Broad Role Assignments

Assigning roles like Owner or Contributor at the Azure Subscription or Resource Group level to an application identity is a severe anti-pattern. Always scope RBAC to the specific resource (e.g., Key Vault Secrets User scoped to a single vault).


10. Security Logging, Auditing, and Observability

A secure system must not only prevent unauthorized access; it must also generate actionable telemetry to answer forensic questions during an incident:

  • Who accessed the resource?
  • What operation was attempted?
  • When and from what IP address did the request originate?
  • Was access allowed or denied?
Architecture Diagram·Mermaid
Rendering architecture diagram...

Sanitizing Log Output

Never log sensitive data:

Scroll horizontally to see all columns.

Logged Category❌ Prohibited in Logs✅ Recommended Sanitized Alternative
AuthenticationRaw passwords, JWT signatures, Bearer tokensIdentity Subject ID (sub), Token Expiration, Issuer
PII & PrivacyCredit card PANs, SSNs, raw email addressesMasked identifiers (**-**-****-4242), Hashed IDs
InfrastructureFull DB connection strings with credentialsTarget Server Name (prod-db-cluster), Database Name

11. Dependency Security & DevSecOps Automation

Modern applications are constructed primarily from third-party open-source packages, container base images, and runtime dependencies. A vulnerability in an external library is an architectural vulnerability in your system.

Architecture Diagram·Mermaid
Rendering architecture diagram...

Automated CLI Checks in CI/CD

Integrate automated dependency checks into your build pipeline:

bash
# Scan .NET dependencies for known CVEs
dotnet list package --vulnerable --include-transitive
 
# Check for outdated packages with breaking changes
dotnet list package --outdated

12. A Practical Production Azure Architecture

Bringing all these principles together yields a robust, scalable, and isolated cloud architecture:

Architecture Diagram·Mermaid
Rendering architecture diagram...

Core Architecture Components:

  • Azure Front Door + WAF: Enforces DDoS mitigation and Layer-7 web application firewall policies globally.
  • Azure API Management: Acts as the single public entry point, validating tokens and throttling abusive callers.
  • Private Virtual Network: Encloses the application tier, database, and key vault inside isolated subnets with no public internet ingress.
  • Microsoft Entra ID & Managed Identities: Eliminates hardcoded passwords by generating dynamic tokens for datastore and key vault communication.

13. Comprehensive Security-by-Design Checklist

Before releasing an architecture to production, run through this architectural verification checklist:

1. Identity & Access Management

  • Are all API endpoints secured with OAuth 2.0 / OpenID Connect tokens?
  • Is authorization policy-based rather than relying on role strings?
  • Are workload identities and service principals audited regularly?

2. Network Isolation & Perimeter

  • Are backend APIs and databases completely isolated from direct public internet access?
  • Do microservices communicate over private endpoints and virtual network links?
  • Is gateway bypass prevented via IP whitelisting or mutual TLS?

3. Secrets & Configuration

  • Are zero credentials or connection strings committed to source control?
  • Are cloud resources utilizing Managed Identities instead of connection passwords?
  • Are secrets in Azure Key Vault rotated and audited automatically?

4. Input Validation & Resilience

  • Is incoming payload schema and size validated before hitting domain logic?
  • Are rate limits configured on public and expensive computational endpoints?
  • Are all database interactions strictly parameterized to eliminate injection vulnerabilities?

5. Data Encryption & Storage

  • Is all external and internal traffic enforced over TLS 1.3 / HTTPS?
  • Is transparent data encryption (TDE) active on all relational and blob stores?
  • Are cryptographic keys managed via Azure Key Vault HSMs?

6. Observability & DevSecOps

  • Are automated SAST, dependency vulnerability, and secret scans active in CI/CD?
  • Are security events and authorization failures routed to a SIEM (e.g., Microsoft Sentinel)?
  • Is application telemetry sanitized to prevent leaking customer PII or auth credentials?

14. Security Is a Continuous Design Constraint

The fundamental mindset shift in modern engineering is changing the guiding question:

Instead of asking:

"How do we secure this application before going live?"

Architects must ask:

"What security properties, isolation boundaries, and trust constraints must this system guarantee before we write the first line of code?"

Architecture Diagram·Mermaid
Rendering architecture diagram...

When security is embedded directly into the architecture, your application becomes inherently resilient, auditable, and prepared to adapt to evolving threats.



Sources and Further Reading


Need an architectural security audit, cloud modernization advisory, or guidance structuring resilient .NET backends? Explore my background and advisory services or connect on LinkedIn.

Rehan Akbar

Written by Rehan Akbar

Software Engineer · Singapore · .NET, Cloud & Applied AI

I write about the engineering trade-offs behind reliable production systems—Clean Architecture, distributed resilience, observability, and practical AI engineering. Open for architecture advisory and technical collaborations.

Discussion & Comments

Share your thoughts, ask technical questions, or discuss architecture edge cases.