You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by pv...@apache.org on 2022/03/09 15:51:00 UTC

[nifi] branch main updated: NIFI-9728: Added support for User Assigned Managed Identity authentication for Azure ADLS and Blob_v12 processors

This is an automated email from the ASF dual-hosted git repository.

pvillard pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/main by this push:
     new 3219c10  NIFI-9728: Added support for User Assigned Managed Identity authentication for Azure ADLS and Blob_v12 processors
3219c10 is described below

commit 3219c105ebd6d3a648c84684b2cb78efe81da438
Author: Peter Turcsanyi <tu...@apache.org>
AuthorDate: Sat Mar 5 13:49:46 2022 +0100

    NIFI-9728: Added support for User Assigned Managed Identity authentication for Azure ADLS and Blob_v12 processors
    
    Also bumped Azure dependencies.
    
    Signed-off-by: Pierre Villard <pi...@gmail.com>
    
    This closes #5846.
---
 .../nifi-azure-processors/pom.xml                  |  6 +--
 .../azure/AbstractAzureBlobProcessor_v12.java      | 10 ++--
 .../AbstractAzureDataLakeStorageProcessor.java     |  2 +
 .../azure/storage/utils/AzureStorageUtils.java     | 11 ++++
 .../storage/ADLSCredentialsControllerService.java  | 61 ++++++++++++++--------
 ...ureStorageCredentialsControllerService_v12.java | 17 ++++--
 .../TestADLSCredentialsControllerService.java      | 47 ++++++++++++++++-
 ...ureStorageCredentialsControllerService_v12.java | 24 ++++-----
 .../azure/storage/ADLSCredentialsDetails.java      | 15 +++++-
 .../AzureStorageCredentialsDetails_v12.java        | 54 +++++++++++--------
 nifi-nar-bundles/nifi-azure-bundle/pom.xml         |  7 ++-
 11 files changed, 178 insertions(+), 76 deletions(-)

diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/pom.xml b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/pom.xml
index ceccc48..4a14fd2 100644
--- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/pom.xml
+++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/pom.xml
@@ -22,9 +22,9 @@
     <properties>
         <azure-eventhubs.version>3.3.0</azure-eventhubs.version>
         <azure-eventhubs-eph.version>3.3.0</azure-eventhubs-eph.version>
-        <azure-keyvault.version>1.2.4</azure-keyvault.version>
-        <azure-storage-file-datalake.version>12.7.1</azure-storage-file-datalake.version>
-        <azure-storage-blob.version>12.14.1</azure-storage-blob.version>
+        <azure-keyvault.version>1.2.6</azure-keyvault.version>
+        <azure-storage-file-datalake.version>12.7.4</azure-storage-file-datalake.version>
+        <azure-storage-blob.version>12.14.4</azure-storage-blob.version>
     </properties>
     <dependencies>
         <dependency>
diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/AbstractAzureBlobProcessor_v12.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/AbstractAzureBlobProcessor_v12.java
index 0186452..91e4420 100644
--- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/AbstractAzureBlobProcessor_v12.java
+++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/AbstractAzureBlobProcessor_v12.java
@@ -130,13 +130,15 @@ public abstract class AbstractAzureBlobProcessor_v12 extends AbstractProcessor {
                 clientBuilder.credential(new AzureSasCredential(credentialsDetails.getSasToken()));
                 break;
             case MANAGED_IDENTITY:
-                clientBuilder.credential(new ManagedIdentityCredentialBuilder().build());
+                clientBuilder.credential(new ManagedIdentityCredentialBuilder()
+                                .clientId(credentialsDetails.getManagedIdentityClientId())
+                        .build());
                 break;
             case SERVICE_PRINCIPAL:
                 clientBuilder.credential(new ClientSecretCredentialBuilder()
-                        .tenantId(credentialsDetails.getTenantId())
-                        .clientId(credentialsDetails.getClientId())
-                        .clientSecret(credentialsDetails.getClientSecret())
+                        .tenantId(credentialsDetails.getServicePrincipalTenantId())
+                        .clientId(credentialsDetails.getServicePrincipalClientId())
+                        .clientSecret(credentialsDetails.getServicePrincipalClientSecret())
                         .build());
                 break;
             case ACCESS_TOKEN:
diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/AbstractAzureDataLakeStorageProcessor.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/AbstractAzureDataLakeStorageProcessor.java
index d371e12..39e2ad2 100644
--- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/AbstractAzureDataLakeStorageProcessor.java
+++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/AbstractAzureDataLakeStorageProcessor.java
@@ -129,6 +129,7 @@ public abstract class AbstractAzureDataLakeStorageProcessor extends AbstractProc
         final AccessToken accessToken = credentialsDetails.getAccessToken();
         final String endpointSuffix = credentialsDetails.getEndpointSuffix();
         final boolean useManagedIdentity = credentialsDetails.getUseManagedIdentity();
+        final String managedIdentityClientId = credentialsDetails.getManagedIdentityClientId();
         final String servicePrincipalTenantId = credentialsDetails.getServicePrincipalTenantId();
         final String servicePrincipalClientId = credentialsDetails.getServicePrincipalClientId();
         final String servicePrincipalClientSecret = credentialsDetails.getServicePrincipalClientSecret();
@@ -151,6 +152,7 @@ public abstract class AbstractAzureDataLakeStorageProcessor extends AbstractProc
                     .buildClient();
         } else if (useManagedIdentity) {
             final ManagedIdentityCredential misCredential = new ManagedIdentityCredentialBuilder()
+                    .clientId(managedIdentityClientId)
                     .build();
             storageClient = new DataLakeServiceClientBuilder()
                     .endpoint(endpoint)
diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/utils/AzureStorageUtils.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/utils/AzureStorageUtils.java
index 1e898da..a73c108 100644
--- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/utils/AzureStorageUtils.java
+++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/utils/AzureStorageUtils.java
@@ -156,6 +156,17 @@ public final class AzureStorageUtils {
             .required(false)
             .build();
 
+    public static final PropertyDescriptor MANAGED_IDENTITY_CLIENT_ID = new PropertyDescriptor.Builder()
+            .name("managed-identity-client-id")
+            .displayName("Managed Identity Client ID")
+            .description("Client ID of the managed identity. The property is required when User Assigned Managed Identity is used for authentication. " +
+                    "It must be empty in case of System Assigned Managed Identity.")
+            .sensitive(true)
+            .required(false)
+            .addValidator(StandardValidators.NON_BLANK_VALIDATOR)
+            .expressionLanguageSupported(ExpressionLanguageScope.NONE)
+            .build();
+
     public static final PropertyDescriptor SERVICE_PRINCIPAL_TENANT_ID = new PropertyDescriptor.Builder()
             .name("service-principal-tenant-id")
             .displayName("Service Principal Tenant ID")
diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/storage/ADLSCredentialsControllerService.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/storage/ADLSCredentialsControllerService.java
index 8699a79..b075322 100644
--- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/storage/ADLSCredentialsControllerService.java
+++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/storage/ADLSCredentialsControllerService.java
@@ -68,13 +68,15 @@ public class ADLSCredentialsControllerService extends AbstractControllerService
     public static final PropertyDescriptor USE_MANAGED_IDENTITY = new PropertyDescriptor.Builder()
             .name("storage-use-managed-identity")
             .displayName("Use Azure Managed Identity")
-            .description("Choose whether or not to use the managed identity of Azure VM/VMSS ")
+            .description("Choose whether or not to use the managed identity of Azure VM/VMSS")
             .required(false)
             .defaultValue("false")
             .allowableValues("true", "false")
             .addValidator(StandardValidators.BOOLEAN_VALIDATOR)
             .build();
 
+    public static final PropertyDescriptor MANAGED_IDENTITY_CLIENT_ID = AzureStorageUtils.MANAGED_IDENTITY_CLIENT_ID;
+
     public static final PropertyDescriptor SERVICE_PRINCIPAL_TENANT_ID = AzureStorageUtils.SERVICE_PRINCIPAL_TENANT_ID;
 
     public static final PropertyDescriptor SERVICE_PRINCIPAL_CLIENT_ID = AzureStorageUtils.SERVICE_PRINCIPAL_CLIENT_ID;
@@ -87,6 +89,7 @@ public class ADLSCredentialsControllerService extends AbstractControllerService
             AzureStorageUtils.ACCOUNT_KEY,
             AzureStorageUtils.PROP_SAS_TOKEN,
             USE_MANAGED_IDENTITY,
+            MANAGED_IDENTITY_CLIENT_ID,
             SERVICE_PRINCIPAL_TENANT_ID,
             SERVICE_PRINCIPAL_CLIENT_ID,
             SERVICE_PRINCIPAL_CLIENT_SECRET
@@ -103,39 +106,50 @@ public class ADLSCredentialsControllerService extends AbstractControllerService
     protected Collection<ValidationResult> customValidate(ValidationContext validationContext) {
         final List<ValidationResult> results = new ArrayList<>();
 
-        boolean accountKeySet = StringUtils.isNotBlank(validationContext.getProperty(AzureStorageUtils.ACCOUNT_KEY).getValue());
-        boolean sasTokenSet = StringUtils.isNotBlank(validationContext.getProperty(AzureStorageUtils.PROP_SAS_TOKEN).getValue());
-        boolean useManagedIdentitySet = validationContext.getProperty(USE_MANAGED_IDENTITY).asBoolean();
+        final boolean accountKeySet = StringUtils.isNotBlank(validationContext.getProperty(AzureStorageUtils.ACCOUNT_KEY).getValue());
+        final boolean sasTokenSet = StringUtils.isNotBlank(validationContext.getProperty(AzureStorageUtils.PROP_SAS_TOKEN).getValue());
+        final boolean useManagedIdentitySet = validationContext.getProperty(USE_MANAGED_IDENTITY).asBoolean();
+
+        final boolean servicePrincipalTenantIdSet = StringUtils.isNotBlank(validationContext.getProperty(SERVICE_PRINCIPAL_TENANT_ID).getValue());
+        final boolean servicePrincipalClientIdSet = StringUtils.isNotBlank(validationContext.getProperty(SERVICE_PRINCIPAL_CLIENT_ID).getValue());
+        final boolean servicePrincipalClientSecretSet = StringUtils.isNotBlank(validationContext.getProperty(SERVICE_PRINCIPAL_CLIENT_SECRET).getValue());
 
-        boolean servicePrincipalTenantIdSet = StringUtils.isNotBlank(validationContext.getProperty(SERVICE_PRINCIPAL_TENANT_ID).getValue());
-        boolean servicePrincipalClientIdSet = StringUtils.isNotBlank(validationContext.getProperty(SERVICE_PRINCIPAL_CLIENT_ID).getValue());
-        boolean servicePrincipalClientSecretSet = StringUtils.isNotBlank(validationContext.getProperty(SERVICE_PRINCIPAL_CLIENT_SECRET).getValue());
+        final boolean servicePrincipalSet = servicePrincipalTenantIdSet || servicePrincipalClientIdSet || servicePrincipalClientSecretSet;
 
-        boolean servicePrincipalSet = servicePrincipalTenantIdSet || servicePrincipalClientIdSet || servicePrincipalClientSecretSet;
+        final String managedIdentityClientId = validationContext.getProperty(MANAGED_IDENTITY_CLIENT_ID).getValue();
 
         if (!onlyOneSet(accountKeySet, sasTokenSet, useManagedIdentitySet, servicePrincipalSet)) {
             results.add(new ValidationResult.Builder().subject(this.getClass().getSimpleName())
                 .valid(false)
                 .explanation("one and only one authentication method of [Account Key, SAS Token, Managed Identity, Service Principal] should be used")
                 .build());
-        } else if (servicePrincipalSet) {
-            String template = "'%s' must be set when Service Principal authentication is being configured";
-            if (!servicePrincipalTenantIdSet) {
-                results.add(new ValidationResult.Builder().subject(this.getClass().getSimpleName())
-                        .valid(false)
-                        .explanation(String.format(template, SERVICE_PRINCIPAL_TENANT_ID.getDisplayName()))
-                        .build());
-            }
-            if (!servicePrincipalClientIdSet) {
-                results.add(new ValidationResult.Builder().subject(this.getClass().getSimpleName())
-                        .valid(false)
-                        .explanation(String.format(template, SERVICE_PRINCIPAL_CLIENT_ID.getDisplayName()))
-                        .build());
+        } else {
+            if (servicePrincipalSet) {
+                final String template = "'%s' must be set when Service Principal authentication is being configured";
+                if (!servicePrincipalTenantIdSet) {
+                    results.add(new ValidationResult.Builder().subject(this.getClass().getSimpleName())
+                            .valid(false)
+                            .explanation(String.format(template, SERVICE_PRINCIPAL_TENANT_ID.getDisplayName()))
+                            .build());
+                }
+                if (!servicePrincipalClientIdSet) {
+                    results.add(new ValidationResult.Builder().subject(this.getClass().getSimpleName())
+                            .valid(false)
+                            .explanation(String.format(template, SERVICE_PRINCIPAL_CLIENT_ID.getDisplayName()))
+                            .build());
+                }
+                if (!servicePrincipalClientSecretSet) {
+                    results.add(new ValidationResult.Builder().subject(this.getClass().getSimpleName())
+                            .valid(false)
+                            .explanation(String.format(template, SERVICE_PRINCIPAL_CLIENT_SECRET.getDisplayName()))
+                            .build());
+                }
             }
-            if (!servicePrincipalClientSecretSet) {
+
+            if (!useManagedIdentitySet && StringUtils.isNotEmpty(managedIdentityClientId)) {
                 results.add(new ValidationResult.Builder().subject(this.getClass().getSimpleName())
                         .valid(false)
-                        .explanation(String.format(template, SERVICE_PRINCIPAL_CLIENT_SECRET.getDisplayName()))
+                        .explanation(String.format("'%s' can only be configured when '%s' is set to true", MANAGED_IDENTITY_CLIENT_ID.getDisplayName(), USE_MANAGED_IDENTITY.getDisplayName()))
                         .build());
             }
         }
@@ -165,6 +179,7 @@ public class ADLSCredentialsControllerService extends AbstractControllerService
         setValue(credentialsBuilder, AzureStorageUtils.PROP_SAS_TOKEN, PropertyValue::getValue, ADLSCredentialsDetails.Builder::setSasToken, attributes);
         setValue(credentialsBuilder, ENDPOINT_SUFFIX, PropertyValue::getValue, ADLSCredentialsDetails.Builder::setEndpointSuffix, attributes);
         setValue(credentialsBuilder, USE_MANAGED_IDENTITY, PropertyValue::asBoolean, ADLSCredentialsDetails.Builder::setUseManagedIdentity, attributes);
+        setValue(credentialsBuilder, MANAGED_IDENTITY_CLIENT_ID, PropertyValue::getValue, ADLSCredentialsDetails.Builder::setManagedIdentityClientId, attributes);
         setValue(credentialsBuilder, SERVICE_PRINCIPAL_TENANT_ID, PropertyValue::getValue, ADLSCredentialsDetails.Builder::setServicePrincipalTenantId, attributes);
         setValue(credentialsBuilder, SERVICE_PRINCIPAL_CLIENT_ID, PropertyValue::getValue, ADLSCredentialsDetails.Builder::setServicePrincipalClientId, attributes);
         setValue(credentialsBuilder, SERVICE_PRINCIPAL_CLIENT_SECRET, PropertyValue::getValue, ADLSCredentialsDetails.Builder::setServicePrincipalClientSecret, attributes);
diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/storage/AzureStorageCredentialsControllerService_v12.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/storage/AzureStorageCredentialsControllerService_v12.java
index b46ab3e..ba8101d 100644
--- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/storage/AzureStorageCredentialsControllerService_v12.java
+++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/storage/AzureStorageCredentialsControllerService_v12.java
@@ -85,6 +85,11 @@ public class AzureStorageCredentialsControllerService_v12 extends AbstractContro
             .dependsOn(CREDENTIALS_TYPE, AzureStorageCredentialsType.SAS_TOKEN.getAllowableValue())
             .build();
 
+    public static final PropertyDescriptor MANAGED_IDENTITY_CLIENT_ID = new PropertyDescriptor.Builder()
+            .fromPropertyDescriptor(AzureStorageUtils.MANAGED_IDENTITY_CLIENT_ID)
+            .dependsOn(CREDENTIALS_TYPE, AzureStorageCredentialsType.MANAGED_IDENTITY.getAllowableValue())
+            .build();
+
     public static final PropertyDescriptor SERVICE_PRINCIPAL_TENANT_ID = new PropertyDescriptor.Builder()
             .fromPropertyDescriptor(AzureStorageUtils.SERVICE_PRINCIPAL_TENANT_ID)
             .required(true)
@@ -109,6 +114,7 @@ public class AzureStorageCredentialsControllerService_v12 extends AbstractContro
             CREDENTIALS_TYPE,
             ACCOUNT_KEY,
             SAS_TOKEN,
+            MANAGED_IDENTITY_CLIENT_ID,
             SERVICE_PRINCIPAL_TENANT_ID,
             SERVICE_PRINCIPAL_CLIENT_ID,
             SERVICE_PRINCIPAL_CLIENT_SECRET
@@ -140,12 +146,13 @@ public class AzureStorageCredentialsControllerService_v12 extends AbstractContro
                 String sasToken = context.getProperty(SAS_TOKEN).getValue();
                 return AzureStorageCredentialsDetails_v12.createWithSasToken(accountName, endpointSuffix, sasToken);
             case MANAGED_IDENTITY:
-                return AzureStorageCredentialsDetails_v12.createWithManagedIdentity(accountName, endpointSuffix);
+                String managedIdentityClientId = context.getProperty(MANAGED_IDENTITY_CLIENT_ID).getValue();
+                return AzureStorageCredentialsDetails_v12.createWithManagedIdentity(accountName, endpointSuffix, managedIdentityClientId);
             case SERVICE_PRINCIPAL:
-                String tenantId = context.getProperty(SERVICE_PRINCIPAL_TENANT_ID).getValue();
-                String clientId = context.getProperty(SERVICE_PRINCIPAL_CLIENT_ID).getValue();
-                String clientSecret = context.getProperty(SERVICE_PRINCIPAL_CLIENT_SECRET).getValue();
-                return AzureStorageCredentialsDetails_v12.createWithServicePrincipal(accountName, endpointSuffix, tenantId, clientId, clientSecret);
+                String servicePrincipalTenantId = context.getProperty(SERVICE_PRINCIPAL_TENANT_ID).getValue();
+                String servicePrincipalClientId = context.getProperty(SERVICE_PRINCIPAL_CLIENT_ID).getValue();
+                String servicePrincipalClientSecret = context.getProperty(SERVICE_PRINCIPAL_CLIENT_SECRET).getValue();
+                return AzureStorageCredentialsDetails_v12.createWithServicePrincipal(accountName, endpointSuffix, servicePrincipalTenantId, servicePrincipalClientId, servicePrincipalClientSecret);
             default:
                 throw new IllegalArgumentException("Unhandled credentials type: " + credentialsType);
         }
diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/services/azure/storage/TestADLSCredentialsControllerService.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/services/azure/storage/TestADLSCredentialsControllerService.java
index 69e2b2d..a113aa4 100644
--- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/services/azure/storage/TestADLSCredentialsControllerService.java
+++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/services/azure/storage/TestADLSCredentialsControllerService.java
@@ -41,6 +41,7 @@ public class TestADLSCredentialsControllerService {
     private static final String ACCOUNT_KEY_VALUE = "AccountKey";
     private static final String SAS_TOKEN_VALUE = "SasToken";
     private static final String END_POINT_SUFFIX_VALUE = "end.point.suffix";
+    private static final String MANAGED_IDENTITY_CLIENT_ID_VALUE = "ManagedIdentityClientID";
     private static final String SERVICE_PRINCIPAL_TENANT_ID_VALUE = "ServicePrincipalTenantID";
     private static final String SERVICE_PRINCIPAL_CLIENT_ID_VALUE = "ServicePrincipalClientID";
     private static final String SERVICE_PRINCIPAL_CLIENT_SECRET_VALUE = "ServicePrincipalClientSecret";
@@ -255,6 +256,16 @@ public class TestADLSCredentialsControllerService {
     }
 
     @Test
+    public void testNotValidBecauseManagedIdentityClientIdSpecifiedButUseManagedIdentityIsFalse() {
+        configureAccountName();
+        configureAccountKey();
+
+        configureManagedIdentityClientId();
+
+        runner.assertNotValid(credentialsService);
+    }
+
+    @Test
     public void testNotValidBecauseNoTenantIdSpecifiedForServicePrincipal() {
         configureAccountName();
 
@@ -300,6 +311,7 @@ public class TestADLSCredentialsControllerService {
         assertEquals(ACCOUNT_KEY_VALUE, actual.getAccountKey());
         assertNull(actual.getSasToken());
         assertFalse(actual.getUseManagedIdentity());
+        assertNull(actual.getManagedIdentityClientId());
         assertNotNull(actual.getEndpointSuffix());
         assertNull(actual.getServicePrincipalTenantId());
         assertNull(actual.getServicePrincipalClientId());
@@ -322,6 +334,7 @@ public class TestADLSCredentialsControllerService {
         assertEquals(ACCOUNT_KEY_VALUE, actual.getAccountKey());
         assertNull(actual.getSasToken());
         assertFalse(actual.getUseManagedIdentity());
+        assertNull(actual.getManagedIdentityClientId());
         assertNotNull(actual.getEndpointSuffix());
         assertNull(actual.getServicePrincipalTenantId());
         assertNull(actual.getServicePrincipalClientId());
@@ -344,6 +357,7 @@ public class TestADLSCredentialsControllerService {
         assertEquals(SAS_TOKEN_VALUE, actual.getSasToken());
         assertNull(actual.getAccountKey());
         assertFalse(actual.getUseManagedIdentity());
+        assertNull(actual.getManagedIdentityClientId());
         assertNotNull(actual.getEndpointSuffix());
         assertNull(actual.getServicePrincipalTenantId());
         assertNull(actual.getServicePrincipalClientId());
@@ -362,6 +376,7 @@ public class TestADLSCredentialsControllerService {
         assertEquals(SAS_TOKEN_VALUE, actual.getSasToken());
         assertNull(actual.getAccountKey());
         assertFalse(actual.getUseManagedIdentity());
+        assertNull(actual.getManagedIdentityClientId());
         assertNotNull(actual.getEndpointSuffix());
         assertNull(actual.getServicePrincipalTenantId());
         assertNull(actual.getServicePrincipalClientId());
@@ -369,7 +384,7 @@ public class TestADLSCredentialsControllerService {
     }
 
     @Test
-    public void testGetCredentialsDetailsWithUseManagedIdentity() throws Exception {
+    public void testGetCredentialsDetailsWithSystemAssignedManagedIdentity() throws Exception {
         // GIVEN
         configureAccountName();
         configureUseManagedIdentity();
@@ -382,6 +397,31 @@ public class TestADLSCredentialsControllerService {
         // THEN
         assertEquals(ACCOUNT_NAME_VALUE, actual.getAccountName());
         assertTrue(actual.getUseManagedIdentity());
+        assertNull(actual.getManagedIdentityClientId());
+        assertNull(actual.getAccountKey());
+        assertNull(actual.getSasToken());
+        assertNotNull(actual.getEndpointSuffix());
+        assertNull(actual.getServicePrincipalTenantId());
+        assertNull(actual.getServicePrincipalClientId());
+        assertNull(actual.getServicePrincipalClientSecret());
+    }
+
+    @Test
+    public void testGetCredentialsDetailsWithUserAssignedManagedIdentity() throws Exception {
+        // GIVEN
+        configureAccountName();
+        configureUseManagedIdentity();
+        configureManagedIdentityClientId();
+
+        runner.enableControllerService(credentialsService);
+
+        // WHEN
+        ADLSCredentialsDetails actual = credentialsService.getCredentialsDetails(new HashMap<>());
+
+        // THEN
+        assertEquals(ACCOUNT_NAME_VALUE, actual.getAccountName());
+        assertTrue(actual.getUseManagedIdentity());
+        assertEquals(MANAGED_IDENTITY_CLIENT_ID_VALUE, actual.getManagedIdentityClientId());
         assertNull(actual.getAccountKey());
         assertNull(actual.getSasToken());
         assertNotNull(actual.getEndpointSuffix());
@@ -408,6 +448,7 @@ public class TestADLSCredentialsControllerService {
         assertNull(actual.getAccountKey());
         assertNull(actual.getSasToken());
         assertFalse(actual.getUseManagedIdentity());
+        assertNull(actual.getManagedIdentityClientId());
         assertNotNull(actual.getEndpointSuffix());
         assertEquals(SERVICE_PRINCIPAL_TENANT_ID_VALUE, actual.getServicePrincipalTenantId());
         assertEquals(SERVICE_PRINCIPAL_CLIENT_ID_VALUE, actual.getServicePrincipalClientId());
@@ -475,6 +516,10 @@ public class TestADLSCredentialsControllerService {
         runner.setProperty(credentialsService, ADLSCredentialsControllerService.USE_MANAGED_IDENTITY, "true");
     }
 
+    private void configureManagedIdentityClientId() {
+        runner.setProperty(credentialsService, ADLSCredentialsControllerService.MANAGED_IDENTITY_CLIENT_ID, MANAGED_IDENTITY_CLIENT_ID_VALUE);
+    }
+
     private void configureEndpointSuffix() {
         runner.setProperty(credentialsService, ADLSCredentialsControllerService.ENDPOINT_SUFFIX, END_POINT_SUFFIX_VALUE);
     }
diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/services/azure/storage/TestAzureStorageCredentialsControllerService_v12.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/services/azure/storage/TestAzureStorageCredentialsControllerService_v12.java
index 3f0a94d..6bda55e 100644
--- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/services/azure/storage/TestAzureStorageCredentialsControllerService_v12.java
+++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/services/azure/storage/TestAzureStorageCredentialsControllerService_v12.java
@@ -165,9 +165,9 @@ public class TestAzureStorageCredentialsControllerService_v12 {
         assertEquals(ACCOUNT_KEY, actual.getCredentialsType());
         assertEquals(ACCOUNT_KEY_VALUE, actual.getAccountKey());
         assertNull(actual.getSasToken());
-        assertNull(actual.getTenantId());
-        assertNull(actual.getClientId());
-        assertNull(actual.getClientSecret());
+        assertNull(actual.getServicePrincipalTenantId());
+        assertNull(actual.getServicePrincipalClientId());
+        assertNull(actual.getServicePrincipalClientSecret());
     }
 
     @Test
@@ -185,9 +185,9 @@ public class TestAzureStorageCredentialsControllerService_v12 {
         assertEquals(SAS_TOKEN, actual.getCredentialsType());
         assertNull(actual.getAccountKey());
         assertEquals(SAS_TOKEN_VALUE, actual.getSasToken());
-        assertNull(actual.getTenantId());
-        assertNull(actual.getClientId());
-        assertNull(actual.getClientSecret());
+        assertNull(actual.getServicePrincipalTenantId());
+        assertNull(actual.getServicePrincipalClientId());
+        assertNull(actual.getServicePrincipalClientSecret());
     }
 
     @Test
@@ -204,9 +204,9 @@ public class TestAzureStorageCredentialsControllerService_v12 {
         assertEquals(MANAGED_IDENTITY, actual.getCredentialsType());
         assertNull(actual.getAccountKey());
         assertNull(actual.getSasToken());
-        assertNull(actual.getTenantId());
-        assertNull(actual.getClientId());
-        assertNull(actual.getClientSecret());
+        assertNull(actual.getServicePrincipalTenantId());
+        assertNull(actual.getServicePrincipalClientId());
+        assertNull(actual.getServicePrincipalClientSecret());
     }
 
     @Test
@@ -226,9 +226,9 @@ public class TestAzureStorageCredentialsControllerService_v12 {
         assertEquals(SERVICE_PRINCIPAL, actual.getCredentialsType());
         assertNull(actual.getAccountKey());
         assertNull(actual.getSasToken());
-        assertEquals(SERVICE_PRINCIPAL_TENANT_ID_VALUE, actual.getTenantId());
-        assertEquals(SERVICE_PRINCIPAL_CLIENT_ID_VALUE, actual.getClientId());
-        assertEquals(SERVICE_PRINCIPAL_CLIENT_SECRET_VALUE, actual.getClientSecret());
+        assertEquals(SERVICE_PRINCIPAL_TENANT_ID_VALUE, actual.getServicePrincipalTenantId());
+        assertEquals(SERVICE_PRINCIPAL_CLIENT_ID_VALUE, actual.getServicePrincipalClientId());
+        assertEquals(SERVICE_PRINCIPAL_CLIENT_SECRET_VALUE, actual.getServicePrincipalClientSecret());
     }
 
     @Test
diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-services-api/src/main/java/org/apache/nifi/services/azure/storage/ADLSCredentialsDetails.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-services-api/src/main/java/org/apache/nifi/services/azure/storage/ADLSCredentialsDetails.java
index 03143ed..eb3b123 100644
--- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-services-api/src/main/java/org/apache/nifi/services/azure/storage/ADLSCredentialsDetails.java
+++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-services-api/src/main/java/org/apache/nifi/services/azure/storage/ADLSCredentialsDetails.java
@@ -28,6 +28,7 @@ public class ADLSCredentialsDetails {
     private final AccessToken accessToken;
 
     private final boolean useManagedIdentity;
+    private final String managedIdentityClientId;
 
     private final String servicePrincipalTenantId;
     private final String servicePrincipalClientId;
@@ -40,6 +41,7 @@ public class ADLSCredentialsDetails {
             String endpointSuffix,
             AccessToken accessToken,
             boolean useManagedIdentity,
+            String managedIdentityClientId,
             String servicePrincipalTenantId,
             String servicePrincipalClientId,
             String servicePrincipalClientSecret
@@ -50,6 +52,7 @@ public class ADLSCredentialsDetails {
         this.endpointSuffix = endpointSuffix;
         this.accessToken = accessToken;
         this.useManagedIdentity = useManagedIdentity;
+        this.managedIdentityClientId = managedIdentityClientId;
         this.servicePrincipalTenantId = servicePrincipalTenantId;
         this.servicePrincipalClientId = servicePrincipalClientId;
         this.servicePrincipalClientSecret = servicePrincipalClientSecret;
@@ -79,6 +82,10 @@ public class ADLSCredentialsDetails {
         return useManagedIdentity;
     }
 
+    public String getManagedIdentityClientId() {
+        return managedIdentityClientId;
+    }
+
     public String getServicePrincipalTenantId() {
         return servicePrincipalTenantId;
     }
@@ -98,6 +105,7 @@ public class ADLSCredentialsDetails {
         private String endpointSuffix;
         private AccessToken accessToken;
         private boolean useManagedIdentity;
+        private String managedIdentityClientId;
         private String servicePrincipalTenantId;
         private String servicePrincipalClientId;
         private String servicePrincipalClientSecret;
@@ -138,6 +146,11 @@ public class ADLSCredentialsDetails {
             return this;
         }
 
+        public Builder setManagedIdentityClientId(String useManagedIdentityClientId) {
+            this.managedIdentityClientId = useManagedIdentityClientId;
+            return this;
+        }
+
         public Builder setServicePrincipalTenantId(String servicePrincipalTenantId) {
             this.servicePrincipalTenantId = servicePrincipalTenantId;
             return this;
@@ -154,7 +167,7 @@ public class ADLSCredentialsDetails {
         }
 
         public ADLSCredentialsDetails build() {
-            return new ADLSCredentialsDetails(accountName, accountKey, sasToken, endpointSuffix, accessToken, useManagedIdentity,
+            return new ADLSCredentialsDetails(accountName, accountKey, sasToken, endpointSuffix, accessToken, useManagedIdentity, managedIdentityClientId,
                     servicePrincipalTenantId, servicePrincipalClientId, servicePrincipalClientSecret);
         }
     }
diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-services-api/src/main/java/org/apache/nifi/services/azure/storage/AzureStorageCredentialsDetails_v12.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-services-api/src/main/java/org/apache/nifi/services/azure/storage/AzureStorageCredentialsDetails_v12.java
index 7851bec..6ab1545 100644
--- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-services-api/src/main/java/org/apache/nifi/services/azure/storage/AzureStorageCredentialsDetails_v12.java
+++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-services-api/src/main/java/org/apache/nifi/services/azure/storage/AzureStorageCredentialsDetails_v12.java
@@ -25,22 +25,24 @@ public class AzureStorageCredentialsDetails_v12 {
     private final AzureStorageCredentialsType credentialsType;
     private final String accountKey;
     private final String sasToken;
-    private final String tenantId;
-    private final String clientId;
-    private final String clientSecret;
+    private final String managedIdentityClientId;
+    private final String servicePrincipalTenantId;
+    private final String servicePrincipalClientId;
+    private final String servicePrincipalClientSecret;
     private final AccessToken accessToken;
 
     private AzureStorageCredentialsDetails_v12(
-            String accountName, String endpointSuffix, AzureStorageCredentialsType credentialsType, String accountKey,
-            String sasToken, String tenantId, String clientId, String clientSecret, AccessToken accessToken) {
+            String accountName, String endpointSuffix, AzureStorageCredentialsType credentialsType, String accountKey, String sasToken, String managedIdentityClientId,
+            String servicePrincipalTenantId, String servicePrincipalClientId, String servicePrincipalClientSecret, AccessToken accessToken) {
         this.accountName = accountName;
         this.endpointSuffix = endpointSuffix;
         this.credentialsType = credentialsType;
         this.accountKey = accountKey;
         this.sasToken = sasToken;
-        this.tenantId = tenantId;
-        this.clientId = clientId;
-        this.clientSecret = clientSecret;
+        this.managedIdentityClientId = managedIdentityClientId;
+        this.servicePrincipalTenantId = servicePrincipalTenantId;
+        this.servicePrincipalClientId = servicePrincipalClientId;
+        this.servicePrincipalClientSecret = servicePrincipalClientSecret;
         this.accessToken = accessToken;
     }
 
@@ -64,16 +66,20 @@ public class AzureStorageCredentialsDetails_v12 {
         return sasToken;
     }
 
-    public String getTenantId() {
-        return tenantId;
+    public String getManagedIdentityClientId() {
+        return managedIdentityClientId;
     }
 
-    public String getClientId() {
-        return clientId;
+    public String getServicePrincipalTenantId() {
+        return servicePrincipalTenantId;
     }
 
-    public String getClientSecret() {
-        return clientSecret;
+    public String getServicePrincipalClientId() {
+        return servicePrincipalClientId;
+    }
+
+    public String getServicePrincipalClientSecret() {
+        return servicePrincipalClientSecret;
     }
 
     public AccessToken getAccessToken() {
@@ -84,35 +90,37 @@ public class AzureStorageCredentialsDetails_v12 {
             String accountName,
             String endpointSuffix,
             String accountKey) {
-        return new AzureStorageCredentialsDetails_v12(accountName, endpointSuffix, AzureStorageCredentialsType.ACCOUNT_KEY, accountKey, null, null, null, null, null);
+        return new AzureStorageCredentialsDetails_v12(accountName, endpointSuffix, AzureStorageCredentialsType.ACCOUNT_KEY, accountKey, null, null, null, null, null, null);
     }
 
     public static AzureStorageCredentialsDetails_v12 createWithSasToken(
             String accountName,
             String endpointSuffix,
             String sasToken) {
-        return new AzureStorageCredentialsDetails_v12(accountName, endpointSuffix, AzureStorageCredentialsType.SAS_TOKEN, null, sasToken, null, null, null, null);
+        return new AzureStorageCredentialsDetails_v12(accountName, endpointSuffix, AzureStorageCredentialsType.SAS_TOKEN, null, sasToken, null, null, null, null, null);
     }
 
     public static AzureStorageCredentialsDetails_v12 createWithManagedIdentity(
             String accountName,
-            String endpointSuffix) {
-        return new AzureStorageCredentialsDetails_v12(accountName, endpointSuffix, AzureStorageCredentialsType.MANAGED_IDENTITY, null, null, null, null, null, null);
+            String endpointSuffix,
+            String managedIdentityClientId) {
+        return new AzureStorageCredentialsDetails_v12(accountName, endpointSuffix, AzureStorageCredentialsType.MANAGED_IDENTITY, null, null, managedIdentityClientId, null, null, null, null);
     }
 
     public static AzureStorageCredentialsDetails_v12 createWithServicePrincipal(
             String accountName,
             String endpointSuffix,
-            String tenantId,
-            String clientId,
-            String clientSecret) {
-        return new AzureStorageCredentialsDetails_v12(accountName, endpointSuffix, AzureStorageCredentialsType.SERVICE_PRINCIPAL, null, null, tenantId, clientId, clientSecret, null);
+            String servicePrincipalTenantId,
+            String servicePrincipalClientId,
+            String servicePrincipalClientSecret) {
+        return new AzureStorageCredentialsDetails_v12(accountName, endpointSuffix, AzureStorageCredentialsType.SERVICE_PRINCIPAL, null, null, null,
+                servicePrincipalTenantId, servicePrincipalClientId, servicePrincipalClientSecret, null);
     }
 
     public static AzureStorageCredentialsDetails_v12 createWithAccessToken(
             String accountName,
             String endpointSuffix,
             AccessToken accessToken) {
-        return new AzureStorageCredentialsDetails_v12(accountName, endpointSuffix, AzureStorageCredentialsType.ACCESS_TOKEN, null, null, null, null, null, accessToken);
+        return new AzureStorageCredentialsDetails_v12(accountName, endpointSuffix, AzureStorageCredentialsType.ACCESS_TOKEN, null, null, null, null, null, null, accessToken);
     }
 }
diff --git a/nifi-nar-bundles/nifi-azure-bundle/pom.xml b/nifi-nar-bundles/nifi-azure-bundle/pom.xml
index 469445c..e18c5a1 100644
--- a/nifi-nar-bundles/nifi-azure-bundle/pom.xml
+++ b/nifi-nar-bundles/nifi-azure-bundle/pom.xml
@@ -27,12 +27,11 @@
 
     <properties>
         <azure-storage.version>8.6.6</azure-storage.version>
-        <azure.core.version>1.21.0</azure.core.version>
-        <!-- upgrade azure-identity to 1.4.x only after https://github.com/Azure/azure-sdk-for-java/issues/25084 has been fixed -->
-        <azure.identity.version>1.3.7</azure.identity.version>
+        <azure.core.version>1.26.0</azure.core.version>
+        <azure.identity.version>1.4.5</azure.identity.version>
         <!-- azure-identity depends on msal4j transitively, keep these versions consistent -->
         <msal4j.version>1.11.0</msal4j.version>
-        <azure-cosmos.version>4.20.0</azure-cosmos.version>
+        <azure-cosmos.version>4.26.0</azure-cosmos.version>
     </properties>
 
     <modules>