AzureAuth
AzureAuth copied to clipboard
Can't use get_managed_token for system assigned MI or user assigned MI within App Service, error 404
Hello,
Using a system or user assigned identity in combination with get_managed_token gives a 404 error. Could not get the function working from within an app service running a Shiny app using a managed identity to access a storage account. AzureAuth seems to make the wrong API call at and endpoint /MSI/token/token that does not exist and hence returns 404 since it should be http://{endpoint}/MSI/token. From within a VM for local development obtaining a token using managed identity using AzureAuth works as expected.
Current workaround for the app service is to create the API call manually instead of using AzureAuth for a system assigned MI reading data from a storage account in a Shiny app hosted in App Services.
library(httr)
library(AzureStor)
# Fetch / set variables for API call within app service running Shiny app running on Shiny server
api_version <- "2019-08-01" ## Might work with newer versions as well
mi_endpoint <- Sys.getenv("MSI_ENDPOINT")
mi_secret <- Sys.getenv("MSI_SECRET")
resource <- "https://storage.azure.com"
storage_account <- "https://<storageaccountname>.blob.core.windows.net"
container_name <- "mycontainer"
headers <- c(
`X-IDENTITY-HEADER` = mi_secret
)
## Fetch managed identity token
res <- GET(url = paste0(mi_endpoint, '?resource=', resource, "&api-version=", api_version), add_headers(.headers=headers))
mi_token <- content(res)$access_token
## Connect to storage account using MI
ad = storage_endpoint(storage_account, token = mi_token)
cont = storage_container(ad, container_name)
I was experiencing the exact same issue as you described and your workaround is working flawlessly for us now! Thank you so much! And indeed the package is in dire need of an update...
The endpoint should already be taken from the MSI_ENDPOINT environment variable, the same as what you've got in your sample code. It gets the secret from the MSI_SECRET variable as well, but it puts it into the HTTP 'secret' header instead of 'X-IDENTITY-HEADER'. Are you sure you've got your variables set correctly? In particular, don't put the token bit at the end of MSI_ENDPOINT.
Below is untested but perhaps the second token part is added in this snippet in AzureTokenManaged. Reading the MSI endpoint sys variable with Sys.getenv("MSI_ENDPOINT") already gives an URL that ends in /token so adding another /token part to the uri might be the issue.
private=list(
initfunc=function(init_args)
{
stopifnot(is.list(self$token_args))
uri <- private$aad_uri("token") ### Here?
query <- utils::modifyList(self$token_args,
list(`api-version`=getOption("azure_imds_version"), resource=self$resource))
secret <- Sys.getenv("MSI_SECRET")
headers <- if(secret != "")
httr::add_headers(secret=secret)
else httr::add_headers(metadata="true")
httr::GET(uri, headers, query=query)
}
))
Yes, the token is added during processing. This works in my testing, but that was in an Azure VM, not an app service. So the MSI_ENDPOINT variable isn't under your control? Does it work with other code that uses the service?
Hello, ok thanks for the clarification. Within an App Service the system assigned MI MSI_ENDPOINT environment variable is set by azure and includes the /token bit in the URL already.
Are there any prospects for fixing this?