Condividi tramite


Proteggere un account Mappe di Azure con un token SAS

Questo articolo descrive come creare un account Mappe di Azure con un token SAS archiviato in modo sicuro che è possibile usare per chiamare l'API REST Mappe di Azure.

Prerequisiti

Scenario di esempio: Archiviazione sicura del token SAS

Una credenziale di token SAS concede il livello di accesso che viene specificato a chiunque lo abbia, fino alla scadenza del token SAS o alla revoca di accesso. Le applicazioni che usano l'autenticazione con token SAS devono archiviare le chiavi in modo sicuro.

Questo scenario archivia in modo sicuro un token SAS in un Key Vault e distribuisce il token in un client pubblico. Gli eventi del ciclo di vita dell'applicazione possono generare nuovi token SAS senza interrompere connessioni attive che usano i token esistenti.

Per altre informazioni sulla configurazione di Key Vault, vedere la guida per gli sviluppatori di Azure Key Vault.

Lo scenario di esempio seguente usa due distribuzioni di modelli di Azure Resource Manager (ARM) per eseguire i seguenti passi:

  1. Creare un insieme di credenziali delle chiavi.
  2. Creare un'identità gestita assegnata dall'utente.
  3. Assegnare il ruolo controllo degli accessi in base al ruolo di Azure (RBAC) Lettore dati di Mappe di Azure all'identità gestita assegnata dall'utente.
  4. Creare un account Mappe di Azure con una configurazione CORS (Condivisione di risorse origine Cross) e collegare l'identità gestita assegnata dall'utente.
  5. Creare e salvare un token SAS in Azure Key Vault.
  6. Recuperare il segreto del token SAS dall'insieme di credenziali delle chiavi.
  7. Creare una richiesta API REST di Mappe di Azure che usa il token SAS.

Al termine, verranno visualizzati Mappe di Azure Search Address (single request) risultati dell'API REST in PowerShell con l'interfaccia della riga di comando di Azure. Le risorse di Azure sono implementate con le autorizzazioni per connettersi all'account Mappe di Azure. Sono disponibili controlli per il limite massimo di velocità, le aree consentite, i criteri CORS configurati localhost e il controllo degli accessi in base al ruolo di Azure.

Distribuzione delle risorse di Azure con l'interfaccia della riga di comando di Azure

I passi seguenti descrivono come creare e configurare un account Mappe di Azure con autenticazione con token SAS. In questo esempio l'interfaccia della riga di comando di Azure viene eseguita in un'istanza di PowerShell.

  1. Accedere alla sottoscrizione di Azure con az login.

  2. Registrare Key Vault, le identità gestite e Mappe di Azure per la sottoscrizione.

    az provider register --namespace Microsoft.KeyVault
    az provider register --namespace Microsoft.ManagedIdentity
    az provider register --namespace Microsoft.Maps
    
  3. Recuperare l'ID oggetto Microsoft Entra.

    $id = $(az rest --method GET --url 'https://graph.microsoft.com/v1.0/me?$select=id' --headers 'Content-Type=application/json' --query "id")
    
  4. Creare un file modello denominato prereq.azuredeploy.json con il contenuto seguente:

    {
        "$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')]"
            }
        }
    }
    
    
  5. Implementare le risorse dei prerequisiti create nel passaggio precedente. Specificare il proprio valore per <group-name>. Assicurarsi di usare lo stesso ___location dell'account Mappe di Azure.

    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)
    
  6. Creare un file modello azuredeploy.json per effettuare il provisioning dell'account Mappe di Azure, l'assegnazione di ruolo e il token SAS.

    Note

    Ritiro del piano tariffario Gen1 di Mappe di Azure

    Il piano tariffario Gen1 è ora deprecato e verrà ritirato il 15/9/26. Il piano tariffario Gen2 sostituisce il piano tariffario Gen1 (S0 e S1). Se per l'account Mappe di Azure è selezionato il piano tariffario Gen1, è possibile passare al piano tariffario Gen2 prima che venga ritirato. In caso contrario, l'aggiornamento verrà eseguito automaticamente. Per altre informazioni, vedere Gestire il piano tariffario dell'account mappe di Azure.

    {
        "$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",
                    "secondaryKey"
                ],
                "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]"
                }
            }
        ]
    }
    
  7. Implementare il modello con i parametri ID dall'insieme di Key Vault e le risorse di identità gestite create nel passaggio precedente. Specificare il proprio valore per <group-name>. Quando si crea il token di firma SAS, si imposta il parametro allowedRegions su eastus, westus2 e westcentralus. È quindi possibile usare questi percorsi per effettuare richieste HTTP all'endpoint us.atlas.microsoft.com.

    Importante

    Salvare il token SAS nell'insieme di credenziali delle chiavi per impedire la visualizzazione delle credenziali nei log di distribuzione di Azure. Il segreto nel token SAS tags contiene anche il nome di inizio, scadenza e il nome della chiave di firma, da visualizzare alla scadenza del token 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"
    
  8. Individuare e salvare una copia del singolo segreto nel token SAS da 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)
    
  9. Testare il token SAS effettuando una richiesta a un endpoint Mappe di Azure. In questo esempio viene specificato us.atlas.microsoft.com per assicurarsi che le route di richiesta vengano instradate all'area geografica Stati Uniti. Il token SAS consente le aree all'interno dei dati geografici degli Stati Uniti.

    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"
    

Esempio di script completo

Per eseguire l'esempio completo, i file modello seguenti devono trovarsi nella stessa directory della sessione di PowerShell corrente:

  • prereq.azuredeploy.json per creare l'insieme di credenziali delle chiavi e l'identità gestita.
  • azuredeploy.json per creare l'account Mappe di Azure, configurare l'assegnazione di ruolo e l'identità gestita, e archiviare il token SAS nell'insieme di credenziali delle chiavi.
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"

Esempio reale

È possibile eseguire richieste per le API Mappe di Azure dalla maggior parte dei client, ad esempio C#, Java o JavaScript. Le piattaforme di sviluppo di API come bruno o Postman possono convertire una richiesta API in un frammento di codice client di base, più o meno in qualsiasi linguaggio di programmazione o framework scelto. È possibile usare i frammenti di codice generato nelle applicazioni front-end.

Il piccolo esempio di codice JavaScript seguente illustra come sarebbe possibile usare il token SAS con l'API di recupero di JavaScript per ottenere e restituire informazioni delle Mappe di Azure. L'esempio usa l'API Ottieni indirizzo di ricerca versione 1.0. Specificare il proprio valore per <your SAS token>.

Per il funzionamento di questo esempio, assicurarsi di eseguirlo dall'interno della stessa origine di allowedOrigins per chiamata API. Ad esempio, se si specifica https://contoso.com come allowedOrigins nella chiamata API, la pagina HTML che ospita lo script JavaScript deve essere 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
  });

Pulire le risorse

Quando le risorse di Azure non sono più necessarie, è possibile eliminarle:

az group delete --name {group-name}

Passaggi successivi

Implementare un modello di ARM di avvio rapido per creare un account Mappe di Azure che usa un token SAS:

Per esempi più dettagliati, vedere:

Trovare le metriche di utilizzo delle API per l'account Mappe di Azure:

Esplorare gli esempi che illustrano come integrare Microsoft Entra ID con Mappe di Azure: