Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 2, 2026

Fix remote environment state authentication for cross-tenant storage accounts

This PR fixes an issue where remote environment state stored in Azure Blob Storage fails with InvalidAuthenticationInfo error when the storage account resides in a different tenant than the user's home tenant.

Changes Made

  1. Added SubscriptionId field to AccountConfig: Users can now specify a subscription ID in their remote state configuration
  2. Updated NewBlobSdkClient: Now accepts account.SubscriptionTenantResolver (existing interface) to resolve the correct tenant for a subscription
  3. Enhanced authentication logic: When a subscription ID is provided, the tenant is resolved from that subscription; otherwise, it defaults to the home tenant
  4. Added comprehensive unit tests: Tests verify correct tenant resolution behavior
  5. Updated all test mocks: Ensured all tests work with the new signature and use the existing account.SubscriptionTenantResolver interface

Usage

Users can now specify a subscription ID in their azure.yaml configuration to access storage accounts in different tenants:

state:
  remote:
    backend: AzureBlobStorage
    config:
      accountName: myaccount01
      subscriptionId: "your-subscription-id"  # Optional: specify when storage is in a different tenant

When subscriptionId is not provided, the system uses the home tenant (backward compatible).

Code Review Feedback Addressed

  • Removed duplicate SubscriptionTenantResolver interface and use existing account.SubscriptionTenantResolver instead
  • Replaced github.com/pkg/errors with standard library errors package
  • Cleaned up dependencies with go mod tidy

Plan

  • Understand the current implementation and issue
  • Update AccountConfig to support subscriptionId field
  • Update NewBlobSdkClient to accept SubscriptionTenantResolver
  • Modify credential resolution to use subscription's tenant when subscriptionId is provided
  • Update dependency injection container registration (auto-wired via IoC)
  • Update tests to work with new signature
  • Run linters and formatting
  • Add unit tests for the new functionality
  • Run targeted tests to validate changes
  • Security scan with CodeQL (passed - 0 alerts)
  • Code review (addressed all comments)
  • Use existing account.SubscriptionTenantResolver instead of duplicate
  • Remove pkg/errors dependency and use standard library

Security Summary

CodeQL security scan completed with 0 alerts - no security vulnerabilities introduced.

Original prompt

This section details on the original issue you should resolve

<issue_title>[Issue] Remote end - InvalidAuthenticationInfo</issue_title>
<issue_description>- [x] Make sure you've installed the latest version using instructions in the wiki

Output from azd version
azd version 1.8.1

Describe the bug

Configured remote env state like this (also tried to define the containerName)

name: azd-poc
state:
  remote:
    backend: AzureBlobStorage
    config:
      accountName: myaccount01
      # containerName: azd # Defaults to project name if not specified

And following error is returned:

ERROR: loading environment: checking for existing environment: listing blobs: failed getting next page of containers: GET https://myaccount01.blob.core.windows.net
--------------------------------------------------------------------------------
RESPONSE 401: 401 Server failed to authenticate the request. Please refer to the information in the www-authenticate header.
ERROR CODE: InvalidAuthenticationInfo
--------------------------------------------------------------------------------
<?xml version="1.0" encoding="utf-8"?><Error><Code>InvalidAuthenticationInfo</Code><Message>Server failed to authenticate the request. Please refer to the information in the www-authenticate header.
RequestId:41af17c6-901e-0024-57ae-9985a6000000
Time:2024-04-28T20:54:57.4081095Z</Message><AuthenticationErrorDetail>Issuer validation failed. Issuer did not match.</AuthenticationErrorDetail></Error>
--------------------------------------------------------------------------------

To Reproduce
Using terraform-starter template

Expected behavior
This should work.
I'm Owner of the Subscription, also have RBAC roles Storage Blob Data Owner and tried to add Storage Blob Data Contributor just to be on the safe side

Environment
Information on your environment:
* IaC Only
* VS Code with freshly build GH Codespaces (Ubuntu:jammy)

Additional Context
I found this issue related to failing test > #3669
I assume the issue was not the test, but the AZD code and the test failed due to issue i'm facing now
</issue_description>

<agent_instructions>Look and find the implementation for remote env and check if it is using a credential using the same tenant-id as the user's home tenant, causing the issue where the account is not in the user's home tenant. Fix it by supporting subscriptionId next to the accountName config for the remote settings. When no subscriptionId is provided, use the user's home tenant id, otherwise, if the subscriptionId is defined, use it to resolve the tenant-id where the subscription is and when asking for auth-tokens with the credential</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@rajeshkamal5050 @wbreza can you take a look? @wbreza @petr-stupka Based on your configuration it looks like you are attempting to use the AZD remote state configuration also as your remote storage configuration for terraform.

There isn't any reason you could not use the same Azure storage account for both Terraform remote state and AZD remote environment state but right now this would require a bit more configuration.

Take a look at the Terraform configuration feature docs which outlines the required environment variables that you will need to set.

If you also want to use AZD remote environments take a look at the Remote environments feature docs.

@wbreza @petr-stupka You shouldn't need to use the legacy `useAzCliAuth`. As long as your storage account configuration set in your `azure.yaml` and have [Storage Blob Data Contributor](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles/storage#storage-blob-data-contributor) role on the storage account you should be good to go. Let me know if you are seeing otherwise. @HadwaAbdelhalem still hitting this error when trying to configure azd remote env. @HadwaAbdelhalem For me, IT was due to enforced policies on my test subscription. Once I updated that It worked as expected @rajeshkamal5050 > @petr-stupka You shouldn't need to use the legacy `useAzCliAuth`. As long as your storage account configuration set in your `azure.yaml` and have [Storage Blob Data Contributor](https://learn.microsoft.com/en-us/azure/role-based-access-control/...

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 4 commits January 3, 2026 00:05
…nant authentication

Co-authored-by: vhvb1989 <24213737+vhvb1989@users.noreply.github.com>
Co-authored-by: vhvb1989 <24213737+vhvb1989@users.noreply.github.com>
…mock

Co-authored-by: vhvb1989 <24213737+vhvb1989@users.noreply.github.com>
Co-authored-by: vhvb1989 <24213737+vhvb1989@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix remote end invalid authentication issue Support cross-tenant authentication for remote environment state in Azure Blob Storage Jan 3, 2026
Copilot AI requested a review from vhvb1989 January 3, 2026 00:16
@vhvb1989 vhvb1989 marked this pull request as ready for review January 3, 2026 00:54
Copilot AI review requested due to automatic review settings January 3, 2026 00:54
@vhvb1989
Copy link
Member

vhvb1989 commented Jan 3, 2026

/azp run azure-dev - cli

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

Copy link
Contributor

Copilot AI left a comment

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 adds support for cross-tenant authentication when accessing Azure Blob Storage for remote environment state. It addresses an issue where users received InvalidAuthenticationInfo errors when their storage account resided in a different tenant than their home tenant. The solution introduces an optional subscriptionId field to the remote state configuration, which enables tenant resolution for cross-tenant scenarios.

Key Changes:

  • Added SubscriptionId field to AccountConfig struct for optional subscription-based tenant resolution
  • Enhanced NewBlobSdkClient to accept a SubscriptionTenantResolver and resolve the tenant from subscription ID when provided
  • Added comprehensive unit tests covering tenant resolution scenarios (home tenant fallback, successful resolution, and error handling)

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
cli/azd/pkg/azsdk/storage/storage_blob_client.go Added SubscriptionTenantResolver interface and SubscriptionId field to AccountConfig; implemented tenant resolution logic in NewBlobSdkClient
cli/azd/pkg/azsdk/storage/storage_blob_client_test.go Added three unit tests verifying tenant resolution behavior for different scenarios
cli/azd/test/functional/remote_state_test.go Updated test helper to provide mock SubscriptionTenantResolver to NewBlobSdkClient
cli/azd/pkg/environment/manager_test.go Added mock SubscriptionTenantResolver registration in test container setup
cli/azd/go.mod Moved pkg/errors from indirect to direct dependencies; removed unused packages
cli/azd/go.sum Updated checksums reflecting dependency changes

"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/azure/azure-dev/cli/azd/pkg/cloud"
"github.com/pkg/errors"
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

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

The pkg/errors import is only used once in this test file (line 138) and introduces an unnecessary third-party dependency. Use the standard library errors package instead for new code, which has been sufficient since Go 1.13.

Suggested change
"github.com/pkg/errors"
"errors"

Copilot uses AI. Check for mistakes.
cli/azd/go.mod Outdated
github.com/moby/patternmatcher v0.6.0
github.com/nathan-fiscaletti/consolesize-go v0.0.0-20220204101620-317176b6684d
github.com/otiai10/copy v1.14.1
github.com/pkg/errors v0.9.1
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

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

The github.com/pkg/errors package should not be added as a direct dependency. It's only used in a test file (storage_blob_client_test.go:138) and goes against modern Go best practices. Since Go 1.13, the standard library provides equivalent error handling capabilities. Remove this from the direct dependencies or better yet, update the test to use the standard errors package.

Suggested change
github.com/pkg/errors v0.9.1

Copilot uses AI. Check for mistakes.
Comment on lines 20 to 25
// SubscriptionTenantResolver allows resolving the correct tenant ID
// that allows the current account access to a given subscription.
type SubscriptionTenantResolver interface {
// Resolve the tenant ID required by the current account to access the given subscription.
LookupTenant(ctx context.Context, subscriptionId string) (tenantId string, err error)
}
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

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

This interface is a duplicate of the existing account.SubscriptionTenantResolver interface defined in cli/azd/pkg/account/subscriptions_manager.go. Creating duplicate interfaces reduces maintainability and creates confusion. Instead, import and use account.SubscriptionTenantResolver directly. The IoC container already has a registration for this interface at cli/azd/cmd/container.go:651-653 that converts *account.SubscriptionsManager to account.SubscriptionTenantResolver.

Copilot uses AI. Check for mistakes.
Comment on lines +137 to +138
mockTenantResolver.On("LookupTenant", mock.Anything, testSubscriptionId).
Return("", errors.New("subscription not found"))
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

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

Using the third-party github.com/pkg/errors package for new code goes against modern Go best practices. Since Go 1.13, the standard library's errors package and fmt.Errorf with %w provide equivalent functionality. For consistency and to avoid unnecessary dependencies, use errors.New("subscription not found") instead, and import the standard errors package.

Copilot uses AI. Check for mistakes.
@vhvb1989
Copy link
Member

vhvb1989 commented Jan 3, 2026

@copilot implemente changes from #6441 (review)

… and standard errors package

Co-authored-by: vhvb1989 <24213737+vhvb1989@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jan 3, 2026

@copilot implemente changes from #6441 (review)

Changes implemented in commit f961b76:

  • Removed duplicate SubscriptionTenantResolver interface and now use account.SubscriptionTenantResolver
  • Replaced github.com/pkg/errors with standard library errors package
  • Updated all test files to use the existing interface
  • Cleaned up dependencies with go mod tidy

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.

[Issue] Remote end - InvalidAuthenticationInfo

2 participants