Skip to content

Conversation

@eerhardt
Copy link
Member

@eerhardt eerhardt commented Feb 6, 2026

Description

Adds Network Security Group (NSG) support for Azure Virtual Networks, enabling fine-grained network traffic control for subnets. Includes both a shorthand API for the common case and an explicit API for full control.

Shorthand API (recommended for most users)

Fluent methods on subnet builders that auto-create an NSG, auto-increment priority, and auto-generate rule names:

var subnet = vnet.AddSubnet("web", "10.0.1.0/24")
    .AllowInbound(port: "443", from: "AzureLoadBalancer", protocol: SecurityRuleProtocol.Tcp)
    .DenyInbound(from: "VirtualNetwork")
    .DenyInbound(from: "Internet");

Explicit API (for full control)

Create standalone NSG resources with explicit AzureSecurityRule objects:

var nsg = builder.AddNetworkSecurityGroup("web-nsg")
    .WithSecurityRule(new AzureSecurityRule
    {
        Name = "allow-https",
        Priority = 100,
        Direction = SecurityRuleDirection.Inbound,
        Access = SecurityRuleAccess.Allow,
        Protocol = SecurityRuleProtocol.Tcp,
        DestinationPortRange = "443"
    });

var subnet = vnet.AddSubnet("web-subnet", "10.0.1.0/24")
    .WithNetworkSecurityGroup(nsg);

New public APIs

Types:

  • AzureNetworkSecurityGroupResource — standalone AzureProvisioningResource with its own bicep module, Id and NameOutput outputs, and AddAsExistingResource support
  • AzureSecurityRule — data class for rule configuration. SourcePortRange, SourceAddressPrefix, and DestinationAddressPrefix default to "*" to reduce verbosity

Extension methods on IDistributedApplicationBuilder:

  • AddNetworkSecurityGroup(name) — creates a top-level NSG resource

Extension methods on IResourceBuilder<AzureNetworkSecurityGroupResource>:

  • WithSecurityRule(rule) — adds a security rule (rejects duplicate names)

Extension methods on IResourceBuilder<AzureSubnetResource>:

  • WithNetworkSecurityGroup(nsg) — associates an explicit NSG with a subnet
  • AllowInbound(port, from, to, protocol, priority, name) — shorthand allow inbound rule
  • DenyInbound(...) — shorthand deny inbound rule
  • AllowOutbound(...) — shorthand allow outbound rule
  • DenyOutbound(...) — shorthand deny outbound rule

Key design decisions

  • NSG is a standalone AzureProvisioningResource — generates its own bicep module (not inline in the VNet module). Subnets reference the NSG via cross-module parameter (param nsg_outputs_id string)
  • NSG is a top-level resource (not a child of VNet), matching Azure's actual resource model
  • Shorthand methods auto-create an implicit NSG named {subnet}-nsg when no NSG is assigned. Calling WithNetworkSecurityGroup after shorthand methods throws InvalidOperationException to prevent silent rule loss
  • Priority auto-increments by 100 (100, 200, 300...) from the max existing priority
  • Rule names auto-generate from access/direction/port/source (e.g., allow-inbound-443-AzureLoadBalancer)
  • Sensible defaults on AzureSecurityRuleSourcePortRange, SourceAddressPrefix, DestinationAddressPrefix all default to "*", reducing the common 10-line rule to ~5 required properties
  • A single NSG can be shared across multiple subnets
  • Duplicate rule names within an NSG are rejected with ArgumentException

Contributes to #13750

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks> and <code/> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No
  • Does the change require an update in our Aspire docs?

Copilot AI review requested due to automatic review settings February 6, 2026 23:31
@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 14383

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 14383"

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds NSG modeling to the Azure Network hosting integration so AppHost authors can define Network Security Groups with rules and associate them to subnets, resulting in correct NSG + rule + subnet references in generated Bicep.

Changes:

  • Introduces AzureNetworkSecurityGroupResource and AzureSecurityRule, plus builder APIs to add NSGs, add rules, and associate NSGs with subnets.
  • Updates VNet provisioning to emit NSGs (and their rules) before subnets and to reference NSGs by resource id from subnets.
  • Adds unit tests + verified Bicep snapshots and updates the playground end-to-end sample to demonstrate NSG usage.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/Aspire.Hosting.Azure.Network/AzureVirtualNetworkExtensions.cs Adds builder APIs and updates VNet provisioning to emit NSGs/rules and pass NSG mapping into subnet generation.
src/Aspire.Hosting.Azure.Network/AzureVirtualNetworkResource.cs Tracks NSGs on the VNet model.
src/Aspire.Hosting.Azure.Network/AzureSubnetResource.cs Adds subnet-to-NSG association support during provisioning.
src/Aspire.Hosting.Azure.Network/AzureNetworkSecurityGroupResource.cs New resource type representing an NSG and converting it (and rules) to provisioning entities.
src/Aspire.Hosting.Azure.Network/AzureSecurityRule.cs New public configuration type for NSG rule definition.
src/Aspire.Hosting.Azure.Network/README.md Documents NSG usage with rules and subnet association.
tests/Aspire.Hosting.Azure.Tests/AzureVirtualNetworkExtensionsTests.cs Adds unit tests for NSG creation, rule handling, subnet association, and Bicep generation.
tests/Aspire.Hosting.Azure.Tests/Snapshots/AzureVirtualNetworkExtensionsTests.AddNetworkSecurityGroup_GeneratesCorrectBicep.verified.bicep Snapshot for NSG-only generation.
tests/Aspire.Hosting.Azure.Tests/Snapshots/AzureVirtualNetworkExtensionsTests.AddNetworkSecurityGroup_WithSecurityRules_GeneratesCorrectBicep.verified.bicep Snapshot for NSG + multiple rules generation.
tests/Aspire.Hosting.Azure.Tests/Snapshots/AzureVirtualNetworkExtensionsTests.AddSubnet_WithNetworkSecurityGroup_GeneratesCorrectBicep.verified.bicep Snapshot for subnet referencing NSG by id.
tests/Aspire.Hosting.Azure.Tests/Snapshots/AzureVirtualNetworkExtensionsTests.AddNetworkSecurityGroup_SharedAcrossSubnets_GeneratesCorrectBicep.verified.bicep Snapshot for a shared NSG across multiple subnets.
playground/AzureVirtualNetworkEndToEnd/AzureVirtualNetworkEndToEnd.AppHost/Program.cs Updates the playground AppHost to create NSGs, add rules, and attach them to subnets.
playground/AzureVirtualNetworkEndToEnd/AzureVirtualNetworkEndToEnd.AppHost/vnet.module.bicep Updates the sample module to include NSGs, rules, and subnet NSG references.

@davidfowl
Copy link
Member

This looks...complex.

@mitchdenny
Copy link
Member

The AzureSecurityRule + WithSecurityRule API makes sense as the low-level building block. A few thoughts:

Higher-level subnet helpers

The rule API is quite verbose for common patterns. Have we thought about higher-level helpers on subnets that generate the right rules underneath? Something like:

// Block all outbound internet from this subnet
subnet.WithInternetAccess(false);

// Allow inbound HTTPS from another subnet
subnet.AllowInboundFrom(otherSubnet, port: 443);

// Allow inbound from a service tag
subnet.AllowInboundFrom("AzureLoadBalancer", port: 443);

// Full isolation — deny all except Azure infrastructure traffic
subnet.WithNetworkIsolation();

These would auto-create an NSG if the subnet doesn't have one, generate the rules, and handle priority numbering. The verbose API stays for custom/compliance rules — this would just be sugar on top.

Why Resource instead of AzureProvisioningResource?

NSG extends Resource which means no ConfigureInfrastructure escape hatch. If someone needs augmented rules (multiple address prefixes), the Description field, or anything else Azure adds to NSGs later — they're stuck. #14413 went with AzureProvisioningResource for NAT Gateway and PIP. Was there a specific reason to go a different direction here? Feels like this would be hard to change later.

Nit: missing aspire-resource-name tag

The generated NSG bicep doesn't set aspire-resource-name in tags. VNet, NAT Gateway, and PIP all do.

Adds the ability to create NSGs with security rules and associate them
with subnets, enabling fine-grained network traffic control for Azure
resources deployed into VNets.

New APIs:
- AddNetworkSecurityGroup() on IResourceBuilder<AzureVirtualNetworkResource>
- WithSecurityRule() on IResourceBuilder<AzureNetworkSecurityGroupResource>
- WithNetworkSecurityGroup() on IResourceBuilder<AzureSubnetResource>

New types:
- AzureNetworkSecurityGroupResource (child of VNet)
- AzureSecurityRule (public data class for rule configuration)

Key behaviors:
- NSGs are created before subnets in bicep for correct dependency ordering
- Security rule bicep identifiers are prefixed with NSG name to avoid
  duplicate symbolic names across multiple NSGs
- A single NSG can be shared across multiple subnets
- Duplicate rule names within an NSG are rejected with ArgumentException
- Subnets reference NSGs via id (not inline properties) in generated bicep
Make helper methods for easily adding rules to subnets.

Make NSG a top-level resource.
Security rules added via WithSecurityRule are now applied after
CreateExistingOrNewProvisionableResource returns, so they apply
to both existing and new NSGs. Previously, rules were only added
inside the new-resource callback.

Added test verifying security rules work alongside
ConfigureInfrastructure customizations.
@eerhardt eerhardt merged commit 45d446d into dotnet:main Feb 10, 2026
341 checks passed
@eerhardt eerhardt deleted the AddNSG branch February 10, 2026 21:35
@dotnet-policy-service dotnet-policy-service bot added this to the 13.2 milestone Feb 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants