diff --git a/azure/services/identities/client.go b/azure/services/identities/client.go index ca406d2914f..d8958c161af 100644 --- a/azure/services/identities/client.go +++ b/azure/services/identities/client.go @@ -51,6 +51,19 @@ func NewClient(auth azure.Authorizer) (Client, error) { return &AzureClient{factory.NewUserAssignedIdentitiesClient()}, nil } +// NewClientBySub creates a new MSI client with a given subscriptionID +func NewClientBySub(auth azure.Authorizer, subscriptionID string) (Client, error) { + opts, err := azure.ARMClientOptions(auth.CloudEnvironment()) + if err != nil { + return nil, errors.Wrap(err, "failed to create identities client options") + } + factory, err := armmsi.NewClientFactory(subscriptionID, auth.Token(), opts) + if err != nil { + return nil, errors.Wrap(err, "failed to create armmsi client factory") + } + return &AzureClient{factory.NewUserAssignedIdentitiesClient()}, nil +} + // Get returns a managed service identity. func (ac *AzureClient) Get(ctx context.Context, resourceGroupName, name string) (armmsi.Identity, error) { ctx, _, done := tele.StartSpanWithLogger(ctx, "identities.AzureClient.Get") diff --git a/azure/services/virtualmachines/virtualmachines.go b/azure/services/virtualmachines/virtualmachines.go index 9179a11dedd..5641b439d1f 100644 --- a/azure/services/virtualmachines/virtualmachines.go +++ b/azure/services/virtualmachines/virtualmachines.go @@ -176,7 +176,18 @@ func (s *Service) checkUserAssignedIdentities(ctx context.Context, specIdentitie // Create a map of the expected identities. The ProviderID is converted to match the format of the VM identity. for _, expectedIdentity := range specIdentities { - expectedClientID, err := s.identitiesGetter.GetClientID(ctx, expectedIdentity.ProviderID) + var identitiesClient identities.Client = s.identitiesGetter + parsed, err := azureutil.ParseResourceID(expectedIdentity.ProviderID) + if err != nil { + return err + } + if parsed.SubscriptionID != s.Scope.SubscriptionID() { + identitiesClient, err = identities.NewClientBySub(s.Scope, parsed.SubscriptionID) + if err != nil { + return errors.Wrapf(err, "failed to create identities client from subscription ID %s", parsed.SubscriptionID) + } + } + expectedClientID, err := identitiesClient.GetClientID(ctx, expectedIdentity.ProviderID) if err != nil { return errors.Wrap(err, "failed to get client ID") } diff --git a/controllers/azurejson_machine_controller.go b/controllers/azurejson_machine_controller.go index 6a49a3f8a08..2eb5e5e4f03 100644 --- a/controllers/azurejson_machine_controller.go +++ b/controllers/azurejson_machine_controller.go @@ -31,6 +31,7 @@ import ( infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" "sigs.k8s.io/cluster-api-provider-azure/azure/scope" "sigs.k8s.io/cluster-api-provider-azure/azure/services/identities" + azureutil "sigs.k8s.io/cluster-api-provider-azure/util/azure" "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" @@ -215,11 +216,22 @@ func (r *AzureJSONMachineReconciler) Reconcile(ctx context.Context, req ctrl.Req // Construct secret for this machine userAssignedIdentityIfExists := "" if len(azureMachine.Spec.UserAssignedIdentities) > 0 { - idsClient, err := identities.NewClient(clusterScope) + var identitiesClient identities.Client + identitiesClient, err := identities.NewClient(clusterScope) if err != nil { return reconcile.Result{}, errors.Wrap(err, "failed to create identities client") } - userAssignedIdentityIfExists, err = idsClient.GetClientID( + parsed, err := azureutil.ParseResourceID(azureMachine.Spec.UserAssignedIdentities[0].ProviderID) + if err != nil { + return reconcile.Result{}, errors.Wrapf(err, "failed to parse ProviderID %s", azureMachine.Spec.UserAssignedIdentities[0].ProviderID) + } + if parsed.SubscriptionID != clusterScope.SubscriptionID() { + identitiesClient, err = identities.NewClientBySub(clusterScope, parsed.SubscriptionID) + if err != nil { + return reconcile.Result{}, errors.Wrapf(err, "failed to create identities client from subscription ID %s", parsed.SubscriptionID) + } + } + userAssignedIdentityIfExists, err = identitiesClient.GetClientID( ctx, azureMachine.Spec.UserAssignedIdentities[0].ProviderID) if err != nil { return reconcile.Result{}, errors.Wrap(err, "failed to get user-assigned identity ClientID") diff --git a/controllers/azurejson_machinepool_controller.go b/controllers/azurejson_machinepool_controller.go index 09d5af0773a..d62cdf41dae 100644 --- a/controllers/azurejson_machinepool_controller.go +++ b/controllers/azurejson_machinepool_controller.go @@ -27,6 +27,7 @@ import ( "k8s.io/client-go/tools/record" "k8s.io/utils/ptr" infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" + azureutil "sigs.k8s.io/cluster-api-provider-azure/util/azure" "sigs.k8s.io/cluster-api-provider-azure/azure/services/identities" infrav1exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1beta1" "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" @@ -148,11 +149,22 @@ func (r *AzureJSONMachinePoolReconciler) Reconcile(ctx context.Context, req ctrl // Construct secret for this machine userAssignedIdentityIfExists := "" if len(azureMachinePool.Spec.UserAssignedIdentities) > 0 { - idsClient, err := getClient(clusterScope) + var identitiesClient identities.Client + identitiesClient, err := getClient(clusterScope) if err != nil { return reconcile.Result{}, errors.Wrap(err, "failed to create identities client") } - userAssignedIdentityIfExists, err = idsClient.GetClientID( + parsed, err := azureutil.ParseResourceID(azureMachinePool.Spec.UserAssignedIdentities[0].ProviderID) + if err != nil { + return reconcile.Result{}, errors.Wrapf(err, "failed to parse ProviderID %s", azureMachinePool.Spec.UserAssignedIdentities[0].ProviderID) + } + if parsed.SubscriptionID != clusterScope.SubscriptionID() { + identitiesClient, err = identities.NewClientBySub(clusterScope, parsed.SubscriptionID) + if err != nil { + return reconcile.Result{}, errors.Wrapf(err, "failed to create identities client from subscription ID %s", parsed.SubscriptionID) + } + } + userAssignedIdentityIfExists, err = identitiesClient.GetClientID( ctx, azureMachinePool.Spec.UserAssignedIdentities[0].ProviderID) if err != nil { return reconcile.Result{}, errors.Wrap(err, "failed to get user-assigned identity ClientID") diff --git a/controllers/azurejson_machinetemplate_controller.go b/controllers/azurejson_machinetemplate_controller.go index 359ae971a57..baea0ee8e18 100644 --- a/controllers/azurejson_machinetemplate_controller.go +++ b/controllers/azurejson_machinetemplate_controller.go @@ -30,6 +30,7 @@ import ( infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" "sigs.k8s.io/cluster-api-provider-azure/azure/scope" "sigs.k8s.io/cluster-api-provider-azure/azure/services/identities" + azureutil "sigs.k8s.io/cluster-api-provider-azure/util/azure" "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" @@ -175,11 +176,22 @@ func (r *AzureJSONTemplateReconciler) Reconcile(ctx context.Context, req ctrl.Re // Construct secret for this machine template userAssignedIdentityIfExists := "" if len(azureMachineTemplate.Spec.Template.Spec.UserAssignedIdentities) > 0 { - idsClient, err := identities.NewClient(clusterScope) + var identitiesClient identities.Client + identitiesClient, err := identities.NewClient(clusterScope) if err != nil { return reconcile.Result{}, errors.Wrap(err, "failed to create identities client") } - userAssignedIdentityIfExists, err = idsClient.GetClientID( + parsed, err := azureutil.ParseResourceID(azureMachineTemplate.Spec.Template.Spec.UserAssignedIdentities[0].ProviderID) + if err != nil { + return reconcile.Result{}, errors.Wrapf(err, "failed to parse ProviderID %s", azureMachineTemplate.Spec.Template.Spec.UserAssignedIdentities[0].ProviderID) + } + if parsed.SubscriptionID != clusterScope.SubscriptionID() { + identitiesClient, err = identities.NewClientBySub(clusterScope, parsed.SubscriptionID) + if err != nil { + return reconcile.Result{}, errors.Wrapf(err, "failed to create identities client from subscription ID %s", parsed.SubscriptionID) + } + } + userAssignedIdentityIfExists, err = identitiesClient.GetClientID( ctx, azureMachineTemplate.Spec.Template.Spec.UserAssignedIdentities[0].ProviderID) if err != nil { return reconcile.Result{}, errors.Wrap(err, "failed to get user-assigned identity ClientID")