{"record":{"id":"91e380eec191fead","repo":"microsoft/aspire","slug":"azure-sandbox-group-name-uses-identity-imagepullidentity","errorCode":null,"errorMessage":"Azure sandbox group '{Name}' uses identity '{imagePullIdentity.Name}' for both image pulls and workloads. Use a dedicated image-pull identity so its AcrPull permission is not exposed to sandbox workloads.","messagePattern":"Azure sandbox group '(.+?)' uses identity '(.+?)' for both image pulls and workloads\\. Use a dedicated image-pull identity so its AcrPull permission is not exposed to sandbox workloads\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Azure.Sandboxes/AzureSandboxGroupResource.cs","lineNumber":205,"sourceCode":"            return;\n        }\n\n        if (this.HasAnnotationOfType<ContainerRegistryReferenceAnnotation>() &&\n            DefaultContainerRegistry is not null)\n        {\n            context.Model.Resources.Remove(DefaultContainerRegistry);\n            DefaultContainerRegistry = null;\n        }\n\n        var containerRegistry = ContainerRegistry ??\n            throw new InvalidOperationException($\"No container registry associated with Azure sandbox group '{Name}'. This should have been added automatically.\");\n        var imagePullIdentity = this.TryGetLastAnnotation<AzureSandboxGroupAcrPullIdentityAnnotation>(out var imagePullIdentityAnnotation)\n            ? imagePullIdentityAnnotation.Identity\n            : null;\n\n        if (imagePullIdentity is not null && WorkloadUserAssignedIdentities.Contains(imagePullIdentity))\n        {\n            throw new InvalidOperationException(\n                $\"Azure sandbox group '{Name}' uses identity '{imagePullIdentity.Name}' for both image pulls and workloads. \" +\n                \"Use a dedicated image-pull identity so its AcrPull permission is not exposed to sandbox workloads.\");\n        }\n\n        var computeEnvironments = context.Model.Resources.OfType<IComputeEnvironmentResource>().ToList();\n        var canClaimUnassignedComputeResources = computeEnvironments.Count == 1 && ReferenceEquals(computeEnvironments[0], this);\n\n        foreach (var resource in context.Model.GetComputeResources())\n        {\n            var resourceComputeEnvironment = resource.GetComputeEnvironment();\n            if (resourceComputeEnvironment is null && !canClaimUnassignedComputeResources)\n            {\n                continue;\n            }\n\n            if (resourceComputeEnvironment is not null && resourceComputeEnvironment != this)\n            {\n                continue;","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Azure.Sandboxes/AzureSandboxGroupResource.cs#L187-L223","documentation":"The identity designated for pulling container images from the registry (with AcrPull) is also listed as a workload identity of the sandbox group. Because workload code could run under that identity and gain registry pull (and potentially sensitive registry) access, the library refuses to publish until a dedicated image-pull identity is used.","triggerScenarios":"Publishing when the AzureSandboxGroupAcrPullIdentityAnnotation identity is contained in WorkloadUserAssignedIdentities — e.g. the same user-assigned managed identity was supplied both as the AcrPull identity (via the sandbox group's image-pull identity configuration) and as the app identity of a compute resource.","commonSituations":"Reusing one managed identity for everything in the sandbox group to simplify setup; copying the same identity resource into PublishAsAzureSandbox identity options and the compute resource's WithAppIdentity/ConfigureAppIdentity; sharing a pre-existing identity across sandbox-level and workload-level configuration.","solutions":["Create a separate user-assigned managed identity exclusively for image pulls and configure it as the sandbox group's AcrPull identity.","Ensure each compute resource's app identity is a distinct identity not referenced by the AzureSandboxGroupAcrPullIdentityAnnotation.","Audit your publish model for identity reuse: list the sandbox group's image-pull identity and every workload identity and confirm there is no overlap.","If using an existing identity everywhere, provision a second identity and grant only it the AcrPull role on the registry."],"exampleFix":"// before\nvar shared = new AzureUserAssignedIdentityResource(\"shared-mi\");\nsandboxGroup.WithImagePullIdentity(shared);\ncompute.WithAppIdentity(shared);\n\n// after\nvar pullIdentity = new AzureUserAssignedIdentityResource(\"acr-pull-mi\");\nsandboxGroup.WithImagePullIdentity(pullIdentity);\ncompute.WithAppIdentity(new AzureUserAssignedIdentityResource(\"workload-mi\"));","handlingStrategy":"validation","validationCode":"var pull = sandboxGroup.GetImagePullIdentity(); // via AzureSandboxGroupAcrPullIdentityAnnotation\nif (pull is not null && sandboxGroup.WorkloadUserAssignedIdentities.Contains(pull))\n{\n    throw new InvalidOperationException(\"Image-pull identity must be distinct from workload identities.\");\n}","typeGuard":"var pullIdentity = resource.TryGetLastAnnotation<AzureSandboxGroupAcrPullIdentityAnnotation>(out var a) ? a.Identity : null;","tryCatchPattern":"try { publish(); } catch (InvalidOperationException ex) when (ex.Message.Contains(\"for both image pulls and workloads\")) { /* provision a dedicated AcrPull identity and update options */ }","preventionTips":["Keep one identity per purpose: one for AcrPull, one per workload.","Name identities explicitly (e.g. acr-pull-mi vs app-mi) to avoid accidental reuse.","Review identity configuration in PublishAsAzureSandbox options and WithAppIdentity calls together during code review."],"tags":["azure","sandbox-group","managed-identity","security","publish"],"backgroundTag":"conflicting-config-options","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}