NeuroAgent

Fix Azure Developer CLI Bicep Error in Pipelines

Fix Azure Developer CLI Bicep validation errors when deploying .NET Aspire projects in pipelines. Learn why port 5001 fails and how to configure HTTPS endpoints correctly for Azure Container Apps.

Why does Azure Developer CLI report invalid Bicep for my .NET Aspire project when running in pipelines?

I’m experiencing an issue with Azure Developer CLI when deploying my .NET Aspire project through Azure DevOps Pipelines. The pipeline fails during the “Generate infrastructure bicep” step with the following error:

ERROR: generating infra/ folder: configuring ingress for resource eriksens-api: Binding https can't be mapped to main ingress because it has port 5001 defined. main ingress only supports port 443 for https scheme.

Problem Description

My goal is to run the pipeline whenever a trigger occurs, generate the infrastructure, provision it, deploy the applications in my .NET Aspire project to Azure Container Apps (ACA), and configure external ingress.

I’m encountering three different scenarios:

  1. Pipeline fails during the “Generate infrastructure bicep” step
  2. Pipeline runs successfully but ingress is set to internal
  3. Pipeline runs successfully with external ingress, but the API can’t find the HTTPS certificate

Configuration Details

AppHost program.cs Configuration

csharp
var externalApi = builder.AddProject<Projects.Eriksens_Api_EriksenExternal>(ServiceNames.EriksensExternalApiServiceName)
    .WithExternalHttpEndpoints()
    .AddCustomEnvironmentVariables();

// In non-local environments:
externalApi
    .WithHttpsEndpoint(port: 5001, targetPort: 8080)
    .WithExternalHttpEndpoints();

Pipeline Configuration

The pipeline uses Azure Developer CLI (azd) version 1.20.3 and includes these key steps:

  • Install azd
  • Configure authentication
  • Generate infrastructure bicep (where the error occurs)
  • Provision infrastructure
  • Deploy application

Observed Behavior

  • When running azd infra gen locally, it works without issues
  • When running in pipelines, it fails with the port 5001 error
  • If I change the port to 443 as suggested by the error, the application can’t find the certificate
  • If I remove the WithHttpsEndpoint configuration, it deploys but with internal ingress

Question

What is causing Azure Developer CLI to report invalid Bicep when using port 5001 for HTTPS endpoints in pipeline environments, and how can I configure my .NET Aspire project to work correctly with external ingress and HTTPS in Azure DevOps Pipelines?

NeuroAgent

The Azure Developer CLI reports invalid Bicep for your .NET Aspire project in pipelines because Azure Container Apps ingress only supports port 443 for HTTPS traffic, but your configuration uses port 5001. This constraint is enforced during Bicep generation in pipeline environments where validation is stricter than in local development.

Contents

Understanding the Root Cause

The core issue stems from Azure Container Apps (ACA) ingress architecture. As Microsoft Learn documentation explains, “Your application ingress endpoint is always exposed on port 443.” This is a fundamental constraint of the Azure platform - HTTPS traffic must terminate on port 443 at the load balancer level.

When your .NET Aspire configuration specifies WithHttpsEndpoint(port: 5001, targetPort: 8080), Azure Developer CLI attempts to generate Bicep that maps HTTPS traffic from port 5001 to your application’s target port 8080. However, Azure Container Apps ingress doesn’t support custom HTTPS ports - it only accepts traffic on port 443 and forwards it to your specified target port.

Why Port 5001 Fails in Pipelines

The behavior differs between local development and pipeline environments due to validation contexts:

  • Local Development: azd infra gen may be more permissive during local testing
  • Pipeline Environments: The Azure Developer CLI performs stricter validation to ensure deployment will succeed in Azure

As shown in the Stack Overflow discussion, when users try to use port 5001, they get the exact error you’re experiencing: “Binding https can’t be mapped to main ingress because it has port 5001 defined. main ingress only supports port 443 for https scheme.”


Solution Approaches

Option 1: Use Port 443 with Proper Configuration

The most straightforward solution is to modify your configuration to use port 443:

csharp
externalApi
    .WithHttpsEndpoint(port: 443, targetPort: 8080)
    .WithExternalHttpEndpoints();

However, as you’ve discovered, this can lead to certificate issues because Azure automatically manages certificates for port 443, and your application needs to be configured to trust the Azure-managed certificate.

Option 2: Configure External Ingress in Bicep

Manually configure the ingress to be external and let Azure handle the HTTPS termination:

bicep
resource containerApp 'Microsoft.App/containerApps@2023-05-01' = {
  name: appName
  location: location
  properties: {
    configuration: {
      ingress: {
        external: true
        targetPort: 8080
        allowInsecure: false // Ensure HTTPS only
      }
    }
    template: {
      containers: [{
        name: containerName
        image: image
      }]
    }
  }
}

Option 3: Environment-Specific Configuration

Use different configurations for local and deployment environments:

csharp
// In Program.cs
if (builder.Environment.IsProduction())
{
    externalApi
        .WithHttpsEndpoint(port: 443, targetPort: 8080)
        .WithExternalHttpEndpoints();
}
else
{
    // Local development configuration
    externalApi
        .WithHttpsEndpoint(port: 5001, targetPort: 8080)
        .WithExternalHttpEndpoints();
}

Based on the research findings, here’s the recommended approach:

1. Update Aspire Configuration

csharp
var externalApi = builder.AddProject<Projects.Eriksens_Api_EriksenExternal>(ServiceNames.EriksensExternalApiServiceName)
    .WithExternalHttpEndpoints()
    .AddCustomEnvironmentVariables();

// Configure for Azure deployment
externalApi
    .WithHttpsEndpoint(port: 443, targetPort: 8080)
    .WithExternalHttpEndpoints();

2. Configure Certificate Trust

Modify your application to trust Azure-managed certificates by adding to your Program.cs:

csharp
// For Azure Container Apps
if (builder.Environment.IsProduction())
{
    builder.Services.Configure<HttpsConnectionFilterOptions>(options =>
    {
        options.AllowedServerCertificates.Add(new X509Certificate2());
    });
}

3. Update Pipeline Configuration

Ensure your pipeline uses the correct azd version and authentication:

yaml
 steps:
 - task: AzureCLI@2
   inputs:
     azureSubscription: 'your-connection'
     scriptType: 'pscore'
     scriptLocation: 'inlineScript'
     inlineScript: |
       azd auth login --use-device-code
       azd pipeline provision --no-prompt

Pipeline-Specific Considerations

Authentication Issues

As noted in the GitHub issue, pipeline authentication can be problematic. Ensure your pipeline properly authenticates with Azure:

yaml
- task: AzureKeyVault@2
  inputs:
    azureSubscription: 'your-connection'
    KeyVaultName: 'your-keyvault'
    SecretsFilter: '*'

Bicep Generation

The error occurs during azd infra gen, which validates the generated Bicep against Azure constraints. Consider adding pipeline-specific configuration:

yaml
- script: |
    azd config set defaults.location eastus
    azd config set defaults.resourceGroup your-resource-group
    azd infra gen

Certificate Management

When using port 443, Azure automatically provisions and manages TLS certificates for your Container Apps. However, your application needs to be configured to:

  1. Trust the Azure-managed certificate
  2. Handle HTTPS redirection properly

Add this to your application startup:

csharp
// Program.cs
if (builder.Environment.IsProduction())
{
    app.UseHsts();
    app.UseHttpsRedirection();
    
    // Configure to trust Azure-managed certificates
    builder.Services.AddHttpClient()
        .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
        {
            ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true
        });
}

Alternative Approaches

Using Azure Front Door

For more complex scenarios, consider using Azure Front Door to handle HTTPS termination and route traffic to your Container Apps:

  1. Create an Azure Front Door instance
  2. Configure a backend pool pointing to your Container Apps
  3. Set up routing rules to handle HTTPS traffic
  4. Update your Aspire configuration to use internal endpoints

Manual Bicep Template Override

You can override the generated Bicep template by creating a custom template in your infra folder:

bicep
// infra/override/main.bicep
@override('Microsoft.App/containerApps@2023-05-01')
resource containerApp 'Microsoft.App/containerApps@2023-05-01' = {
  // Your custom configuration
  properties: {
    configuration: {
      ingress: {
        external: true
        targetPort: 8080
        transport: 'http'
        allowInsecure: false
      }
    }
  }
}

Conclusion

The Azure Developer CLI reports invalid Bicep because Azure Container Apps ingress only supports port 443 for HTTPS traffic. To resolve this:

  1. Update your Aspire configuration to use port 443 for HTTPS endpoints
  2. Configure certificate trust in your application to work with Azure-managed certificates
  3. Use environment-specific configurations to handle local vs deployment differences
  4. Ensure proper pipeline authentication and configuration

The key takeaway is that Azure Container Apps has strict ingress requirements that differ from local development environments. By aligning your configuration with these constraints and properly handling certificate management, you can successfully deploy .NET Aspire projects with external HTTPS access through Azure DevOps Pipelines.

Sources

  1. Stack Overflow - Azure Developer CLI Bicep validation error
  2. Microsoft Learn - Configure Ingress for Azure Container Apps
  3. Microsoft Learn - Customize .NET Aspire Azure deployments
  4. GitHub Issue - .NET Aspire Azure CI/CD pipeline issues
  5. Microsoft Learn - Deploy .NET Aspire with Azure Developer CLI