Watch Aspire live streams문서Aspire 사용해 보기
Watch Aspire live streams문서사용해 보기

Aspire on Azure: security best practices

이 콘텐츠는 아직 번역되지 않았습니다.

When you deploy Aspire apps to Azure, the base security posture comes from the deployment target you choose and the Azure resources you provision. This guide explains what Aspire configures for you by default and how to work with either the standard public networking model or the private-networked model, then harden the deployment with managed identities, Key Vault, and monitoring.

  • Azure Container Apps can expose internal-only or public endpoints. Use a delegated subnet when you want the environment inside your virtual network.
  • Azure App Service is a public website model for web-facing apps and APIs. Use managed Azure services for databases, caches, brokers, and other backing infrastructure instead of trying to run them on App Service.

Aspire supports both of these Azure networking models:

ModelWhat it means
Default public modelYour compute uses the target’s normal public ingress behavior, and managed Azure services stay on their standard public endpoints.
Private-networked modelYour Azure Container Apps environment runs in a delegated subnet and/or your managed Azure services are exposed through private endpoints instead of public network access.

Azure Container Apps supports both models. If you don’t attach a delegated subnet, Aspire leaves the environment on the default platform-managed network. Azure App Service remains a public website model either way, so private networking there is primarily about the backing Azure services rather than the app’s public site endpoint.

Start with Deploy to Azure for the shared Azure deployment model, then see Deploy to Azure Container Apps or Deploy to Azure App Service for target-specific behavior.

Aspire already handles several security basics for deployed Azure targets:

  • uses managed identities for deployment scenarios such as pulling images from Azure Container Registry
  • relies on platform-managed HTTPS behavior for public web ingress on Azure Container Apps and Azure App Service
  • flows connection information through resource references and configuration instead of requiring you to bake secrets into container images

These defaults are a good starting point. Some deployments can stay on the public model, while others need stronger network isolation for backing services.

Add private networking when you need network isolation

Section titled “Add private networking when you need network isolation”

If you’re staying on the default public model, focus on identities, secrets, RBAC, service-specific firewall rules, and monitoring. When you need private connectivity, add the 📦 Aspire.Hosting.Azure.Network package so you can configure virtual networks, subnets, network security groups (NSGs), NAT gateways, and private endpoints in your AppHost.

For Azure Container Apps, a common production pattern is to place the environment in a delegated subnet and put private endpoints for backing Azure services in a separate subnet:

apphost.mts
import {
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
} from './.aspire/modules/aspire.mjs';
const
const builder: IDistributedApplicationBuilder
builder
= await
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
();
const
const vnet: AzureVirtualNetworkResource
vnet
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addAzureVirtualNetwork(name: string, options?: {
addressPrefix?: string | ParameterResource;
}): AzureVirtualNetworkResource (+1 overload)

Adds an Azure Virtual Network resource to the application model.

addAzureVirtualNetwork
("vnet");
const
const appsSubnet: AzureSubnetResource
appsSubnet
= await
const vnet: AzureVirtualNetworkResource
vnet
.
AzureVirtualNetworkResource.addSubnet(name: string, addressPrefix: string | ParameterResource, options?: {
subnetName?: string;
} | undefined): AzureSubnetResource (+1 overload)

Adds an Azure subnet resource to an Azure Virtual Network resource.

addSubnet
("container-apps", "10.0.0.0/23");
const
const peSubnet: AzureSubnetResource
peSubnet
= await
const vnet: AzureVirtualNetworkResource
vnet
.
AzureVirtualNetworkResource.addSubnet(name: string, addressPrefix: string | ParameterResource, options?: {
subnetName?: string;
} | undefined): AzureSubnetResource (+1 overload)

Adds an Azure subnet resource to an Azure Virtual Network resource.

addSubnet
("private-endpoints", "10.0.2.0/27");
const
const env: AzureContainerAppEnvironmentResource
env
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addAzureContainerAppEnvironment(name: string): AzureContainerAppEnvironmentResource

Adds a container app environment resource to the distributed application builder.

addAzureContainerAppEnvironment
("aca-env");
await
const env: AzureContainerAppEnvironmentResource
env
.
IAzureDelegatedSubnetResource.withDelegatedSubnet(subnet: AzureSubnetResource): AzureContainerAppEnvironmentResource

Configures the resource to use the specified subnet with appropriate service delegation.

withDelegatedSubnet
(
const appsSubnet: AzureSubnetResource
appsSubnet
);
const
const keyVault: AzureKeyVaultResource
keyVault
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addAzureKeyVault(name: string): AzureKeyVaultResource

Adds an Azure Key Vault resource to the application model.

addAzureKeyVault
("vault");
await
const peSubnet: AzureSubnetResource
peSubnet
.
AzureSubnetResource.addPrivateEndpoint(target: IAzurePrivateEndpointTarget): AzurePrivateEndpointResource

Adds an Azure Private Endpoint resource to the subnet.

addPrivateEndpoint
(
const keyVault: AzureKeyVaultResource
keyVault
);
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.build(): DistributedApplication

Builds the distributed application

build
().
DistributedApplication.run(cancellationToken?: cancellationToken): void

Runs the distributed application

run
();

This pattern has a few important behaviors:

  • WithDelegatedSubnet configures the subnet delegation Azure Container Apps environments require.
  • AddPrivateEndpoint automatically creates the private DNS zone, virtual network link, and DNS zone group the target service needs.
  • In publish and deploy flows, adding a private endpoint also disables public network access on the target Azure resource by default.
  • Resources that reference the target keep using the same connection information; private DNS resolves the hostname to the private IP inside the virtual network.

If you omit WithDelegatedSubnet and AddPrivateEndpoint, Aspire keeps using the default public model.

If you deploy compute to App Service instead of Azure Container Apps, the same private-endpoint guidance still applies to your backing Azure services. App Service itself remains a public website model.

You can also add NSG rules to the delegated and private-endpoint subnets, and attach a NAT gateway when you need tighter ingress and egress control or deterministic outbound IP addresses.

For service-specific requirements such as Service Bus Premium tier support and Azure SQL private-endpoint deployment scripts, see Azure Virtual Network.

Store sensitive configuration data and secrets in Azure Key Vault instead of source control or container images:

apphost.mts
import {
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
} from './.aspire/modules/aspire.mjs';
const
const builder: IDistributedApplicationBuilder
builder
= await
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
();
const
const keyVault: AzureKeyVaultResource
keyVault
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addAzureKeyVault(name: string): AzureKeyVaultResource

Adds an Azure Key Vault resource to the application model.

addAzureKeyVault
("key-vault");
const
const api: ProjectResource
api
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addProject(name: string, projectPath: string, options?: {
launchProfileOrOptions?: ProjectResourceOptions;
}): ProjectResource (+1 overload)

Adds a .NET project resource

addProject
("api", "../Api/Api.csproj");
await
const api: ProjectResource
api
.
ProjectResource.withReference(source: EndpointReference | string | uri, options?: {
connectionName?: string;
optional?: boolean;
name?: string;
} | undefined): ProjectResource (+1 overload)

Adds a reference to another resource

withReference
(
const keyVault: AzureKeyVaultResource
keyVault
);
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.build(): DistributedApplication

Builds the distributed application

build
().
DistributedApplication.run(cancellationToken?: cancellationToken): void

Runs the distributed application

run
();

For more information, see Aspire Azure Key Vault integration.

Use user-assigned managed identities when you need explicit lifecycle control

Section titled “Use user-assigned managed identities when you need explicit lifecycle control”

For more granular control over permissions and role assignments, attach a user-assigned managed identity to the compute resource that needs it:

apphost.mts
import {
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
} from './.aspire/modules/aspire.mjs';
const
const builder: IDistributedApplicationBuilder
builder
= await
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
();
const
const identity: AzureUserAssignedIdentityResource
identity
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addAzureUserAssignedIdentity(name: string): AzureUserAssignedIdentityResource

Adds an Azure user‑assigned identity resource to the application model.

addAzureUserAssignedIdentity
("app-identity");
const
const api: ProjectResource
api
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addProject(name: string, projectPath: string, options?: {
launchProfileOrOptions?: ProjectResourceOptions;
}): ProjectResource (+1 overload)

Adds a .NET project resource

addProject
("api", "../Api/Api.csproj");
await
const api: ProjectResource
api
.
ProjectResource.withAzureUserAssignedIdentity(identityResourceBuilder: AzureUserAssignedIdentityResource): ProjectResource

Associates an Azure user-assigned identity with a compute resource

withAzureUserAssignedIdentity
(
const identity: AzureUserAssignedIdentityResource
identity
);
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.build(): DistributedApplication

Builds the distributed application

build
().
DistributedApplication.run(cancellationToken?: cancellationToken): void

Runs the distributed application

run
();

For detailed guidance, see Aspire Azure user-assigned managed identity integration.

Use the deployed Aspire Dashboard to inspect the compute resources that Aspire places in Azure Container Apps or Azure App Service, then use Application Insights and Azure Monitor alerts to detect suspicious behavior, repeated failures, or unusual traffic patterns after deployment:

apphost.mts
import {
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
} from './.aspire/modules/aspire.mjs';
const
const builder: IDistributedApplicationBuilder
builder
= await
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
();
const
const appInsights: AzureApplicationInsightsResource
appInsights
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addAzureApplicationInsights(name: string): AzureApplicationInsightsResource

Adds an Azure Application Insights resource to the application model.

addAzureApplicationInsights
("monitoring");
const
const api: ProjectResource
api
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addProject(name: string, projectPath: string, options?: {
launchProfileOrOptions?: ProjectResourceOptions;
}): ProjectResource (+1 overload)

Adds a .NET project resource

addProject
("api", "../Api/Api.csproj");
await
const api: ProjectResource
api
.
ProjectResource.withReference(source: EndpointReference | string | uri, options?: {
connectionName?: string;
optional?: boolean;
name?: string;
} | undefined): ProjectResource (+1 overload)

Adds a reference to another resource

withReference
(
const appInsights: AzureApplicationInsightsResource
appInsights
);
await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.build(): DistributedApplication

Builds the distributed application

build
().
DistributedApplication.run(cancellationToken?: cancellationToken): void

Runs the distributed application

run
();

The dashboard helps you inspect deployed compute resources, but it doesn’t surface managed Azure backing services as dashboard resources. Create Azure Monitor alerts for authentication failures, unexpected restarts, unusual latency spikes, and abnormal resource consumption across the app and its dependent Azure services.

For comprehensive guidance on Azure security, see Azure security best practices and patterns.