Skip to content

Fix ACR pull role assignments for existing registries - #17992

Draft
David Fowler (davidfowl) wants to merge 9 commits into
mainfrom
davidfowl/investigate-acr-role
Draft

Fix ACR pull role assignments for existing registries#17992
David Fowler (davidfowl) wants to merge 9 commits into
mainfrom
davidfowl/investigate-acr-role

Conversation

@davidfowl

Copy link
Copy Markdown
Collaborator

Description

Existing ACA and App Service environment Bicep emitted the AcrPull role assignment inline in the environment module. That fails when the selected ACR is an existing registry in another resource group because Bicep extension resources must be deployed at the target scope.

This moves those grants into generated AzureRoleAssignmentResource modules and teaches AzureResourcePreparer to materialize role-assignment annotations from aggregate owner resources. Environments now own the ACR-pull identity and deployment prerequisites, while WithAcrPullIdentity keeps the BYO identity path from generating extra identity or role resources.

User-facing usage

Existing registry scenarios continue to use the existing APIs:

var acr = builder.AddAzureContainerRegistry("acr")
    .AsExisting(acrName, sharedResourceGroup);

builder.AddAzureContainerAppEnvironment("env")
    .AsExisting(environmentName, environmentResourceGroup)
    .WithAzureContainerRegistry(acr);

The generated Bicep now emits the AcrPull grant as a separate role-assignment module scoped with the registry, so cross-resource-group existing registries no longer fail Bicep validation.

Security considerations

This change preserves the existing AcrPull permission shape but moves where the grant is emitted. It also keeps BYO identities as an explicit opt-out: callers using WithAcrPullIdentity remain responsible for granting AcrPull themselves. Tests cover that aggregate and implied role assignments do not broaden defaults or grant non-referencing resources.

Validation

  • dotnet test --project tests/Aspire.Hosting.Azure.Tests/Aspire.Hosting.Azure.Tests.csproj --no-launch-profile -- --filter-class "*.AzureResourcePreparerTests" --filter-class "*.AzureContainerAppEnvironmentExtensionsTests" --filter-class "*.AzureAppServiceTests" --filter-class "*.AzureContainerAppsTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true" - 191 passed
  • dotnet test --project tests/Aspire.Hosting.Azure.Kubernetes.Tests/Aspire.Hosting.Azure.Kubernetes.Tests.csproj --no-launch-profile -- --filter-class "*.AzureKubernetesFoundryReferenceTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true" - 1 passed
  • dotnet test --project tests/Aspire.Hosting.Foundry.Tests/Aspire.Hosting.Foundry.Tests.csproj --no-launch-profile -- --filter-class "*.HostedAgentExtensionTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true" - 27 passed
  • git diff --check
  • No .received.* snapshot files remain

Fixes #11256

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

Move ACA and App Service environment ACR pull grants into generated AzureRoleAssignmentResource modules so existing registries in other resource groups are scoped correctly. Generalize AzureResourcePreparer so aggregate resources can declare role assignments for internal Azure resources, and expand regression coverage across ACA, App Service, AKS/Foundry, and generated artifacts.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

🚀 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/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 17992

Or

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

David Fowler (davidfowl) and others added 7 commits June 7, 2026 13:58
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

CLI E2E Tests unknown — 113 passed, 0 failed, 2 unknown (commit 01de672)

View all recordings
- Test Detail
AddPackageInteractiveWhileAppHostRunningDetached Recording · Job · CLI logs
AddPackageWhileAppHostRunningDetached Recording · Job · CLI logs
AgentCommands_AllHelpOutputs_AreCorrect Recording · Job · CLI logs
AgentInitCommand_DefaultSelection_InstallsDefaultSkills Recording · Job · CLI logs
AgentInitCommand_MigratesDeprecatedConfig Recording · Job · CLI logs
AgentInit_NonInteractive_BundleOnlySkillsNotInCatalog Recording · Job · CLI logs
AgentMcpListStructuredLogsReturnsLogsFromStarterApp Recording · Job · CLI logs
AgentMcpListStructuredLogsReturnsLogsFromStarterApp_DevLocalhost Recording · Job · CLI logs
AgentMcpListStructuredLogsReturnsLogsFromStarterApp_Isolated Recording · Job · CLI logs
AllPublishMethodsBuildDockerImages Recording · Job · CLI logs
AspireAddAndStartWorkAgainstLegacyAppHostTs Recording · Job · CLI logs
AspireAddPackageVersionToDirectoryPackagesProps Recording · Job · CLI logs
AspireInitSingleFileAppHostRunsViaDotnetRunAppHost Recording · Job · CLI logs
AspireInit_ExistingAppHostDir_RecreatesNuGetConfigKeepsFiles Recording · Job · CLI logs
AspireInit_SolutionFile_BuildsAgainstChannelHive Recording · Job · CLI logs
AspireStartUpdatesStaleTypeScriptAppHostPath Recording · Job · CLI logs
AspireUpdateRemovesAppHostPackageVersionFromDirectoryPackagesProps Recording · Job · CLI logs
AspireUpdateRemovesOrphanAppHostPackageVersionWhenSdkAlreadyCurrent Recording · Job · CLI logs
Banner_DisplayedOnFirstRun Recording · Job · CLI logs
Banner_DisplayedWithExplicitFlag Recording · Job · CLI logs
Banner_NotDisplayedWithNoLogoFlag Recording · Job · CLI logs
CertificatesClean_RemovesCertificates Recording · Job · CLI logs
CertificatesTrust_WithNoCert_CreatesAndTrustsCertificate Recording · Job · CLI logs
CertificatesTrust_WithUntrustedCert_TrustsCertificate Recording · Job · CLI logs
ConfigSetGet_CreatesNestedJsonFormat Recording · Job · CLI logs
CreateAndRunAspireStarterProject Recording · Job · CLI logs
CreateAndRunAspireStarterProjectWithBundle Recording · Job · CLI logs
CreateAndRunEmptyAppHostProject Recording · Job · CLI logs
CreateAndRunJavaEmptyAppHostProject Recording · Job · CLI logs
CreateAndRunJsReactProject Recording · Job · CLI logs
CreateAndRunPolyglotAppHostWithDevLocalhostUrls Recording · Job · CLI logs
CreateAndRunPythonReactProject Recording · Job · CLI logs
CreateAndRunTypeScriptEmptyAppHostProject Recording · Job · CLI logs
CreateAndRunTypeScriptStarterProject Recording · Job · CLI logs
CreateJavaAppHostWithViteApp Recording · Job · CLI logs
CreateTypeScriptAppHostWithViteApp_UsesConfiguredToolchain Recording · Job · CLI logs
DashboardRunWithAgentMcpListTracesReturnsNoTraces Recording · Job · CLI logs
DashboardRunWithAgentMcpListTracesReturnsNoTraces_DevLocalhost Recording · Job · CLI logs
DashboardRunWithOtelTracesReturnsNoTraces Recording · Job · CLI logs
DashboardRunWithOtelTracesReturnsNoTraces_DevLocalhost Recording · Job · CLI logs
DeployK8sBasicApiService Recording · Job · CLI logs
DeployK8sWithExternalHelmChart Recording · Job · CLI logs
DeployK8sWithGarnet Recording · Job · CLI logs
DeployK8sWithMongoDB Recording · Job · CLI logs
DeployK8sWithMySql Recording · Job · CLI logs
DeployK8sWithPostgres Recording · Job · CLI logs
DeployK8sWithRabbitMQ Recording · Job · CLI logs
DeployK8sWithRedis Recording · Job · CLI logs
DeployK8sWithSqlServer Recording · Job · CLI logs
DeployK8sWithValkey Recording · Job · CLI logs
DeployTypeScriptAppToKubernetes Recording · Job · CLI logs
DescribeCommandResolvesReplicaNames Recording · Job · CLI logs
DescribeCommandShowsRunningResources Recording · Job · CLI logs
DetachFormatJsonProducesValidJson Recording · Job · CLI logs
DetachFormatJsonProducesValidJsonWhenRestartingExistingInstance Recording · Job · CLI logs
DoPublishAndDeployListStepsWork Recording · Job · CLI logs
DocsCommand_RendersInteractiveMarkdownFromLocalSource Recording · Job · CLI logs
DoctorCommand_DetectsDeprecatedAgentConfig Recording · Job · CLI logs
DoctorCommand_TypeScriptAppHostReportsMissingConfiguredToolchain Recording · Job · CLI logs
DoctorCommand_WithSslCertDir_ShowsTrusted Recording · Job · CLI logs
DoctorCommand_WithoutSslCertDir_ShowsPartiallyTrusted Recording · Job · CLI logs
DotNetRunFileBasedAppHostUsesAspireCliBundle Recording · Job · CLI logs
DotNetRunProjectAppHostUsesAspireCliBundle Recording · Job · CLI logs
GatewayWithoutExternalEndpoint_FailsPublishWithGuidance Recording · Job · CLI logs
GeneratedAspireDevScript_StartsWatchMode_WithConfiguredToolchain Recording · Job · CLI logs
GlobalMigration_HandlesCommentsAndTrailingCommas Recording · Job · CLI logs
GlobalMigration_HandlesMalformedLegacyJson Recording · Job · CLI logs
GlobalMigration_PreservesAllValueTypes Recording · Job · CLI logs
GlobalMigration_SkipsWhenNewConfigExists Recording · Job · CLI logs
GlobalSettings_MigratedFromLegacyFormat Recording · Job · CLI logs
IngressWithoutExternalEndpoint_FailsPublishWithGuidance Recording · Job · CLI logs
InitTypeScriptAppHost_AugmentsExistingViteRepoInWorkspaceSubdirectory Recording · Job · CLI logs
InteractiveCSharpInitCreatesExpectedFiles Recording · Job · CLI logs
InvalidAppHostPathWithComments_IsHealedOnRun Recording · Job · CLI logs
JavaScriptHostingApisRunFromTypeScriptAppHost Recording · Job · CLI logs
LatestCliCanStartStableChannelAppHost Recording · Job · CLI logs
LatestCliCanStartStableChannelTypeScriptAppHost Recording · Job · CLI logs
LegacySettingsMigration_AdjustsRelativeAppHostPath Recording · Job · CLI logs
LogsCommandShowsResourceLogs Recording · Job · CLI logs
OtelLogsReturnsStructuredLogsFromStarterApp Recording · Job · CLI logs
OtelLogsReturnsStructuredLogsFromStarterAppIsolated Recording · Job · CLI logs
PersistentContainersPreserveDataAcrossAppHostRuns Recording · Job · CLI logs
PsCommandListsRunningAppHost Recording · Job · CLI logs
PsFormatJsonOutputsOnlyJsonToStdout Recording · Job · CLI logs
PublishJavaScriptPatternsGeneratesExpectedDockerComposeArtifacts Recording · Job · CLI logs
PublishWithConfigureEnvFileUpdatesEnvOutput Recording · Job · CLI logs
PublishWithDockerComposeServiceCallbackSucceeds Recording · Job · CLI logs
PublishWithoutOutputPathUsesAppHostDirectoryDefault Recording · Job · CLI logs
ResourceCommand_FailedExec_ShowsLogPathAndLogHasEntries Recording · Job · CLI logs
ResourceCommand_SetAndDeleteParameterUpdatesDescribeOutput Recording · Job · CLI logs
RestoreGeneratesSdkFiles Recording · Job · CLI logs
RestoreGeneratesSdkFiles_WithConfiguredToolchain Recording · Job · CLI logs
RestoreRefreshesGeneratedSdkAfterAddingIntegration Recording · Job · CLI logs
RestoreSupportsConfigOnlyHelperPackageAndCrossPackageTypes Recording · Job · CLI logs
RunFromParentDirectory_UsesExistingConfigNearAppHost Recording · Job · CLI logs
RunReportsSyntaxErrorsForDotNetAppHost Recording · Job · CLI logs
RunReportsSyntaxErrorsForTypeScriptAppHost Recording · Job · CLI logs
SecretCrudOnDotNetAppHost Recording · Job · CLI logs
SecretCrudOnTypeScriptAppHost Recording · Job · CLI logs
StagingChannel_ConfigureAndVerifySettings_ThenSwitchChannels Recording · Job · CLI logs
StartAndWaitForTypeScriptSqlServerAppHostWithNativeAssets Recording · Job · CLI logs
StartReportsSyntaxErrorsForDotNetAppHost Recording · Job · CLI logs
StartReportsSyntaxErrorsForTypeScriptAppHost Recording · Job · CLI logs
StopAllAppHostsFromAppHostDirectory Recording · Job · CLI logs
StopJavaPolyglotAppHostUsingApphostDirectory Recording · Job · CLI logs
StopNonInteractiveSingleAppHost Recording · Job · CLI logs
StopTypeScriptPolyglotAppHostUsingApphostDirectory Recording · Job · CLI logs
StopWithNoRunningAppHostExitsSuccessfully Recording · Job · CLI logs
TypeScriptAppHostRunDoesNotDeadlockWhenLazyOptionsInvokeAsyncCallback Recording · Job · CLI logs
TypeScriptAppHostWithVite_AllowsDifferentGuestPkgManager Recording · Job · CLI logs
UnAwaitedChainsCompileWithAutoResolvePromises Recording · Job · CLI logs
UpdateToStable_CSharpEmptyAppHost_KeepsConfigChannel Recording · Job · CLI logs
UpdateToStable_CSharpSingleFileInit_KeepsConfigChannel Recording · Job · CLI logs
UpdateToStable_TypeScriptSingleFileInit_KeepsConfigChannel Recording · Job · CLI logs
UpdateToStable_TypeScript_PreviewsStablePkgsAndKeepsChannel Recording · Job · CLI logs

📹 Recordings uploaded automatically from CI run #27107572727

@mitchdenny

Copy link
Copy Markdown
Member

Make sure we have an E2E deployment test covering this scenario. We already have some test cases in the K8S tests which pre-provision ACR, we should do a similar thing for this change to make sure we catch changes which break it in the future.

The ACR pull managed identity is now a real {env}-acr-pull-identity model
resource with a separate {env}-roles-{env}-acr role-assignment module
(instead of an inline env_mi identity + inline AcrPull role). That caused
four categories of test failure:

- Race: azure-prepare-resources mutates the model (adds role-assignment
  resources/annotations) while validate-compute-environments enumerates it.
  Both were only ordered against BeforeStart, so they could run concurrently
  ("Collection was modified"). Make prepare depend on validate so validation
  completes (and fails fast) before any mutation.
- Test fake: the separate role module reads the identity's principalId output
  at provision time, but the test provisioner returned empty outputs ("No
  output for principalId"). Synthesize id/clientId/principalId/principalName/
  name for {env}-acr-pull-identity deployments to mirror real Azure UAIs.
- Counts: the env now adds a real AzureUserAssignedIdentityResource plus a
  role module, so AzureUserAssignedIdentityTests collection/count assertions
  were updated to the new topology.
- Snapshots: regenerated 17 Deployer/Environment/Sql .verified snapshots to
  reflect the separate identity + role modules.

All 9 affected classes pass locally (254/254).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 11, 2026 07:03

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes issue #11256 where ACR pull role assignments failed with Bicep error BCP139 when the target Azure Container Registry existed in a different resource group. The root cause was that the generated Bicep emitted role assignments inline in the environment module, but Bicep requires extension resources to be deployed in a separate module when they target a different scope.

Changes:

  • Moves the managed identity creation and AcrPull role assignment out of the environment Bicep module into separate AzureUserAssignedIdentityResource and AzureRoleAssignmentResource modules, allowing cross-resource-group existing registries to work with Bicep's scope rules.
  • Adds a ContainerRegistryRoleAssignmentAnnotation and GeneratedContainerRegistryAnnotation to track auto-generated ACR infrastructure, and updates WithAcrPullIdentity to cleanly remove generated resources when a BYO identity replaces them.
  • Adds a pipeline ordering edge (DependsOnSteps = [ValidateComputeEnvironments]) to AzureResourcePreparer's step to prevent concurrent model mutation during validation.
Show a summary per file
File Description
src/Aspire.Hosting.Azure/RoleAssignmentAnnotation.cs Converts from primary constructor to explicit constructor with null checks
src/Aspire.Hosting.Azure/ContainerRegistryRoleAssignmentAnnotation.cs New annotation declaring ACR role needs for compute environments
src/Shared/GeneratedContainerRegistryAnnotation.cs New shared annotation to track auto-generated container registries
src/Aspire.Hosting.Azure/AzureEnvironmentResource.cs Adds DependsOnSteps on ValidateComputeEnvironments to prevent concurrent mutation
src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppExtensions.cs Major refactoring: removes inline identity/role creation, adds identity & role as separate resources
src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppEnvironmentResource.cs Replaces DefaultContainerRegistry with annotation-based registry tracking and adds deployment prerequisite helpers
src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppEnvironmentAcrPullIdentityAnnotation.cs Adds assignAcrPullRole flag to distinguish generated vs BYO identities
src/Aspire.Hosting.Azure.AppContainers/Aspire.Hosting.Azure.AppContainers.csproj Adds shared file include
src/Aspire.Hosting.Azure.AppService/AzureAppServiceEnvironmentExtensions.cs Parallel refactoring to AppContainers
src/Aspire.Hosting.Azure.AppService/AzureAppServiceEnvironmentResource.cs Parallel refactoring to AppContainers
src/Aspire.Hosting.Azure.AppService/AzureAppServiceEnvironmentAcrPullIdentityAnnotation.cs Parallel to AppContainers annotation
src/Aspire.Hosting.Azure.AppService/Aspire.Hosting.Azure.AppService.csproj Adds shared file include
src/Aspire.Hosting.Azure.Kubernetes/AzureKubernetesEnvironmentResource.cs Replaces DefaultContainerRegistry with annotation-based lookup
src/Aspire.Hosting.Azure.Kubernetes/AzureKubernetesEnvironmentExtensions.cs Uses GeneratedContainerRegistryAnnotation for registry replacement
src/Aspire.Hosting.Azure.Kubernetes/Aspire.Hosting.Azure.Kubernetes.csproj Adds shared file include
tests/Aspire.Hosting.Azure.Tests/AzureResourcePreparerTests.cs Adds 6 new tests for aggregate owner role assignments
tests/Aspire.Hosting.Azure.Tests/AzureUserAssignedIdentityTests.cs Updates assertions for new auto-generated identity/role resources
tests/Aspire.Hosting.Azure.Tests/AzureContainerAppEnvironmentExtensionsTests.cs Updates test to verify role assignment scope for existing registries
tests/Aspire.Hosting.Azure.Tests/AzureAppServiceTests.cs Updates test to verify role assignment scope for existing registries
tests/Aspire.Hosting.Azure.Tests/ProvisioningTestHelpers.cs Synthesizes identity outputs for test deployments
tests/Aspire.Hosting.Azure.Kubernetes.Tests/AzureKubernetesEnvironmentExtensionsTests.cs Updates tests for annotation-based registry tracking
tests/.../*.verified.bicep (many) Snapshot updates reflecting the refactored Bicep structure
tests/.../*.verified.json (many) Snapshot updates reflecting new identity/role resources in manifest
tests/.../*.verified.txt (several) Pipeline dependency graph snapshots reflecting new provisioning steps

Copilot's findings

  • Files reviewed: 85/85 changed files
  • Comments generated: 2

Comment on lines +234 to +267
private IReadOnlySet<AzureBicepResource> GetEnvironmentDeploymentPrerequisites()
{
if (!this.TryGetAnnotationsOfType<DeploymentPrerequisitesAnnotation>(out var prerequisiteAnnotations))
{
return new HashSet<AzureBicepResource>();
}

// The preparer writes environment-owned prerequisites after it materializes generated
// role-assignment modules. Collapse all annotations here so future environment-owned
// infrastructure can participate in the same deployment ordering contract.
return prerequisiteAnnotations.SelectMany(a => a.Resources).ToHashSet();
}

private static void AddDeploymentPrerequisites(IResource resource, IReadOnlySet<AzureBicepResource> prerequisites)
{
if (prerequisites.Count == 0)
{
return;
}

var newPrerequisites = prerequisites.ToHashSet();
if (resource.TryGetAnnotationsOfType<DeploymentPrerequisitesAnnotation>(out var existingAnnotations))
{
// A resource can already have prerequisites from direct Azure references. Only add the
// environment-level resources it does not already wait on to avoid duplicate References
// when deployment targets are generated.
newPrerequisites.ExceptWith(existingAnnotations.SelectMany(a => a.Resources));
}

if (newPrerequisites.Count > 0)
{
resource.Annotations.Add(new DeploymentPrerequisitesAnnotation(newPrerequisites));
}
}
Comment on lines +717 to +790
private static void RemoveGeneratedAcrPullIdentity(IResourceBuilder<AzureContainerAppEnvironmentResource> builder)
{
if (!builder.Resource.TryGetLastAnnotation<AzureContainerAppEnvironmentAcrPullIdentityAnnotation>(out var identityAnnotation) ||
!identityAnnotation.AssignAcrPullRole)
{
return;
}

// This environment owns the generated ACR-pull identity only while Aspire is also responsible
// for granting AcrPull. A BYO identity means the caller owns both the identity and permission,
// so remove only Aspire's generated AppIdentityAnnotation(s) and model resource.
foreach (var appIdentityAnnotation in builder.Resource.Annotations.OfType<AppIdentityAnnotation>()
.Where(a => a.IdentityResource == identityAnnotation.Identity)
.ToArray())
{
builder.Resource.Annotations.Remove(appIdentityAnnotation);
}

// WithAcrPullIdentity means the caller owns the identity and its AcrPull permission. Remove the
// hidden identity from the model; RemoveGeneratedAcrPullRoleAssignment removes the matching
// generated RBAC intent.
builder.ApplicationBuilder.Resources.Remove(identityAnnotation.Identity);
}

private static void RemoveGeneratedAcrPullRoleAssignment(AzureContainerAppEnvironmentResource environment)
{
foreach (var annotation in environment.Annotations.OfType<ContainerRegistryRoleAssignmentAnnotation>().ToArray())
{
environment.Annotations.Remove(annotation);
}
}

private static AzureProvisioningResource GetContainerRegistryForAcrPullRole(AzureContainerAppEnvironmentResource environment)
{
if (environment.TryGetLastAnnotation<ContainerRegistryReferenceAnnotation>(out var registryReferenceAnnotation))
{
if (registryReferenceAnnotation.Registry is AzureProvisioningResource explicitRegistry)
{
return explicitRegistry;
}

throw new InvalidOperationException($"The container registry associated with environment '{environment.Name}' is not an Azure Container Registry.");
}

throw new InvalidOperationException($"No container registry associated with environment '{environment.Name}'. This should have been added automatically.");
}

private static AzureUserAssignedIdentityResource CreateDefaultAcrPullIdentity(IDistributedApplicationBuilder builder, string environmentName)
{
var identity = new AzureUserAssignedIdentityResource(GetUniqueAcrPullIdentityName(builder, environmentName));
// The identity is a first-class resource so the preparer can order it before the environment
// module and pass its id into the environment Bicep as an input parameter.
builder.AddResource(identity);

return identity;
}

private static string GetUniqueAcrPullIdentityName(IDistributedApplicationBuilder builder, string environmentName)
{
var baseName = $"{environmentName}-acr-pull-identity";
if (!builder.Resources.TryGetByName(baseName, out _))
{
return baseName;
}

for (var i = 2; ; i++)
{
var candidate = $"{baseName}-{i}";
if (!builder.Resources.TryGetByName(candidate, out _))
{
return candidate;
}
}
}
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.

Role Assignment for Existing Azure Container Registry Fails Due to Bicep Scope Limitation

3 participants