{"record":{"id":"a6b3ed7716be596c","repo":"microsoft/aspire","slug":"azure-sandbox-group-name-uses-identity-userassignedidentity","errorCode":null,"errorMessage":"Azure sandbox group '{Name}' uses identity '{userAssignedIdentity.Name}' for both image pulls and workload '{resource.Name}'. 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 workload '(.+?)'\\. 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":247,"sourceCode":"            }\n\n            if (resource.TryGetLastAnnotation<AppIdentityAnnotation>(out var appIdentity))\n            {\n                if (appIdentity.IdentityResource is not AzureUserAssignedIdentityResource userAssignedIdentity)\n                {\n                    throw new NotSupportedException(\n                        $\"Compute resource '{resource.Name}' uses an application identity type that Azure sandboxes do not support.\");\n                }\n\n                if (this.IsExisting())\n                {\n                    throw new InvalidOperationException(\n                        $\"Compute resource '{resource.Name}' uses managed identity '{userAssignedIdentity.Name}', but workload identities are not supported when publishing to existing Azure sandbox group '{Name}'.\");\n                }\n\n                if (ReferenceEquals(imagePullIdentity, userAssignedIdentity))\n                {\n                    throw new InvalidOperationException(\n                        $\"Azure sandbox group '{Name}' uses identity '{userAssignedIdentity.Name}' for both image pulls and workload '{resource.Name}'. \" +\n                        \"Use a dedicated image-pull identity so its AcrPull permission is not exposed to sandbox workloads.\");\n                }\n\n                AddWorkloadUserAssignedIdentity(userAssignedIdentity);\n            }\n\n            AzureSandboxContainerDeployment.ValidateSandboxCompatibility(resource);\n\n            resource.Annotations.Add(new ContainerBuildOptionsCallbackAnnotation(static buildOptions =>\n            {\n                // ADC requires a single Docker-format linux/amd64 manifest. Buildx's default OCI\n                // index with provenance attestations can produce a disk image with no bootable root filesystem.\n                buildOptions.Destination = ContainerImageDestination.Registry;\n                buildOptions.OutputPath = null;\n                buildOptions.ImageFormat = ContainerImageFormat.Docker;\n                buildOptions.TargetPlatform = ContainerTargetPlatform.LinuxAmd64;\n            }));","sourceCodeStart":229,"sourceCodeEnd":265,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Azure.Sandboxes/AzureSandboxGroupResource.cs#L229-L265","documentation":"A compute resource's workload identity is the exact same identity instance as the sandbox group's image-pull (AcrPull) identity. Granting AcrPull to that identity and also running workloads under it would expose registry pull permission to sandbox code, so publishing is blocked until a dedicated image-pull identity is provided.","triggerScenarios":"Publishing when ReferenceEquals(imagePullIdentity, userAssignedIdentity) — the AzureSandboxGroupAcrPullIdentityAnnotation identity and the compute resource's AppIdentityAnnotation identity are the same AzureUserAssignedIdentityResource, and the sandbox group is not existing (the earlier existing-group check did not apply).","commonSituations":"Passing the same user-assigned identity to both the sandbox group's image-pull identity option and the workload's WithAppIdentity; constructing one identity resource and reusing it across sandbox-level and compute-level configuration to save a resource.","solutions":["Provision a separate user-assigned managed identity solely for image pulls and set it via the sandbox group's image-pull identity (AcrPull) configuration.","Give the compute resource its own AzureUserAssignedIdentityResource distinct from the image-pull identity.","Search your app model for the identity's resource name and confirm it appears in only one of the two roles (image pull vs workload).","If simplification is the goal, remember the separation is a security boundary: the AcrPull identity must never run workload code."],"exampleFix":"// before\nvar mi = new AzureUserAssignedIdentityResource(\"app-mi\");\nsandboxGroup.WithImagePullIdentity(mi);\ncompute.ConfigureAppIdentity(new AppIdentityAnnotation(mi));\n\n// after\nvar pullMi = new AzureUserAssignedIdentityResource(\"acr-pull-mi\");\nvar appMi = new AzureUserAssignedIdentityResource(\"app-mi\");\nsandboxGroup.WithImagePullIdentity(pullMi);\ncompute.ConfigureAppIdentity(new AppIdentityAnnotation(appMi));","handlingStrategy":"validation","validationCode":"if (ReferenceEquals(pullIdentity, workloadIdentity))\n{\n    throw new InvalidOperationException(\"Image-pull identity must differ from every workload identity.\");\n}","typeGuard":"bool IsDedicatedPullIdentity(AzureUserAssignedIdentityResource pull, AzureUserAssignedIdentityResource workload) => !ReferenceEquals(pull, workload);","tryCatchPattern":"try { publish(); } catch (InvalidOperationException ex) when (ex.Message.Contains(\"for both image pulls and workload\")) { /* create a dedicated AcrPull identity and reconfigure */ }","preventionTips":["Provision a dedicated AcrPull identity per sandbox group as a standard template step.","Never pass the same AzureUserAssignedIdentityResource instance to both sandbox identity options and compute app identity.","Grep the model-building code for each identity resource name to confirm single-role usage."],"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-21T09:17:21.228Z"}