Skip to content

Support Azure CLI (az) version 2.73.0 and newer.#55374

Merged
gabrielcorado merged 5 commits intomasterfrom
gabrielcorado/tsh-az-login-resource
Jun 3, 2025
Merged

Support Azure CLI (az) version 2.73.0 and newer.#55374
gabrielcorado merged 5 commits intomasterfrom
gabrielcorado/tsh-az-login-resource

Conversation

@gabrielcorado
Copy link
Copy Markdown
Contributor

@gabrielcorado gabrielcorado commented Jun 2, 2025

Related to #55298

After version 2.73.0 of the az (Azure CLI), the managed identity flows were updated to use Microsoft Authentication Library (MSAL) by default.

Effective for our usage, that meant two breaking changes happened:

  • The az login --username/-u flag was deprecated when using managed identities (--identity). We should use --resource-id instead.
  • MSI is no longer used when only MSI_ENDPOINT is set, instead it also requires a MSI_SECRET set, however the new implementation is not backwards compatible and lacks documentation. Instead of using MSI endpoint, we can rely in the Identity (App Service) endpoint which is better documented and supported (for example, by Azure functions). This API works the same way as the MSI one, with the exception of a few fields that were renamed.
❯ tsh apps login azure-cli --azure-identity=azure-identity

Passing the managed identity ID with --username is no longer supported. Use --client-id, --object-id or --resource-id instead.
ERROR: exit status 1

ERROR: failed to automatically login with `az login` using identity "/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/rg/providers/microsoft.managedidentity/userassignedidentities/azure-identity"; run with --debug for details
        exit status 1

To support the newer version of az CLI, we've updated:

  • Use the --resource-id flag when on a newer version of the CLI. Otherwise, fallback into using the --username/-u flag.
  • Update the AzureMSIMiddleware (renamed to AzureTokenMiddleware) to be able to process Identity endpoint requests. There was no flow change, only a few fields changed and tests were added.
❯ tsh apps login azure-cli --azure-identity=azure-identity
[
  {
    "environmentName": "AzureCloud",
    "homeTenantId": "00000000-0000-0000-0000-000000000000",
    "id": "00000000-0000-0000-0000-000000000000",
    "isDefault": true,
    "managedByTenants": [],
    "name": "Subscription",
    "state": "Enabled",
    "tenantId": "00000000-0000-0000-0000-000000000000",
    "user": {
      "assignedIdentityInfo": "MSIResource-/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/rg/providers/microsoft.managedidentity/userassignedidentities/azure-identity",
      "name": "userAssignedIdentity",
      "type": "servicePrincipal"
    }
  }
]
Logged into Azure app "azure-cli".
Your identity: /subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/rg/providers/microsoft.managedidentity/userassignedidentities/azure-identity
Example Azure CLI command: tsh az vm list

Most of this PR changes are in the test files, which were updated to test the usage of both MSI and Identity endpoints.

changelog: Added support to tsh App Access commands for Azure CLI (az) version 2.73.0 and newer.

@github-actions github-actions Bot requested review from atburke and fspmarshall June 2, 2025 21:22
@github-actions github-actions Bot added application-access size/md tsh tsh - Teleport's command line tool for logging into nodes running Teleport. labels Jun 2, 2025
@greedy52 greedy52 requested review from Tener and marcoandredinis and removed request for atburke, fspmarshall and marcoandredinis June 2, 2025 22:42
Copy link
Copy Markdown
Contributor

@Tener Tener left a comment

Choose a reason for hiding this comment

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

A few minor items.

}

func (m *AzureMSIMiddleware) msiEndpoint(rw http.ResponseWriter, req *http.Request) error {
func (m *AzureTokenMiddleware) handleEndpoint(rw http.ResponseWriter, req *http.Request, identityRequest bool) error {
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.

As far as I can tell identityRequest is true when we are serving the updated protocol. The name doesn't quite reflect that, so perhaps we can rename is slightly to clarify that fact and add a comment about it as well.

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.

alternatively, for better readability, avoid the bool and make two separate functions like handleMSIEndpoint, handleIdentityEndpoint.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've updated this function to receive the field name and secret, so we don't need any conditions for this function.

Comment thread lib/srv/alpnproxy/azure_token_middleware_test.go
Comment thread tool/tsh/common/app.go Outdated
Comment thread tool/tsh/common/app_azure.go Outdated
}

endpoint := os.Getenv("MSI_ENDPOINT")
if endpoint == "" {
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.

Should we look for IDENTITY_ENDPOINT too? I know we will overwrite it, but perhaps checking its existence might be worth it for debugging purposes?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Having only IDENTITY_HEADER set shouldn't be effective (as per MSAL definition). So I updated this function to follow this too.

Comment thread tool/tsh/common/app_azure.go Outdated
Copy link
Copy Markdown
Contributor

@greedy52 greedy52 left a comment

Choose a reason for hiding this comment

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

Thanks for the quick fix! lets also update the docs (here or separately)

}

func (m *AzureMSIMiddleware) msiEndpoint(rw http.ResponseWriter, req *http.Request) error {
func (m *AzureTokenMiddleware) handleEndpoint(rw http.ResponseWriter, req *http.Request, identityRequest bool) error {
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.

alternatively, for better readability, avoid the bool and make two separate functions like handleMSIEndpoint, handleIdentityEndpoint.

Comment thread lib/web/app/transport.go
Comment on lines +292 to +293
// TODO(gabrielcorado): use the cluster name. This value must match the
// one used by the proxy.
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.

i doubt we will ever fix this. if we do, how do we plan to preserve backwards compatibility? is this jwt verification even necessary?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I haven't looked into too many details on this, either. I just updated the comment because now it is confusing why we use the MSI endpoint here, so I wanted to clarify that it is just a placeholder.

We can leave here and look later. If the JWT verification is not required, we can also simplify this code.

Copy link
Copy Markdown
Contributor

@Tener Tener Jun 3, 2025

Choose a reason for hiding this comment

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

I'd drop the TODO. Using the cluster name would be helpful for validation purposes, but the other validation element is the CA that signed the JWT. It is safe to assume that CA is cluster-specific, so we don't necessarily need the cluster name to be different; it won't validate in the other cluster.

Comment thread tool/tsh/common/app_azure_test.go Outdated
@gabrielcorado gabrielcorado enabled auto-merge June 3, 2025 18:54
@gabrielcorado gabrielcorado added this pull request to the merge queue Jun 3, 2025
Merged via the queue into master with commit affde68 Jun 3, 2025
41 checks passed
@gabrielcorado gabrielcorado deleted the gabrielcorado/tsh-az-login-resource branch June 3, 2025 20:05
@backport-bot-workflows
Copy link
Copy Markdown
Contributor

@gabrielcorado See the table below for backport results.

Branch Result
branch/v15 Failed
branch/v16 Failed
branch/v17 Failed
branch/v18 Create PR

gabrielcorado added a commit that referenced this pull request Jul 18, 2025
* refactor(tsh): support `az login` with MSAL

* chore(tsh): fix lint

* refactor: code review suggestions

* test(tsh): fix wrong env names
gabrielcorado added a commit that referenced this pull request Jul 18, 2025
* refactor(tsh): support `az login` with MSAL

* chore(tsh): fix lint

* refactor: code review suggestions

* test(tsh): fix wrong env names
github-merge-queue Bot pushed a commit that referenced this pull request Jul 21, 2025
* refactor(tsh): support `az login` with MSAL

* chore(tsh): fix lint

* refactor: code review suggestions

* test(tsh): fix wrong env names
github-merge-queue Bot pushed a commit that referenced this pull request Jul 21, 2025
* refactor(tsh): support `az login` with MSAL

* chore(tsh): fix lint

* refactor: code review suggestions

* test(tsh): fix wrong env names
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

application-access backport/branch/v17 backport/branch/v18 size/md tsh tsh - Teleport's command line tool for logging into nodes running Teleport.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants