diff --git a/lib/cloud/azure/kubernetes.go b/lib/cloud/azure/kubernetes.go index 65ef46cb4e423..afbac977ab108 100644 --- a/lib/cloud/azure/kubernetes.go +++ b/lib/cloud/azure/kubernetes.go @@ -261,7 +261,6 @@ func (c *aksClient) ClusterCredentials(ctx context.Context, cfg ClusterCredentia default: return nil, time.Time{}, trace.BadParameter("unsupported AKS authentication mode %v", clusterDetails.Properties.AccessConfig) } - } // getAzureRBACCredentials generates a config to access the cluster. @@ -279,7 +278,7 @@ func (c *aksClient) getAzureRBACCredentials(ctx context.Context, cluster Cluster } if err := c.checkAccessPermissions(ctx, cfg, cluster); err != nil { - return nil, time.Time{}, trace.WrapWithMessage(err, `Azure RBAC rules have not been configured for the agent. + return nil, time.Time{}, trace.WrapWithMessage(err, `Azure RBAC rules have not been configured for the agent. Please check that you have configured them correctly.`) } @@ -300,7 +299,6 @@ func (c *aksClient) getUserCredentials(ctx context.Context, cfg ClusterCredentia result, err := c.getRestConfigFromKubeconfigs(res.Kubeconfigs) return result, trace.Wrap(err) - } // getAzureADCredentials gets the client configuration and checks if Kubernetes RBAC is configured. @@ -378,7 +376,6 @@ func (c *aksClient) getAdminCredentials(ctx context.Context, group, name string) } result, err = checkIfAuthMethodIsUnSupported(result) return result, trace.Wrap(err) - } // getRestConfigFromKubeconfigs parses the first kubeConfig returned by ListClusterAdminCredentials and @@ -433,17 +430,35 @@ func (c *aksClient) genAzureToken(ctx context.Context, tentantID string) (string return "", time.Time{}, trace.Wrap(ConvertResponseError(err)) } - cliAccessToken, err := cred.GetToken(ctx, policy.TokenRequestOptions{ + cliAccessToken, origErr := cred.GetToken(ctx, policy.TokenRequestOptions{ // azureManagedClusterScope is a fixed scope that identifies azure AKS managed clusters. Scopes: []string{azureManagedClusterScope}, }, ) + if origErr == nil { + return cliAccessToken.Token, cliAccessToken.ExpiresOn, nil + } + + // Some azure credentials like Workload Identity - but not all - require the + // scope to be suffixed with /.default. + // Since the AZ identity returns a chained credentials provider + // that tries to get the token from any of the configured providers but doesn't + // expose which provider was used, we retry the token generation with the + // the expected scope. + // In the case of this attempt doesn't return any valid credential, we return + // the original error. + cliAccessToken, err = cred.GetToken( + ctx, + policy.TokenRequestOptions{ + // azureManagedClusterScope is a fixed scope that identifies azure AKS managed clusters. + Scopes: []string{azureManagedClusterScope + "/.default"}, + }, + ) if err != nil { - return "", time.Time{}, trace.Wrap(ConvertResponseError(err)) + // use the original error since it's clear. + return "", time.Time{}, trace.Wrap(ConvertResponseError(origErr)) } - return cliAccessToken.Token, cliAccessToken.ExpiresOn, nil - } // grantAccessWithAdminCredentials tries to create the ClusterRole and ClusterRoleBinding into the AKS cluster @@ -460,7 +475,6 @@ func (c *aksClient) grantAccessWithAdminCredentials(ctx context.Context, adminCf err = c.upsertClusterRoleBindingWithAdminCredentials(ctx, client, groupID) return trace.Wrap(err) - } // upsertClusterRoleWithAdminCredentials tries to upsert the ClusterRole using admin credentials.