Authenticating with rbac Service Principal causes 403 Audience validation failed. Audience did not match

439 Views Asked by At

Authenticating with rbac Service Principal causes 403 Audience validation failed. Audience did not match

I am trying to give an application access to a blob storage container but with minimum required permissions (Read / Write)

Using the azure cli i have done the following steps to attempt this:

az group create -l ${LOCATION} -n ${RESOURCE_GROUP_NAME}

az role definition create --role-definition rw-blob-role.json

rw-blob-role.json:
{
  "assignableScopes": [
    "/subscriptions/{{SUBSCRIPTION_ID}}"
  ],
  "description": "Custom role to allow for read and write access to Azure Storage blob containers and data",
  "name": "{{APP_RW_ROLE_NAME}}",
  "permissions": [
    {
      "actions": [
        "Microsoft.Storage/storageAccounts/blobServices/containers/read",
        "Microsoft.Storage/storageAccounts/blobServices/containers/write"
      ],
      "dataActions": [
        "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read",
        "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/write"
      ],
      "notActions": [],
      "notDataActions": []
    }
  ],
  "type": "Microsoft.Authorization/roleDefinitions"
}


az ad sp create-for-rbac --name ${AZ_SERVICE_PRINCIPAL_NAME} --password ${APP_CLIENT_SECRET}

az role assignment delete --assignee ${AZ_SERVICE_PRINCIPAL_NAME} --role Contributor

az role assignment create --assignee ${AZ_SERVICE_PRINCIPAL_NAME} --role ${APP_RW_ROLE_NAME}

az storage account create --name ${STORAGE_ACCOUNT_NAME} --resource-group ${RESOURCE_GROUP_NAME} --location ${LOCATION} --kind BlobStorage --sku ${STORAGE_ACCOUNT_SKU} --access-tier ${STORAGE_ACCOUNT_ACCESS_TIER}

az storage container create --name ${BLOB_STORAGE_CONTAINER} --account-name ${STORAGE_ACCOUNT_NAME} --public-access off

From this i save the following properties to use by my application:
- TENANT_ID="$(az account show --output tsv --query tenantId)"
- CLIENT_ID="$(az ad sp list --spn ${AZ_SERVICE_PRINCIPAL_NAME} --output tsv --query [0].appId)"
- Client secret: ${APP_CLIENT_SECRET}
- Resource: ${AZ_SERVICE_PRINCIPAL_NAME}
- Storage Account name: ${STORAGE_ACCOUNT_NAME}
- Container name: ${BLOB_STORAGE_CONTAINER}

Using com.microsoft.azure:adal4j i acquire a token:

public AuthenticationResult getToken() {
    ExecutorService service = Executors.newFixedThreadPool(1);
    ClientCredential credential = new ClientCredential(CLIENT_ID, APP_CLIENT_SECRET);
    String authorityTenantUrl = String.format(https://login.microsoftonline.com/%s/oauth2/token, TENANT_ID);

    AuthenticationContext context;
    AuthenticationResult result;
    try {
      context = new AuthenticationContext(authorityTenantUrl, true, service);
      Future<AuthenticationResult> future = context.acquireToken(AZ_SERVICE_PRINCIPAL_NAME, credential, null);
      result = future.get();
    } catch (Exception e) {
      throw new RuntimeException(e);
    } finally {
      service.shutdown();
    }

    if (result == null) {
      throw new RuntimeException("authentication result was null");
    }

    return result;
}

Using the accessToken from the AuthenticationResult and com.microsoft.azure:azure-storage-blob i attempt to fetch a blob:

TokenCredentials credential = new TokenCredentials(accessToken);
HttpPipeline pipeline = StorageURL.createPipeline(credentials, new PipelineOptions());
ServiceURL serviceURL = new ServiceURL("https://STORAGE_ACCOUNT_NAME.blob.core.windows.net", pipeline);
ContainerURL containerURL = serviceURL.createContainerURL(BLOB_STORAGE_CONTAINER);
BlockBlobURL blobURL = containerURL.createBlockBlobURL(identifier);
ByteBuffer byteBuffer = FlowableUtil.collectBytesInBuffer(blobURL.download().blockingGet().body(new ReliableDownloadOptions())).blockingGet();

This causes a StorageException:

<Error>
  <Code>AuthenticationFailed</Code>
  <Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.</Message>
  <AuthenticationErrorDetail>Audience validation failed. Audience did not match.</AuthenticationErrorDetail>
</Error>

I am pretty sure the problem is the AZ_SERVICE_PRINCIPAL_NAME passed to adal4j on acquireToken() but i have no idea what the correct value is. I have tried using the CLIENT_ID and other properties on the Tenant AD and Service Principal.

1

There are 1 best solutions below

0
Tony Ju On BEST ANSWER

You should use https://storage.azure.com/ for the value of Resource.