Server room with blue lights and fiber optic cables
Back to blog
aspireenterpriseazure

Aspire 13 for Enterprise: Networking, Registry, and Security

Sven HennessenDevOps

Network isolation, private endpoints, container registry abstraction, and Azure Front Door – Aspire 13 addresses enterprise requirements directly in the AppHost, without separate infrastructure configuration.

Enterprise environments impose requirements that go beyond "start containers and connect them": network isolation, private database connections, controlled access to container registries, and global traffic distribution. In Aspire 9, these aspects were entirely outside the AppHost. Aspire 13 brings them in.

Container Registry as an Explicit Concept

In Aspire 9, the container registry was implicit: Azure Container Apps came with a registry, end of story. Anyone wanting to reuse an existing registry, point multiple environments at the same registry, or use Docker Hub or GHCR had no clean abstraction.

From Aspire 13.1, the registry is a standalone resource:

// External registry (Docker Hub, GHCR, custom)
var registry = builder.AddContainerRegistry("prod-registry", "registry.example.com");

// Azure Container Registry with automatic provisioning
var acr = builder.AddAzureContainerRegistry("acr");

builder.AddProject<Projects.Api>("api")
    .WithContainerRegistry(registry);

This has practical consequences for the deployment flow: the image push step is now explicit in the pipeline and can run in parallel with other provisioning steps. Anyone with an ACR and existing pull identities can reference them directly:

env.WithAcrPullIdentity(existingAcr);

Azure Virtual Network and Private Endpoints

From Aspire 13.2, network isolation can be declared directly in the AppHost. Instead of writing Bicep templates manually, VNets, subnets, and private endpoints emerge from the application model:

var vnet = builder.AddAzureVirtualNetwork("vnet");

var appSubnet = vnet.AddSubnet("app-subnet");
var dataSubnet = vnet.AddSubnet("data-subnet");

var postgres = builder.AddAzurePostgresFlexibleServer("db")
    .RunAsContainer()
    .WithSubnet(dataSubnet)
    .AddPrivateEndpoint();

var api = builder.AddProject<Projects.Api>("api")
    .WithSubnet(appSubnet)
    .WithReference(postgres);

Aspire automatically generates the DNS zone configuration for private endpoints, so services can communicate via their Aspire names even when they sit in isolated subnets. NAT gateways and network security groups are configurable as shorthand methods at the subnet level:

vnet.AddSubnet("app-subnet")
    .WithNatGateway()
    .WithNsg(nsg => nsg
        .DenyAllInbound()
        .AllowInboundFrom(appSubnet));

Important: All VNet APIs are still marked [Experimental("ASPIREAZURE003")]. You can use a warning suppressor in the project to explicitly acknowledge this (at your own risk):

#pragma warning disable ASPIREAZURE003
var vnet = builder.AddAzureVirtualNetwork("vnet");
#pragma warning restore ASPIREAZURE003

Known trap: Azure SQL Server + Private Endpoints. When AddPrivateEndpoint is set on a SQL Server, Aspire disables public network access. But Aspire also needs to run a deployment script (Azure PowerShell) that connects to the SQL Server to assign managed identity roles. This script container runs outside the VNet – and can no longer reach the SQL Server.

This caused a DeploymentFailed error without an explanatory log up to 13.1. Aspire 13.2 resolves this by integrating the deployment script container into the VNet plus automatically provisioning a storage account needed as a file share for the script container. This happens transparently, but costs an additional provisioned Azure storage account per deployment (microsoft/aspire#14421). Anyone deploying SQL Server with private endpoints on Aspire 13.1 or older will hit this error reproducibly.

Network Security Perimeters

From Aspire 13.3, Azure Network Security Perimeters are integrable – a concept that allows grouping multiple Azure resources (storage accounts, Service Bus, Key Vault) under a shared network perimeter that enforces uniform access rules:

var perimeter = builder.AddAzureNetworkSecurityPerimeter("nsp");

builder.AddAzureStorage("storage")
    .WithNetworkSecurityPerimeter(perimeter);

builder.AddAzureServiceBus("bus")
    .WithNetworkSecurityPerimeter(perimeter);

Traffic between resources within the same perimeter is allowed without explicit configuration; external access is managed centrally.

Azure Front Door

For globally distributed deployments, Azure Front Door is directly modelable in the AppHost from Aspire 13.3:

var frontDoor = builder.AddAzureFrontDoor("cdn");

builder.AddProject<Projects.Api>("api")
    .WithExternalHttpEndpoints()
    .WithAzureFrontDoor(frontDoor, route => route
        .WithPath("/api/*")
        .WithCaching());

builder.AddProject<Projects.Frontend>("frontend")
    .WithExternalHttpEndpoints()
    .WithAzureFrontDoor(frontDoor, route => route
        .WithPath("/*"));

Aspire provisions the Front Door profile, origins, and routing rules as part of the normal aspire deploy flow. Caching configuration, WAF policies, and health probes are configurable directly on the route.

Caution when upgrading to 13.4: Front Door naming conventions changed between 13.3 and 13.4 in a way that can create duplicate resource names in existing deployments. Existing Front Door resources should be manually reviewed before upgrading to 13.4.

External Helm Charts as Deployment Steps

For Kubernetes deployments in enterprise environments there is often existing infrastructure: an ingress controller, a secrets manager, a monitoring stack. Aspire 13.4 allows these to be included as Helm chart steps in the deployment pipeline:

builder.AddHelmChart("cert-manager", "cert-manager/cert-manager", "v1.16.0",
    values => values.Set("installCRDs", true));

builder.AddHelmChart("prometheus", "prometheus-community/kube-prometheus-stack", "65.1.0");

These charts are installed as part of aspire deploy, with the same dependency ordering as Aspire-native resources. aspire destroy runs helm uninstall for all registered charts.

Managed Identities per Service

Introduced in Aspire 9.x but worth mentioning here: each Azure Container App has received a dedicated managed identity since Aspire 9.3. In enterprise environments this is the foundation for granular access management – instead of a shared identity with broad access, each service gets exactly the permissions it needs. Aspire generates the corresponding role assignments automatically at deploy time.

Need support?

Want to implement enterprise requirements like network isolation, private endpoints, or global traffic routing with Aspire, but unsure which APIs are stable and where the pitfalls still are? We're happy to help! Get in touch and we'll work together to set up your enterprise infrastructure safely with Aspire.

Get in touch