microsoft / spring-cloud-azure

Spring Cloud Azure is an open-source project that provides seamless Spring integration with Azure services.
https://microsoft.github.io/spring-cloud-azure
MIT License
217 stars 105 forks source link

[BUG] Spring Azure Cloud 4.4.1 Service Bus with stream binder results into AuthorizationFailed #1033

Closed VarshaGadekar closed 1 year ago

VarshaGadekar commented 2 years ago

Describe the bug Spring Azure Cloud 4.4.1 Service Bus with stream binder results into AuthorizationFailed Exception or Stack Trace results into following error

NOTE: on different environment different object id is displayed in error

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.azure.messaging.servicebus.ServiceBusClientBuilder]: Factory method 'serviceBusClientBuilder' threw exception; nested exception is java.lang.RuntimeException: Fetching ServiceBusNamespace with name '<some valid servicebus namespace>' failed due to: com.azure.core.management.exception.ManagementException: Status code 403, "{"error":{"code":"AuthorizationFailed","message":"The client '8f455a17-6010-45b5-9e6a-a39d74a64ac0' with object id '8f455a17-6010-45b5-9e6a-a39d74a64ac0' does not have authorization to perform action 'Microsoft.ServiceBus/namespaces/read' over scope '/subscriptions/<some valid subscription id>/resourceGroups/<some valid resource group>/providers/Microsoft.ServiceBus/namespaces/<some valid servicebus namespace>' or the scope is invalid. If access was recently granted, please refresh your credentials."}}": The client '8f455a17-6010-45b5-9e6a-a39d74a64ac0' with object id '8f455a17-6010-45b5-9e6a-a39d74a64ac0' does not have authorization to perform action 'Microsoft.ServiceBus/namespaces/read' over scope '/subscriptions/<some valid subscription id>/resourceGroups/<some valid resource group>/providers/Microsoft.ServiceBus/namespaces/<some valid servicebus namespace>' or the scope is invalid. If access was recently granted, please refresh your credentials.
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653)
    ... 19 common frames omitted
Caused by: java.lang.RuntimeException: Fetching ServiceBusNamespace with name '<some valid servicebus namespace>' failed due to: com.azure.core.management.exception.ManagementException: Status code 403, "{"error":{"code":"AuthorizationFailed","message":"The client '8f455a17-6010-45b5-9e6a-a39d74a64ac0' with object id '8f455a17-6010-45b5-9e6a-a39d74a64ac0' does not have authorization to perform action 'Microsoft.ServiceBus/namespaces/read' over scope '/subscriptions/<some valid subscription id>/resourceGroups/<some valid resource group>/providers/Microsoft.ServiceBus/namespaces/<some valid servicebus namespace>' or the scope is invalid. If access was recently granted, please refresh your credentials."}}": The client '8f455a17-6010-45b5-9e6a-a39d74a64ac0' with object id '8f455a17-6010-45b5-9e6a-a39d74a64ac0' does not have authorization to perform action 'Microsoft.ServiceBus/namespaces/read' over scope '/subscriptions/<some valid subscription id>/resourceGroups/<some valid resource group>/providers/Microsoft.ServiceBus/namespaces/<some valid servicebus namespace>' or the scope is invalid. If access was recently granted, please refresh your credentials.
    at com.azure.spring.cloud.resourcemanager.implementation.crud.AbstractResourceCrud.get(AbstractResourceCrud.java:62)
    at com.azure.spring.cloud.resourcemanager.implementation.connectionstring.ServiceBusArmConnectionStringProvider.getConnectionString(ServiceBusArmConnectionStringProvider.java:39)
    at com.azure.spring.cloud.core.implementation.factory.AbstractAzureServiceClientBuilderFactory.configureConnectionString(AbstractAzureServiceClientBuilderFactory.java:231)
    at com.azure.spring.cloud.core.implementation.factory.AbstractAzureServiceClientBuilderFactory.configureCore(AbstractAzureServiceClientBuilderFactory.java:152)
    at com.azure.spring.cloud.core.implementation.factory.AbstractAzureAmqpClientBuilderFactory.configureCore(AbstractAzureAmqpClientBuilderFactory.java:58)
    at com.azure.spring.cloud.core.implementation.factory.AbstractAzureServiceClientBuilderFactory.build(AbstractAzureServiceClientBuilderFactory.java:126)
    at com.azure.spring.cloud.autoconfigure.servicebus.AzureServiceBusClientBuilderConfiguration.serviceBusClientBuilder(AzureServiceBusClientBuilderConfiguration.java:50)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
    ... 20 common frames omitted
Caused by: com.azure.core.management.exception.ManagementException: Status code 403, "{"error":{"code":"AuthorizationFailed","message":"The client '8f455a17-6010-45b5-9e6a-a39d74a64ac0' with object id '8f455a17-6010-45b5-9e6a-a39d74a64ac0' does not have authorization to perform action 'Microsoft.ServiceBus/namespaces/read' over scope '/subscriptions/<some valid subscription id >/resourceGroups/<some valid resource group>/providers/Microsoft.ServiceBus/namespaces/<some valid servicebus namespace>' or the scope is invalid. If access was recently granted, please refresh your credentials."}}"
    at java.lang.invoke.MethodHandle.invokeWithArguments(Unknown Source)
    at com.azure.core.implementation.http.rest.ResponseExceptionConstructorCache.invoke(ResponseExceptionConstructorCache.java:56)
    at com.azure.core.implementation.http.rest.RestProxyBase.instantiateUnexpectedException(RestProxyBase.java:377)
    at com.azure.core.implementation.http.rest.AsyncRestProxy.lambda$ensureExpectedStatus$1(AsyncRestProxy.java:117)
    at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:113)
    at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2398)
    at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:171)
    at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2194)
    at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:2068)
    at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:96)
    at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:55)
    at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
    at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:157)
    at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129)
    at reactor.core.publisher.FluxHide$SuppressFuseableSubscriber.onNext(FluxHide.java:137)
    at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129)
    at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129)
    at reactor.core.publisher.FluxHide$SuppressFuseableSubscriber.onNext(FluxHide.java:137)
    at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:122)
    at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)
    at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1816)
    at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:151)
    at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129)
    at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1816)
    at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:151)
    at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.complete(MonoIgnoreThen.java:292)
    at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onNext(MonoIgnoreThen.java:187)
    at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1816)
    at reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:249)
    at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1816)
    at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:151)
    at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129)
    at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1816)
    at reactor.core.publisher.MonoCollect$CollectSubscriber.onComplete(MonoCollect.java:160)
    at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1817)
    at reactor.core.publisher.FluxCallable.subscribe(FluxCallable.java:49)
    at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
    at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:157)
    at reactor.core.publisher.SerializedSubscriber.onNext(SerializedSubscriber.java:99)
    at reactor.core.publisher.FluxRetryWhen$RetryWhenMainSubscriber.onNext(FluxRetryWhen.java:174)
    at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)
    at reactor.core.publisher.Operators$MonoInnerProducerBase.complete(Operators.java:2664)
    at reactor.core.publisher.MonoSingle$SingleSubscriber.onComplete(MonoSingle.java:180)
    at reactor.core.publisher.MonoFlatMapMany$FlatMapManyInner.onComplete(MonoFlatMapMany.java:260)
    at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:144)
    at reactor.core.publisher.FluxDoFinally$DoFinallySubscriber.onComplete(FluxDoFinally.java:128)
    at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onComplete(FluxMapFuseable.java:152)
    at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1817)
    at reactor.core.publisher.MonoCollect$CollectSubscriber.onComplete(MonoCollect.java:160)
    at reactor.core.publisher.FluxHandle$HandleSubscriber.onComplete(FluxHandle.java:220)
    at reactor.core.publisher.FluxMap$MapConditionalSubscriber.onComplete(FluxMap.java:275)
    at reactor.netty.channel.FluxReceive.onInboundComplete(FluxReceive.java:400)
    at reactor.netty.channel.ChannelOperations.onInboundComplete(ChannelOperations.java:419)
    at reactor.netty.channel.ChannelOperations.terminate(ChannelOperations.java:473)
    at reactor.netty.http.client.HttpClientOperations.onInboundNext(HttpClientOperations.java:703)
    at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:93)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
    at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:327)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:299)
    at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1373)
    at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1236)
    at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1285)
    at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:510)
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:449)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:279)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:722)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:658)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:584)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:496)
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.lang.Thread.run(Unknown Source)
    Suppressed: java.lang.Exception: #block terminated with an error
        at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:99)
        at reactor.core.publisher.Mono.block(Mono.java:1707)
        at com.azure.resourcemanager.resources.fluentcore.arm.collection.implementation.GroupableResourcesImpl.getByResourceGroup(GroupableResourcesImpl.java:106)
        at com.azure.resourcemanager.resources.fluentcore.arm.collection.implementation.GroupableResourcesImpl.getByResourceGroup(GroupableResourcesImpl.java:28)
        at com.azure.spring.cloud.resourcemanager.implementation.crud.ServiceBusNamespaceCrud.internalGet(ServiceBusNamespaceCrud.java:35)
        at com.azure.spring.cloud.resourcemanager.implementation.crud.ServiceBusNamespaceCrud.internalGet(ServiceBusNamespaceCrud.java:15)
        at com.azure.spring.cloud.resourcemanager.implementation.crud.AbstractResourceCrud.get(AbstractResourceCrud.java:59)
        at com.azure.spring.cloud.resourcemanager.implementation.connectionstring.ServiceBusArmConnectionStringProvider.getConnectionString(ServiceBusArmConnectionStringProvider.java:39)
        at com.azure.spring.cloud.core.implementation.factory.AbstractAzureServiceClientBuilderFactory.configureConnectionString(AbstractAzureServiceClientBuilderFactory.java:231)
        at com.azure.spring.cloud.core.implementation.factory.AbstractAzureServiceClientBuilderFactory.configureCore(AbstractAzureServiceClientBuilderFactory.java:152)
        at com.azure.spring.cloud.core.implementation.factory.AbstractAzureAmqpClientBuilderFactory.configureCore(AbstractAzureAmqpClientBuilderFactory.java:58)
        at com.azure.spring.cloud.core.implementation.factory.AbstractAzureServiceClientBuilderFactory.build(AbstractAzureServiceClientBuilderFactory.java:126)
        at com.azure.spring.cloud.autoconfigure.servicebus.AzureServiceBusClientBuilderConfiguration.serviceBusClientBuilder(AzureServiceBusClientBuilderConfiguration.java:50)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
        at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653)
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:638)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:955)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734)
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:308)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295)

To Reproduce

Code Snippet

spring.cloud.azure.credential.client-id=<some valid value>
spring.cloud.azure.credential.client-secret=<some valid value>
spring.cloud.azure.profile.tenant-id=<some valid value>
spring.cloud.azure.servicebus.namespace=<some valid value>
spring.cloud.azure.profile.subscription-id=<some valid value>
spring.cloud.azure.servicebus.resource.resource-group=<some valid value>

Expected behavior

Screenshots

Content (please complete the following information if possible):

Additional context

Information Checklist

saragluna commented 2 years ago

@VarshaGadekar do you need to create the service bus queue or topic? If not, you could remove the following properties

spring.cloud.azure.profile.subscription-id=<some valid value>
spring.cloud.azure.servicebus.resource.resource-group=<some valid value>

The error is because the service principal isn't authorized to read resources in the given namespace.

VarshaGadekar commented 2 years ago

I dont want to create queue or topic. The application is either producer or consumer based on business logic for different queues/topics.

spring.cloud.azure.credential.client-id= spring.cloud.azure.credential.client-secret= spring.cloud.azure.profile.tenant-id= spring.cloud.azure.servicebus.namespace=

When I tried to use without resource-group and subscription-id with only above parameters it gives following error: {"dd.trace_id":"0", "dd.span_id":"0", "thread_id":"reactor-executor-1", "az.sdk.message":"onLinkRemoteClose","connectionId":"MF_26ff17_1667798177941","errorCondition":"amqp:unauthorized-access","errorDescription":"Unauthorized access. 'Listen' claim(s) are required to perform this operation. Resource: 'sb://.servicebus.windows.net/'. TrackingId:c434470f795743a4a3b870381908184e_G17, SystemTracker:gateway7, Timestamp:2022-11-07T05:16:22","linkName":"_f5d972_1667798178172","entityPath":""}

I checked that the client-id, client-secret, tenant-id and namespace are correctly configured and access policy has 'Manage', 'Send', 'Listen' assigned.

saragluna commented 2 years ago

Have you assigned the Service Bus Owner/Sender/Receiver role to the service principal https://microsoft.github.io/spring-cloud-azure/current/reference/html/index.html#authorize-access-with-azure-active-directory? @VarshaGadekar

VarshaGadekar commented 2 years ago

hi @saragluna can you please confirm why Spring Azure Cloud needs to assign above roles with Azure AD? Because if we directly use Azure APIs it does not need these roles. keyvault Endpoint with tenant-id, client-id and client-secret works and provides us the sas token.

saragluna commented 2 years ago

@VarshaGadekar are you storing the sas token in Key Vault?

Put KV aside, if you try to access service bus, there are two approaches: one via the connection string (this will give you the sas token), another is via Azure AD service principals or managed identities (this approach requires the roles).

What did you mean by using Azure APIs directly? What are these APIs and how do you call them?

VarshaGadekar commented 2 years ago

yes we are using key-vault.

following way with Azure API's worked:

String serviceBusSAS = AzureUtils.getServiceBusSAS(clientId, clientSecret, keyvaultUrl, secretName);
com.microsoft.azure.servicebus.QueueClient queueClient = com.microsoft.azure.servicebus.QueueClient(
                new com.microsoft.azure.servicebus.primitives.ConnectionStringBuilder(serviceBusSAS + ";EntityPath=my-test-service-bus-queue", "my-test-service-bus-queue"),
                ReceiveMode.RECEIVEANDDELETE);

once above queueClient is created as bean we can use as follows

AzureUtils.sendServiceBusMessage(queueClient, objectMapper.writeValueAsString(fileQueueMessage));

AzureUtils.java has following

import java.time.Duration;
import org.springframework.http.MediaType;
import com.azure.messaging.servicebus.ServiceBusMessage;
import com.azure.messaging.servicebus.ServiceBusSenderClient;
import com.microsoft.azure.servicebus.Message;

with method

    public static void sendServiceBusMessage(final ServiceBusSenderClient client, final String content) {
        final ServiceBusMessage message = new ServiceBusMessage(content);
        message.setContentType(MediaType.APPLICATION_JSON_VALUE);
        message.setTimeToLive(Duration.ofMinutes(10));
        client.sendMessage(message);
    }
saragluna commented 2 years ago

Ok got it. The serviceBusSAS is the connection string for the service bus namespace, so in the code you posted the application connects to the service bus using the connection string. The service principal (client id) only needs the role to access the KV.

But if you are connecting to the Service Bus using that service principal, you need to assign it the role I mentioned before.

Another approach is you provide the spring.cloud.azure.servicebus.connection-string property to your application. The property can be saved to the KV using key spring-cloud-azure-servicebus-connectionstring.

VarshaGadekar commented 2 years ago

yes spring.cloud.azure.servicebus.connection-string is working fine. However can you please confirm if it is possible for Spring Azure Cloud Stream Binder to not mandate the role Owner/Sender/Receiver with Azure AD? Can there be some way with spring azure cloud stream binder (may be in future) to use above way which will need only client id?

saragluna commented 2 years ago

In my understanding, if you want to connect using an Azure AD user/service principal/managed identity, you need to grant permissions to that identity. Just like how you assign role/access policy to the service principal to access KV.

The request is not coming from the library, it's coming from the Azure Service. Whenever you authenticate the application using an Azure AD identity, the client will request an access token from Azure AD, and then use that token to access the Azure Service. In this process, it reflects how it works with OAuth 2.0, the Azure AD is the authorization server, and the Azure Service is the resource server. The Azure Service's responsibility is to check that the token sent to it has a corresponding role in performing actions.

What do you mean by spring azure cloud stream binder (may be in future) to use above way which will need only client id?

VarshaGadekar commented 2 years ago

Thank you for providing all details. I was saying if internally spring azure cloud stream binder can provide some way to use service principal and internally it can generate the spring.cloud.azure.servicebus.connection-string with service principle and skipping the Azure AD identity route.

saragluna commented 2 years ago

@VarshaGadekar yes, we can provide that by requesting Azure Resource Manager (ARM) for the connection string. But this step requires the service principal to have management roles.

VarshaGadekar commented 1 year ago

ok thank you @saragluna.

saragluna commented 1 year ago

I will close this issue now, please reopen it if you have any other questions.