Azure / azure-storage-java

Microsoft Azure Storage Library for Java

Home Page:https://docs.microsoft.com/en-us/java/api/overview/azure/storage

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Unable to find MSI interface to connect to blob storage

kirankbs opened this issue · comments

Which service(blob, file, queue, table) does this issue concern?

blob

Which version of the SDK was used?

azure-storage 8.4.0

Please note that if your issue is with v11, we are recommending customers either move back to v11 or move to v12 (currently in preview) if at all possible. Hopefully this resolves your issue, but if there is some reason why moving away from v11 is not possible at this time, please do continue to ask your question and we will do our best to support you. The README for this SDK has been updated to point to more information on why we have made this decision.

What problem was encountered?

We are migrating to Azure blob storage. Everything worked with simple authentication connection string. Just used below:

val storageAccount: CloudStorageAccount = CloudStorageAccount.parse(blobConf.connectionString)
  val serviceClient = storageAccount.createCloudBlobClient()
  val blobContainer: CloudBlobContainer = serviceClient.getContainerReference(blobConf.container)

Now, I really need to use RBAC. I failed to find example or documentation that how can i use it java API for this.

It will be great if i get any help

Have you found a mitigation/solution?

No

For instance i tried below python code from AZURE VM and worked:

import azure.common
from azure.storage.blob import BlockBlobService
from msrestazure.azure_active_directory import MSIAuthentication

credentials = MSIAuthentication(resource='https://storage.azure.com/')
blockblob_service = BlockBlobService(account_name, token_credential=credentials)

Trying to achieve same authentication approach here.

Hi, @kirankbs. Thank you for your question. There is a StorageCredentialsToken type that accepts an account and a token value. You can then pass this credential object along with the URI to the container into the construction of your CloudBlobContainer object. I think this should satisfy your use case. Please let me know if you need more help.

Can you please tell me how can I get token if VM is not set with one. I did not pass any token with python code mentioned above and similar way I tried below:

CODE:
dependencies:

libraryDependencies += "com.microsoft.azure" % "azure-storage" % "8.4.0"
libraryDependencies += "com.microsoft.azure.msi_auth_token_provider" % "azure-authentication-msi-token-provider" % "1.0.0-Beta-2"
import com.microsoft.azure.storage.{CloudStorageAccount, StorageCredentialsToken}
import com.microsoft.azure.msiAuthTokenProvider._
import com.microsoft.azure.storage.blob.{CloudBlobClient, CloudBlobContainer}
import java.net.URI
import java.io.{File, FileInputStream}

object Main extends App {
val credsProvider = MSICredentials.getMSICredentials
val token: MSIToken = credsProvider.getToken(null)
val tokenValue: String = token.accessToken
val storageCredentialsToken = new StorageCredentialsToken("my-blob-container", tokenValue)
val blobContainer: CloudBlobContainer = new CloudBlobContainer(new URI("https://xxx.blob.core.windows.net/my-blob-container"), storageCredentialsToken)
val buildBlob = blobContainer.getBlockBlobReference("build.scala")

val buildBlobFile = File.createTempFile("build", ".scala")
buildBlob.upload(new FileInputStream(buildBlobFile), buildBlobFile.length)
}

OUTPUT

[info] running Main
[error] (run-main-0) com.microsoft.azure.storage.StorageException: Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
[error] com.microsoft.azure.storage.StorageException: Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
[error] 	at com.microsoft.azure.storage.StorageException.translateException(StorageException.java:87)
[error] 	at com.microsoft.azure.storage.core.StorageRequest.materializeException(StorageRequest.java:305)
[error] 	at com.microsoft.azure.storage.core.ExecutionEngine.executeWithRetry(ExecutionEngine.java:196)
[error] 	at com.microsoft.azure.storage.blob.CloudBlockBlob.uploadFullBlob(CloudBlockBlob.java:1035)
[error] 	at com.microsoft.azure.storage.blob.CloudBlockBlob.upload(CloudBlockBlob.java:864)
[error] 	at com.microsoft.azure.storage.blob.CloudBlockBlob.upload(CloudBlockBlob.java:743)
[error] 	at com.microsoft.azure.storage.blob.CloudBlockBlob.upload(CloudBlockBlob.java:712)
[error] 	at Main$.delayedEndpoint$Main$1(Sample.scala:16)
[error] 	at Main$delayedInit$body.apply(Sample.scala:7)
[error] 	at scala.Function0.apply$mcV$sp(Function0.scala:39)
[error] 	at scala.Function0.apply$mcV$sp$(Function0.scala:39)
[error] 	at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:17)
[error] 	at scala.App.$anonfun$main$1$adapted(App.scala:80)
[error] 	at scala.collection.immutable.List.foreach(List.scala:392)
[error] 	at scala.App.main(App.scala:80)
[error] 	at scala.App.main$(App.scala:78)
[error] 	at Main$.main(Sample.scala:7)
[error] 	at Main.main(Sample.scala)
[error] 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[error] 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[error] 	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[error] 	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
  1. Created Managed Identity
  2. Storage Blob Data Contributor role is assigned to the Container
  3. User assigned identity is attached to VM

The token is not required to access the storage in this case and tested successfully with Python code. Please let me know if I am missing something!

Just to clarify, are you running both the Java and Python applications in the same environment?

Python code for the sanity check of the infrastructure setup. Later, Scala microservice will be running in the environment.

@rickle-msft You are right that we need the token from Active Directory to authorize the storage container.
I referred section How a user-assigned managed identity works with an Azure VM from documentation and tried to debug the issue. Below are my debug findings:

  1. Made sure managed identity is attached to VM by calling endpoint http://169.254.169.254/metadata/identity/oauth2/token inside VM and received the proper access token.
  2. Hardcoded above access token and created StorageCredentialsToken with the account name.
  3. Created CloudBlobContainer with the absolute path of the container(URI) and above created credentials.
  4. Got blockBlob reference and tried to upload a temp file.

Sample Code:

  val tempAccessToken = "xxx"
  val storageCredentialsToken =
    new StorageCredentialsToken("xxx", tempAccessToken)
  val container =
    new CloudBlobContainer(
      new URI("xxx/my-blob-container"),
      storageCredentialsToken
    )
  val buildBlob = container.getBlockBlobReference("build.scala")

  val buildBlobFile = File.createTempFile("build", ".scala")
  buildBlob.upload(new FileInputStream(buildBlobFile), buildBlobFile.length)

Still getting below error:

[error] (run-main-0) com.microsoft.azure.storage.StorageException: Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
[error] com.microsoft.azure.storage.StorageException: Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.

Do you think I am missing any steps or proper usage of API

@kirankbs I'm glad to hear you've made some progress. The first thought that comes to mind is whether the Token you are getting grants the right privileges for writing a blob. My understanding of RBAC is that the token, which represents a certain authorized user, is given certain roles, and those roles are what determine the privileges. If you don't have the right permissions, you could see this authentication failure. I think that you need the role of Data Contributor to write blobs?

If you feel you have all the right permissions to be able to perform this operation, could you please share a Fiddler trace (redacting sensitive information) so we can check whether the Bearer Token header is getting set correctly?

@rickle-msft , I can confirm the token is not a problem:

  1. I checked the dashboard and the Storage Blob Data Contributor role is given.
  2. When I tested with a python script, it worked.
  3. http://169.254.169.254/metadata/identity/oauth2/token inside VM and received the proper access token and same client-id(Managed Identity) configured.

I wonder the issue can be as mentioned here:
https://blogs.msdn.microsoft.com/kwill/2013/08/27/http-403-server-failed-to-authenticate-the-request-when-using-shared-access-signatures/

I checked source code where we are setting start time:

return BlobRequestOptions.populateAndApplyDefaults(options, blobType, client, true);

Meantime I will try to get Fiddler Trace Azure Ubuntu VM.

@rickle-msft I am not able to achieve to collect HTTP traces from Ubuntu Azure VM. Do you know any known and easy way that I can collect Http traces?

Meanwhile, I tried with version 12.0.0.4.preview and it served out the goal of connecting Storage using RBAC, upload and Generate BLOB URL with SAS signature.

I really want to try out with a Stable version of Library instead of preview one.

@kirankbs Well you're in luck! We are GAing v12 today, so if it works for you there and the only blocker to upgrading was preview vs GA, that should go away in a matter of hours. If you want to stay on v8 still, I will look into contacting the person who contributed to implementing the MSI stuff and see if he has some more insights as to what may be going on. Let me know which path is preferable to you.

Apologies for the delay. Preparations for this release have made our response times a little slow.

@rickle-msft do you mean semantic versioning starts with the GA release of v12?
If yes, I am happy to use V12.

But, do you think this thread is useful for the users who want to stick to V8? then please troubleshoot from your side else you can close this issue

@kirankbs Yes, we are releasing 12.0.0 today, no longer a preview, and we will be following semantic versioning here on out. We are in fact waiting for the release to go out as I type. I'm glad this will get you unblocked, if not in the way we originally expected :)

I will close this issue for now as we are trying to emphasize v12, but if someone else encounters this thread and needs support, they should feel free to comment and will pick it up from there.

@rickle-msft When can I expect v12 availability at Maven repo? I see current version is v11.0.1

You can find it here.

Maven's search seems to take a little while to index new artifacts even after they're published, but having a direct URL usually works. And you should be able to pull it into a project now.

Worked!
Thank You :-)

Just to clarify, why does Maven repo does not show the new stable V12 release:
https://mvnrepository.com/artifact/com.microsoft.azure/azure-storage-blob

There was a change to the package group due to Azure's SDK unification efforts. Replace com.microsoft.azure in that url with just com.azure and you should see it.

@rickle-msft @jaschrep-msft Can you please help me that how can I be updated about V12. any gitter channel or forum etc? because we are going to use this in Production.

@kirankbs We don't have any gitter channel or other such forum setup. All discussions and development are currently happening through tracking GitHub issues, and we are making an intentional effort to have a quick response time to any conversations happening on github. You can search for issues tagged with "Storage" and "Client" to only see issues for this service. You could also star the repo to follow it, but you may get a good number of extra notifications unrelated to Storage.