Skip to content

Implemented abac support for tag and manifest'#599

Draft
keithy1012 wants to merge 2 commits intoAzure:mainfrom
keithy1012:t-keithyao/abac-support-manifest-and-tag
Draft

Implemented abac support for tag and manifest'#599
keithy1012 wants to merge 2 commits intoAzure:mainfrom
keithy1012:t-keithyao/abac-support-manifest-and-tag

Conversation

@keithy1012
Copy link
Contributor

Purpose of the PR

  • Adds ABAC support for acr tag list, acr tag delete, acr manifest list, and acr manifest delete commands. These commands currently fail with a 401 unauthorized error on ABAC-enabled registries because newAcrCLIClientWithBearerAuth requests the wildcard scope repository::, which ABAC registries silently ignore. Since these commands already know the target repository, we detect ABAC registries using the aad_identity JWT claim and request a repo-scoped token instead.

Fixes #

  • internal/api/acrsdk.go: Added hasAadIdentityClaim() for ABAC detection. Updated GetAcrCLIClientWithAuth and newAcrCLIClientWithBearerAuth to accept repoName and request repo-scoped tokens for ABAC registries.
  • cmd/acr/tag.go: Pass repoName to GetAcrCLICLientWithAuth in tag list and delete.
  • cmd/acr/manifest.go: Pass repoName to GetAcrCLIClientWithAuth in manifest list and manifest delete.
  • internal/api/acrsdk_test.go: Updated GetAcrCLIClientWithAuth signatures in test

@keithy1012 keithy1012 force-pushed the t-keithyao/abac-support-manifest-and-tag branch from 631fe4a to 9179528 Compare March 10, 2026 17:27
cmd/acr/tag.go Outdated
loginURL := api.LoginURL(registryName)
// An acrClient is created to make the http requests to the registry.
acrClient, err := api.GetAcrCLIClientWithAuth(loginURL, tagParams.username, tagParams.password, tagParams.configs)
acrClient, err := api.GetAcrCLIClientWithAuth(loginURL, tagParams.username, tagParams.password, tagParams.configs, tagParams.repoName)
Copy link
Member

Choose a reason for hiding this comment

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

Instead of updating newAcrCLIClientWithBearerAuth and GetAcrCLIClientWithAuth with some duplicate ABAC logic that already exists in RefreshTokenForAbac, can we simplify this by keeping GetAcrCLIClientWithAuth with its original signature, and have the tag/manifest commands call RefreshTokenForAbac after client creation (the same pattern purge already uses)?

like:

// In tag.go / manifest.go:
acrClient, err := api.GetAcrCLIClientWithAuth(loginURL, params.username, params.password, params.configs)
if err != nil {
    return err
}
// For ABAC registries, scope the token to the target repository.
if acrClient.IsAbac() {
    if err := acrClient.RefreshTokenForAbac(context.Background(), []string{params.repoName}); err != nil {
        return err
    }
}

loginURL := api.LoginURL(registryName)
// An acrClient with authentication is generated, if the authentication cannot be resolved an error is returned.
acrClient, err := api.GetAcrCLIClientWithAuth(loginURL, annotateParams.username, annotateParams.password, annotateParams.configs)
acrClient, err := api.GetAcrCLIClientWithAuth(loginURL, annotateParams.username, annotateParams.password, annotateParams.configs, "")
Copy link
Member

Choose a reason for hiding this comment

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

I reviewed the cssc and annotate commands, both also call GetAcrTags acorss multiple repositories, so they are have the same ABAC gap and would need the same batch pattern as purge command. That's a larger change though, and cssc command is still in preview. Let's keep this PR focused on tag and manifest command. I will create a separate work item to track ABAC support for annotate and cssc

Copy link
Member

@lizMSFT lizMSFT left a comment

Choose a reason for hiding this comment

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

overall lgtm. please add the unit tests for the tag and manifest ABAC code path

}
// For ABAC registries, scope the token to the target repository.
if acrClient.IsAbac() {
if err := acrClient.RefreshTokenForAbac(context.Background(), []string{manifestParams.repoName}); err != nil {
Copy link
Member

Choose a reason for hiding this comment

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

nit: the context.Background() is redundant here, move the ctx declaration above the ABAC block and reuse it (same in all 4 call sites)
reference: https://github.com/Azure/acr-cli/blob/main/cmd/acr/purge.go#L133C1-L134C1

func refreshAcrCLIClientToken(ctx context.Context, c *AcrCLIClient, repoName string) error {
var scope string
if c.isAbac {
// For ABAC registries, build scope from currentRepositories and ensure repoName is included
Copy link
Member

Choose a reason for hiding this comment

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

Let's still keep the comment here

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.

2 participants