Protección de una cuenta de Azure Maps con un token de SAS
En este artículo se describe cómo crear una cuenta de Azure Maps con un token de SAS almacenado con seguridad que se puede usar para llamar a la API REST de Azure Maps.
Prerrequisitos
Suscripción a Azure. Si aún no tiene una cuenta de Azure, regístrese para obtener una cuenta gratuita.
Permiso de rol Propietario en la suscripción de Azure. Necesita los permisos de Propietario para:
- Crear un almacén de claves en Azure Key Vault.
- Cree una identidad administrada asignada por el usuario.
- Asignar un rol a la identidad administrada.
- Crear una cuenta de Azure Maps.
La CLI de Azure está instalada para implementar los recursos.
Escenario de ejemplo: almacenamiento seguro de un token de SAS
Una credencial de token de SAS concede el nivel de acceso especificado a cualquier persona que lo tenga, hasta que el token expire o se revoque el acceso. Las aplicaciones que usan la autenticación de token de SAS tienen que almacenar las claves de forma segura.
En este escenario se almacena de forma segura un token de SAS como secreto en Azure Key Vault y se distribuye el token en un cliente público. Los eventos en el ciclo de vida de una aplicación pueden generar nuevos tokens de SAS sin interrumpir las conexiones activas que usan tokens existentes.
Para más información sobre cómo configurar Key Vault, consulte la Guía del desarrollador de Azure Key Vault.
En el escenario de ejemplo siguiente se usan dos implementaciones de plantilla de Azure Resource Manager (ARM) para realizar los pasos siguientes:
- Cree un almacén de claves.
- Cree una identidad administrada asignada por el usuario.
- Asigne el control de acceso basado en rol (RBAC) Lector de datos de Azure Maps a la identidad administrada asignada por el usuario.
- Cree una cuenta de Azure Maps con una configuración de uso compartido de recursos entre orígenes (CORS) y adjunte la identidad administrada asignada por el usuario.
- Cree y guarde un token de SAS en el almacén de Azure Key Vault.
- Recupere el secreto del token de SAS del almacén de claves.
- Cree una solicitud a la API REST de Azure Maps que usa el token de SAS.
Cuando haya finalizado, debería ver los resultados de la API REST de Azure Maps Search Address (Non-Batch)
en PowerShell con la CLI de Azure. Los recursos de Azure se implementan con permisos para conectarse a la cuenta de Azure Maps. Hay controles para el límite de velocidad máximo, las regiones permitidas, la directiva de CORS configurada con localhost
y RBAC de Azure.
Implementación de recursos de Azure con la CLI de Azure
En los pasos siguientes se describe cómo crear y configurar una cuenta de Azure Maps con autenticación de token de SAS. En este ejemplo, la CLI de Azure se ejecuta en una instancia de PowerShell.
Inicie sesión en la suscripción de Azure con
az login
.Registre de Key Vault, identidades administradas y Azure Maps para la suscripción.
az provider register --namespace Microsoft.KeyVault az provider register --namespace Microsoft.ManagedIdentity az provider register --namespace Microsoft.Maps
Recupere su identificador de objeto de Microsoft Entra.
$id = $(az rest --method GET --url 'https://graph.microsoft.com/v1.0/me?$select=id' --headers 'Content-Type=application/json' --query "id")
Cree un archivo de plantilla denominado prereq.azuredeploy.json con el siguiente contenido:
{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Specifies the location for all the resources." } }, "keyVaultName": { "type": "string", "defaultValue": "[concat('vault', uniqueString(resourceGroup().id))]", "metadata": { "description": "Specifies the name of the key vault." } }, "userAssignedIdentityName": { "type": "string", "defaultValue": "[concat('identity', uniqueString(resourceGroup().id))]", "metadata": { "description": "The name for your managed identity resource." } }, "objectId": { "type": "string", "metadata": { "description": "Specifies the object ID of a user, service principal, or security group in the Azure AD tenant for the vault. The object ID must be unique for the set of access policies. Get it by using Get-AzADUser or Get-AzADServicePrincipal cmdlets." } }, "secretsPermissions": { "type": "array", "defaultValue": [ "list", "get", "set" ], "metadata": { "description": "Specifies the permissions to secrets in the vault. Valid values are: all, get, list, set, delete, backup, restore, recover, and purge." } } }, "resources": [ { "type": "Microsoft.ManagedIdentity/userAssignedIdentities", "name": "[parameters('userAssignedIdentityName')]", "apiVersion": "2018-11-30", "location": "[parameters('location')]" }, { "apiVersion": "2021-04-01-preview", "type": "Microsoft.KeyVault/vaults", "name": "[parameters('keyVaultName')]", "location": "[parameters('location')]", "properties": { "tenantId": "[subscription().tenantId]", "sku": { "name": "Standard", "family": "A" }, "enabledForTemplateDeployment": true, "accessPolicies": [ { "objectId": "[parameters('objectId')]", "tenantId": "[subscription().tenantId]", "permissions": { "secrets": "[parameters('secretsPermissions')]" } } ] } } ], "outputs": { "userIdentityResourceId": { "type": "string", "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('userAssignedIdentityName'))]" }, "userAssignedIdentityPrincipalId": { "type": "string", "value": "[reference(parameters('userAssignedIdentityName')).principalId]" }, "keyVaultName": { "type": "string", "value": "[parameters('keyVaultName')]" } } }
Implemente los recursos de requisitos previos que creó en el paso anterior. Proporcione su propio valor para
<group-name>
. Asegúrese de usar el mismo valorlocation
que la cuenta de Azure Maps.az group create --name <group-name> --location "East US" $outputs = $(az deployment group create --name ExampleDeployment --resource-group <group-name> --template-file "./prereq.azuredeploy.json" --parameters objectId=$id --query "[properties.outputs.keyVaultName.value, properties.outputs.userAssignedIdentityPrincipalId.value, properties.outputs.userIdentityResourceId.value]" --output tsv)
Cree un archivo de plantilla azuredeploy.json para aprovisionar la cuenta de Azure Maps, la asignación de roles y el token de SAS.
Nota:
Retirada del plan de tarifa Gen1 de Azure Maps
El plan de tarifa de Gen1 ya está en desuso y se retirará el 15/9/26. El plan de tarifa Gen2 reemplaza al plan de tarifa Gen1 (tanto S0 como S1). Si la cuenta de Azure Maps tiene seleccionado el plan de tarifa Gen1, puede cambiar a los precios de Gen2 antes de que se retire; de lo contrario, se actualizará automáticamente. Para obtener más información, consulte Administración del plan de tarifa de la cuenta de Azure Maps.
{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Specifies the location for all the resources." } }, "keyVaultName": { "type": "string", "metadata": { "description": "Specifies the resourceId of the key vault." } }, "accountName": { "type": "string", "defaultValue": "[concat('map', uniqueString(resourceGroup().id))]", "metadata": { "description": "The name for your Azure Maps account." } }, "userAssignedIdentityResourceId": { "type": "string", "metadata": { "description": "Specifies the resourceId for the user assigned managed identity resource." } }, "userAssignedIdentityPrincipalId": { "type": "string", "metadata": { "description": "Specifies the resourceId for the user assigned managed identity resource." } }, "pricingTier": { "type": "string", "allowedValues": [ "S0", "S1", "G2" ], "defaultValue": "G2", "metadata": { "description": "The pricing tier for the account. Use S0 for small-scale development. Use S1 or G2 for large-scale applications." } }, "kind": { "type": "string", "allowedValues": [ "Gen1", "Gen2" ], "defaultValue": "Gen2", "metadata": { "description": "The pricing tier for the account. Use Gen1 for small-scale development. Use Gen2 for large-scale applications." } }, "guid": { "type": "string", "defaultValue": "[guid(resourceGroup().id)]", "metadata": { "description": "Input string for new GUID associated with assigning built in role types." } }, "startDateTime": { "type": "string", "defaultValue": "[utcNow('u')]", "metadata": { "description": "Current Universal DateTime in ISO 8601 'u' format to use as the start of the SAS token." } }, "duration" : { "type": "string", "defaultValue": "P1Y", "metadata": { "description": "The duration of the SAS token. P1Y is maximum, ISO 8601 format is expected." } }, "maxRatePerSecond": { "type": "int", "defaultValue": 500, "minValue": 1, "maxValue": 500, "metadata": { "description": "The approximate maximum rate per second the SAS token can be used." } }, "signingKey": { "type": "string", "defaultValue": "primaryKey", "allowedValues": [ "primaryKey", "seconaryKey" ], "metadata": { "description": "The specified signing key which will be used to create the SAS token." } }, "allowedOrigins": { "type": "array", "defaultValue": [], "maxLength": 10, "metadata": { "description": "The specified application's web host header origins (example: https://www.azure.com) which the Azure Maps account allows for CORS." } }, "allowedRegions": { "type": "array", "defaultValue": [], "metadata": { "description": "The specified SAS token allowed locations where the token may be used." } } }, "variables": { "accountId": "[resourceId('Microsoft.Maps/accounts', parameters('accountName'))]", "Azure Maps Data Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '423170ca-a8f6-4b0f-8487-9e4eb8f49bfa')]", "sasParameters": { "signingKey": "[parameters('signingKey')]", "principalId": "[parameters('userAssignedIdentityPrincipalId')]", "maxRatePerSecond": "[parameters('maxRatePerSecond')]", "start": "[parameters('startDateTime')]", "expiry": "[dateTimeAdd(parameters('startDateTime'), parameters('duration'))]", "regions": "[parameters('allowedRegions')]" } }, "resources": [ { "name": "[parameters('accountName')]", "type": "Microsoft.Maps/accounts", "apiVersion": "2023-06-01", "location": "[parameters('location')]", "sku": { "name": "[parameters('pricingTier')]" }, "kind": "[parameters('kind')]", "properties": { "cors": { "corsRules": [ { "allowedOrigins": "[parameters('allowedOrigins')]" } ] } }, "identity": { "type": "UserAssigned", "userAssignedIdentities": { "[parameters('userAssignedIdentityResourceId')]": {} } } }, { "apiVersion": "2020-04-01-preview", "name": "[concat(parameters('accountName'), '/Microsoft.Authorization/', parameters('guid'))]", "type": "Microsoft.Maps/accounts/providers/roleAssignments", "dependsOn": [ "[parameters('accountName')]" ], "properties": { "roleDefinitionId": "[variables('Azure Maps Data Reader')]", "principalId": "[parameters('userAssignedIdentityPrincipalId')]", "principalType": "ServicePrincipal" } }, { "apiVersion": "2021-04-01-preview", "type": "Microsoft.KeyVault/vaults/secrets", "name": "[concat(parameters('keyVaultName'), '/', parameters('accountName'))]", "dependsOn": [ "[variables('accountId')]" ], "tags": { "signingKey": "[variables('sasParameters').signingKey]", "start" : "[variables('sasParameters').start]", "expiry" : "[variables('sasParameters').expiry]" }, "properties": { "value": "[listSas(variables('accountId'), '2023-06-01', variables('sasParameters')).accountSasToken]" } } ] }
Implemente la plantilla con los parámetros de id. de los recursos de Azure Key Vault y de identidad administrada creados en el paso anterior. Proporcione su propio valor para
<group-name>
. Al crear el token de SAS, se establece el parámetroallowedRegions
eneastus
,westus2
ywestcentralus
. Puede usar estas ubicaciones para realizar solicitudes HTTP al punto de conexiónus.atlas.microsoft.com
.Importante
Guarde el token de SAS en el almacén de claves para evitar que sus credenciales aparezcan en los registros de implementación de Azure. El elemento
tags
del secreto del token de SAS también contiene el inicio, el vencimiento y el nombre de la clave de firma para mostrar cuándo expirará el token de SAS.az deployment group create --name ExampleDeployment --resource-group <group-name> --template-file "./azuredeploy.json" --parameters keyVaultName="$($outputs[0])" userAssignedIdentityPrincipalId="$($outputs[1])" userAssignedIdentityResourceId="$($outputs[2])" allowedOrigins="['http://localhost']" allowedRegions="['eastus', 'westus2', 'westcentralus']" maxRatePerSecond="10"
Busque y guarde una copia del secreto del token de SAS único de Azure Key Vault.
$secretId = $(az keyvault secret list --vault-name $outputs[0] --query "[? contains(name,'map')].id" --output tsv) $sasToken = $(az keyvault secret show --id "$secretId" --query "value" --output tsv)
Pruebe el token de SAS enviando una solicitud a un punto de conexión de Azure Maps. En este ejemplo se especifica
us.atlas.microsoft.com
para asegurarse de que la solicitud se enruta a la geografía de EE. UU. El token de SAS permite regiones dentro de la geografía de EE. UU.az rest --method GET --url 'https://us.atlas.microsoft.com/search/address/json?api-version=1.0&query=1 Microsoft Way, Redmond, WA 98052' --headers "Authorization=jwt-sas $($sasToken)" --query "results[].address"
Ejemplo de script completo
Para ejecutar el ejemplo completo, los siguientes archivos de plantilla tienen que estar en el mismo directorio que la sesión actual de PowerShell:
- prereq.azuredeploy.json para crear el almacén de claves y la identidad administrada.
- azuredeploy.json para crear la cuenta de Azure Maps, configurar la asignación de roles e identidad administrada y almacenar el token de SAS en el almacén de claves.
az login
az provider register --namespace Microsoft.KeyVault
az provider register --namespace Microsoft.ManagedIdentity
az provider register --namespace Microsoft.Maps
$id = $(az rest --method GET --url 'https://graph.microsoft.com/v1.0/me?$select=id' --headers 'Content-Type=application/json' --query "id")
az group create --name <group-name> --location "East US"
$outputs = $(az deployment group create --name ExampleDeployment --resource-group <group-name> --template-file "./prereq.azuredeploy.json" --parameters objectId=$id --query "[properties.outputs.keyVaultName.value, properties.outputs.userAssignedIdentityPrincipalId.value, properties.outputs.userIdentityResourceId.value]" --output tsv)
az deployment group create --name ExampleDeployment --resource-group <group-name> --template-file "./azuredeploy.json" --parameters keyVaultName="$($outputs[0])" userAssignedIdentityPrincipalId="$($outputs[1])" userAssignedIdentityResourceId="$($outputs[2])" allowedOrigins="['http://localhost']" allowedRegions="['eastus', 'westus2', 'westcentralus']" maxRatePerSecond="10"
$secretId = $(az keyvault secret list --vault-name $outputs[0] --query "[? contains(name,'map')].id" --output tsv)
$sasToken = $(az keyvault secret show --id "$secretId" --query "value" --output tsv)
az rest --method GET --url 'https://us.atlas.microsoft.com/search/address/json?api-version=1.0&query=1 Microsoft Way, Redmond, WA 98052' --headers "Authorization=jwt-sas $($sasToken)" --query "results[].address"
Ejemplo real
Puede enviar solicitudes a las API de Azure Maps desde la mayoría de los clientes, como C#, Java o JavaScript. Las plataformas de desarrollo de API, como bruno o Postman pueden convertir una solicitud de API en un fragmento de código de cliente básico en casi cualquier lenguaje de programación o marco que elija. Puede usar el fragmento de código generado en las aplicaciones front-end.
En el siguiente pequeño ejemplo de código de JavaScript se muestra cómo puede usar el token de SAS con la API Fetch de JavaScript para obtener y devolver información de Azure Maps. En el ejemplo se usa la versión 1.0 de la API Obtener dirección de búsqueda. Proporcione su propio valor para <your SAS token>
.
Para que este ejemplo funcione, asegúrese de ejecutarlo desde el mismo origen que allowedOrigins
para la llamada a la API. Por ejemplo, si proporciona https://contoso.com
como allowedOrigins
en la llamada a la API, la página HTML que hospeda el script de JavaScript tiene que ser https://contoso.com
.
async function getData(url = 'https://us.atlas.microsoft.com/search/address/json?api-version=1.0&query=1 Microsoft Way, Redmond, WA 98052') {
const response = await fetch(url, {
method: 'GET',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
'Authorization': 'jwt-sas <your SAS token>',
}
});
return response.json(); // parses JSON response into native JavaScript objects
}
postData('https://us.atlas.microsoft.com/search/address/json?api-version=1.0&query=1 Microsoft Way, Redmond, WA 98052')
.then(data => {
console.log(data); // JSON data parsed by `data.json()` call
});
Limpieza de recursos
Cuando ya no necesite los recursos de Azure, puede eliminarlos:
az group delete --name {group-name}
Pasos siguientes
Implemente una plantilla de ARM de inicio rápido para crear una cuenta de Azure Maps que use un token de SAS:
Para obtener ejemplos detallados, consulte:
Descubra las métricas de uso de API de la cuenta de Azure Maps:
Explore ejemplos que muestran cómo integrar Microsoft Entra ID con Azure Maps: