Documentation

adrs/045-vnet-service-endpoints.md

ADR-045: VNet Service Endpoints for External Storage Access

Status

Accepted

Context

Container Apps running in a VNet need to access external Azure Storage accounts that have firewall rules enabled. The IoT component's DatalogicBlobProcessor connects to an external storage account (saacsiscorpbbuatdev) that stores camera images from Datalogic devices.

The Problem

When Container Apps in a VNet attempt to access a storage account with firewall rules:

  1. Without Service Endpoints: Traffic exits via the Container App Environment's static public IP
  2. Storage Firewall Behavior: The storage account sees the request coming from the public IP, not the VNet
  3. Result: Even if the VNet/subnet is in the storage account's allowed list, access is denied (403 AuthorizationFailure)

The error manifested as:

Azure.RequestFailedException: This request is not authorized to perform this operation.
Status: 403 (This request is not authorized to perform this operation.)
ErrorCode: AuthorizationFailure

Root Cause

The Container Apps infrastructure subnet was missing the Microsoft.Storage service endpoint. Service endpoints route traffic through Azure's backbone network directly to the storage service, allowing the storage account's VNet firewall rules to recognize the traffic as coming from the allowed subnet.

Decision

Configure the Container Apps infrastructure subnet with the Microsoft.Storage service endpoint in the Dynaplex orchestration infrastructure.

Implementation

// In DynaplexInfrastructureExtensions.cs - AddDynaplexContainerAppEnvironment()
var subnet = new SubnetResource("infrastructureSubnet") {
    Parent = vnet,
    Name = context.ResourceName(DynaplexContext.AzureAbbreviations.Subnet, "infra"),
    AddressPrefix = "10.0.0.0/23",
    Delegations = [
        new ServiceDelegation {
            Name = "containerApps",
            ServiceName = "Microsoft.App/environments"
        }
    ],
    ServiceEndpoints = [
        new ServiceEndpointProperties { Service = "Microsoft.Storage" }
    ]
};

Consequences

Positive

  • Enables External Storage Access: Container Apps can now access storage accounts with VNet firewall rules
  • Improved Security: Traffic stays on Azure backbone, never traversing public internet
  • Lower Latency: Direct routing to storage service reduces network hops
  • Future-Proof: Any component needing external storage access will work automatically

Negative

  • Regional Limitation: Service endpoints are regional; cross-region storage access still requires firewall IP rules
  • Additional Configuration: External storage accounts must still have the VNet/subnet in their allowed list

Neutral

  • No impact on storage accounts without firewall rules (public access still works)
  • No impact on the Aspire-managed storage account (uses managed identity, not VNet rules)

Notes

Manual Fix for Existing Deployments

If deploying to an existing environment that doesn't have the service endpoint, run:

az network vnet subnet update \
  --resource-group <resource-group> \
  --vnet-name <vnet-name> \
  --name <subnet-name> \
  --service-endpoints Microsoft.Storage

Then restart the affected containers to pick up the network change.

Storage Account Requirements

For external storage accounts to accept traffic from the Container Apps:

  1. The storage account must have the VNet/subnet in its "Virtual networks" allowed list
  2. The subnet must have the Microsoft.Storage service endpoint enabled
  3. Both conditions must be met - neither alone is sufficient
  • ADR-043: Azure Infrastructure Architecture
  • ADR-044: PostgreSQL Public Access (similar VNet considerations)