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:
- Pipeline fails during the “Generate infrastructure bicep” step
- Pipeline runs successfully but ingress is set to internal
- Pipeline runs successfully with external ingress, but the API can’t find the HTTPS certificate
Configuration Details
AppHost program.cs Configuration
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 genlocally, 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
WithHttpsEndpointconfiguration, 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?
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
- Why Port 5001 Fails in Pipelines
- Solution Approaches
- Recommended Configuration
- Pipeline-Specific Considerations
- Certificate Management
- Alternative Approaches
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 genmay 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:
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:
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:
// 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();
}
Recommended Configuration
Based on the research findings, here’s the recommended approach:
1. Update Aspire Configuration
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:
// 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:
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:
- 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:
- 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:
- Trust the Azure-managed certificate
- Handle HTTPS redirection properly
Add this to your application startup:
// 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:
- Create an Azure Front Door instance
- Configure a backend pool pointing to your Container Apps
- Set up routing rules to handle HTTPS traffic
- 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:
// 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:
- Update your Aspire configuration to use port 443 for HTTPS endpoints
- Configure certificate trust in your application to work with Azure-managed certificates
- Use environment-specific configurations to handle local vs deployment differences
- 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.