Suscribirte a los eventos de una cuenta en Azure Storage desde otro tenant con Azure Event Grid

La semana pasada, uno de nuestros clientes me preguntó si era posible este escenario: necesitaban suscribirse a una cuenta de almacenamiento de Azure Storage, a través de los eventos que se generan en Event Grid, con un Service Bus que se encontraba en otro tenant diferente. La respuesta fue que sí y hoy quiero compartir contigo cómo hacerlo.

Un usuario con permisos en las dos suscripciones de ambos tenants

Lo primero que necesitas es un usuario con permisos suficientes para llevar a cabo la operación. Como mínimo debes tener permisos de Contributor sobre la suscripción, si vas a crear los recursos como se detalla más adelante, o sobre los recursos que ya tienes. Para comprobarlo puedes utilizar los siguientes comandos:

SUBSCRIPTION_FOR_THE_STORAGE="<SUBSCRIPTION_ID>"
SUBSCRIPTION_FOR_THE_SERVICE_BUS="<SUBSCRIPTION_ID>"

# The user needs permissions in both tenants
az login
#Check permissions
az account set --subscription $SUBSCRIPTION_FOR_THE_STORAGE
az role assignment list \
--assignee $(az ad signed-in-user show --query objectId -o tsv) \
-o table
az account set --subscription $SUBSCRIPTION_FOR_THE_SERVICE_BUS
az role assignment list \
--assignee $(az ad signed-in-user show --query objectId -o tsv) \
-o table

Es importante que, si cambias los permisos del usuario para hacer esta tarea, refresques el login del usuario para que se recupere el token actualizado con los nuevos permisos.

Crear los recursos

Si todavía no los tienes, puedes crear los recursos que necesitas con los siguientes parámetros:

# Variables for the storage
RG_STORAGE="storage-in-a-different-tenant"
STORAGE_ACCOUNT_NAME="<YOUR_ACCOUNT_NAME>"
LOCATION="westeurope"

# Create resource group
az group create --name $RG_STORAGE --location $LOCATION --subscription $SUBSCRIPTION_FOR_THE_STORAGE
# Create storage account
az storage account create \
--resource-group $RG_STORAGE \
--name $STORAGE_ACCOUNT_NAME \
--location $LOCATION \
--sku Standard_LRS \
--subscription $SUBSCRIPTION_FOR_THE_STORAGE

# Get storage account resource ID
STORAGE_ACCOUNT_ID=$(az storage account show \
--resource-group $RG_STORAGE \
--name $STORAGE_ACCOUNT_NAME \
--subscription $SUBSCRIPTION_FOR_THE_STORAGE \
--query id \
--out tsv)

# Variables for the service bus
RESOURCE_GROUP="process-in-a-different-tenant"
SERVICE_BUS_NAME="<YOUR_SERVICE_BUS_NAME>"
LOCATION="westeurope"
# Create a resource group
az group create --name $RESOURCE_GROUP --location $LOCATION --subscription $SUBSCRIPTION_FOR_THE_SERVICE_BUS
# Create Service Bus namespace
az servicebus namespace create \
--resource-group $RESOURCE_GROUP \
--name $SERVICE_BUS_NAME \
--location $LOCATION \
--sku Standard \
--subscription $SUBSCRIPTION_FOR_THE_SERVICE_BUS
# Create Service Bus queue
QUEUE_NAME=$STORAGE_ACCOUNT_NAME
az servicebus queue create \
--resource-group $RESOURCE_GROUP \
--namespace-name $SERVICE_BUS_NAME \
--name $STORAGE_ACCOUNT_NAME \
--enable-partitioning true \
--subscription $SUBSCRIPTION_FOR_THE_SERVICE_BUS
# Get Service Bus queue resource ID
SERVICE_BUS_QUEUE_ID=$(az servicebus queue show \
--resource-group $RESOURCE_GROUP \
--namespace-name $SERVICE_BUS_NAME \
--name $STORAGE_ACCOUNT_NAME \
 --subscription $SUBSCRIPTION_FOR_THE_SERVICE_BUS \
--query id \
--out tsv)

Suscribirse a la cuenta de almacenamiento a través de Service Bus

Con todo lo anterior, el último paso es suscribirse a través de Service Bus, en este ejemplo, a los eventos que ocurran en la cuenta en el otro tenant. Para ello, debes hacer uso de los IDs recuperados anteriormente en las variables STORAGE_ACCOUNT_ID y SERVICE_BUS_QUEUE_ID, con el fin de hacer referencia absoluta a los recursos:

# Subscribe Azure Storage account via Event Grid using the Service Bus queue 
az eventgrid event-subscription create \
--name $STORAGE_ACCOUNT_NAME-servicebus-sub \
 --source-resource-id $STORAGE_ACCOUNT_ID \
--endpoint-type servicebusqueue \
--endpoint $SERVICE_BUS_QUEUE_ID 

Si por algún motivo este comando te da error, como que no tienes los permisos suficientes (es posible que no tengas actualizada la versión de Azure CLI) puedes lanzar también la llamada directamente a la API REST:

STORAGE_TENANT="<STORAGE_TENANT_ID>"
SERVICE_BUS_TENANT="<SERVICE_BUS_TENANT_ID>"
URL="/subscriptions/$SUBSCRIPTION_FOR_THE_STORAGE/resourceGroups/$RG_STORAGE/providers/Microsoft.Storage/storageAccounts/$STORAGE_ACCOUNT_NAME/providers/Microsoft.EventGrid/eventSubscriptions/$STORAGE_ACCOUNT_NAME-servicebussub?api-version=2020-01-01-preview"
PRIMARY_TOKEN=$(az account get-access-token --tenant $STORAGE_TENANT | jq -r .accessToken)                
primaryToken="Bearer $PRIMARY_TOKEN" 
AUX_TOKEN=$(az account get-access-token --tenant $SERVICE_BUS_TENANT | jq -r .accessToken)
auxToken="Bearer $AUX_TOKEN"
                
az rest --uri $URL \
--method PUT \
--skip-authorization-header \
--headers Authorization="$primaryToken" \
x-ms-authorization-auxiliary="$auxToken" \
ContentType="application/json" \
--body "{\"properties\":{\"destination\":{\"endpointType\":\"ServiceBusQueue\",\"properties\":{\"resourceId\":\"/subscriptions/$SUBSCRIPTION_FOR_THE_SERVICE_BUS/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.ServiceBus/namespaces/$SERVICE_BUS_NAME/queues/$QUEUE_NAME\"}},\"eventDeliverySchema\":\"EventGridSchema\"}}"

El resultado será el siguiente en el portal de Azure:

Azure Service Bus suscrito a un Azure Storage en otro tenant

Para comprobar que todo funciona correctamente, basta con subir algunos archivos a la cuenta de almacenamiento y comprobarás que comienzan a llegar mensajes a tu cuenta de Azure Service Bus.

¡Saludos!