Sichern eines Azure Maps-Kontos mit einem SAS-Token

In diesem Artikel wird beschrieben, wie Sie ein Azure Maps-Konto mit einem sicher gespeicherten SAS-Token erstellen, das Sie zum Aufrufen der Azure Maps-REST-API verwenden können.

Voraussetzungen

  • Ein Azure-Abonnement. Falls Sie noch kein Azure-Konto haben, registrieren Sie sich für ein kostenloses.

  • Rollenberechtigung Besitzer für das Azure-Abonnement. Sie benötigen die Berechtigungen Besitzer für folgende Aufgaben:

    • Erstellen Sie einen Schlüsseltresor in Azure Key Vault.
    • Erstellen Sie eine benutzerseitig zugewiesene verwaltete Identität.
    • Weisen Sie die verwaltete Identität einer Rolle zu.
    • Erstellen Sie ein Azure Maps-Konto.
  • Installierte Azure CLI zum Bereitstellen der Ressourcen.

Beispielszenario: Sicherer SAS-Tokenspeicher

Anmeldeinformationen für ein SAS-Token gewähren die angegebene Zugriffsebene jeder Person, die sie besitzt, bis zum Ablauf des Tokens oder zum Widerruf des Zugriffs. Anwendungen, die die SAS-Tokenauthentifizierung nutzen, sollten die Schlüssel sicher speichern.

In diesem Szenario wird ein SAS-Token im Schlüsseltresor als Geheimnis sicher gespeichert und in einen öffentlichen Client verteilt. Ereignisse im Lebenszyklus einer Anwendung können neue SAS-Token generieren, ohne aktive Verbindungen zu unterbrechen, die vorhandene Token nutzen.

Weitere Informationen zum Konfigurieren von Key Vault finden Sie im Leitfaden für Azure Key Vault-Entwickler.

Im folgenden Beispielszenario werden zwei Azure Resource Manager (ARM)-Vorlagenbereitstellungen verwendet, um die folgenden Schritte auszuführen:

  1. Erstellen eines Schlüsseltresors
  2. Erstellen Sie eine benutzerseitig zugewiesene verwaltete Identität.
  3. Weisen Sie die Rolle Leseberechtigter für Azure Maps-Daten der rollenbasierten Zugriffssteuerung (Role-Based Access Control, RBAC) in Azure der benutzerseitig zugewiesenen verwalteten Identität zu.
  4. Erstellen Sie ein Azure Maps-Konto mit einer CORS-Konfiguration (Cross Origin Resource Sharing), und fügen Sie die benutzerseitig zugewiesene verwaltete Identität an.
  5. Erstellen Sie ein SAS-Token, und speichern Sie es im Azure-Schlüsseltresor.
  6. Rufen Sie das SAS-Tokengeheimnis aus dem Schlüsseltresor ab.
  7. Erstellen Sie eine Azure Maps-REST-API-Anforderung, die das SAS-Token verwendet.

Wenn Sie damit fertig sind, sollten die Ergebnisse Search Address (Non-Batch) der Azure Maps-REST-API in PowerShell mit Azure CLI angezeigt werden. Die Azure-Ressourcen werden mit Berechtigungen zum Herstellen einer Verbindung mit dem Azure Maps-Konto bereitgestellt. Es gibt Steuerelemente für maximale Ratenbegrenzung, zulässige Regionen, konfigurierte CORS-Richtlinie localhost und Azure RBAC.

Azure-Ressourcenbereitstellung mit der Azure CLI

In den folgenden Schritten wird beschrieben, wie Sie ein Azure Maps-Konto mit SAS-Tokenauthentifizierung erstellen und konfigurieren. In diesem Beispiel wird Azure CLI in einer PowerShell-Instanz ausgeführt.

  1. Melden Sie sich bei Ihrem Azure-Abonnement mit az login an.

  2. Registrieren Sie Azure Key Vault, verwaltete Identitäten und Azure Maps für Ihr Abonnement.

    az provider register --namespace Microsoft.KeyVault
    az provider register --namespace Microsoft.ManagedIdentity
    az provider register --namespace Microsoft.Maps
    
  3. Rufen Sie Ihre Azure Active Directory (Azure AD)-Objekt-ID ab.

    $id = $(az rest --method GET --url 'https://graph.microsoft.com/v1.0/me?$select=id' --headers 'Content-Type=application/json' --query "id")
    
  4. Erstellen Sie eine Vorlagendatei namens prereq.azuredeploy.json mit folgendem Inhalt:

    {
        "$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. Stellen Sie die erforderlichen Ressourcen bereit, die Sie im vorhergehenden Schritt erstellt haben. Geben Sie Ihren eigenen Wert für <group-name> an. Stellen Sie sicher, dass Sie denselben Speicherort (location) wie das Azure Maps-Konto verwenden.

    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. Erstellen Sie die Vorlagendatei azuredeploy.json zur Bereitstellung des Azure Maps-Kontos, der Rollenzuweisung und des SAS-Tokens.

    {
        "$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": "2021-12-01-preview",
                "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'), '2021-12-01-preview', variables('sasParameters')).accountSasToken]"
                }
            }
        ]
    }
    
  7. Stellen Sie die Vorlage mit den ID-Parametern aus Key Vault und den Ressourcen für verwaltete Identitäten bereit, die Sie im vorhergehenden Schritt erstellt haben. Geben Sie Ihren eigenen Wert für <group-name> an. Beim Erstellen des SAS-Tokens legen Sie den Parameter allowedRegions auf eastus, westus2 und westcentralus fest. Sie können diese Standorte nutzen, um HTTP-Anforderungen an den Endpunkt us.atlas.microsoft.com zu senden.

    Wichtig

    Sie speichern das SAS-Token im Schlüsseltresor, um zu verhindern, dass seine Anmeldeinformationen in den Azure-Bereitstellungsprotokollen angezeigt werden. Die Tags (tags) des SAS-Tokengeheimnisses enthalten außerdem den Beginn, den Ablauf und den Namen des Signaturschlüssels, um zu zeigen, wann das SAS-Token abläuft.

     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. Suchen Sie das einzelne SAS-Tokengeheimnis aus Azure Key Vault, und speichern Sie eine Kopie davon.

    $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. Testen Sie das SAS-Token, indem Sie eine Anforderung an einen Azure Maps-Endpunkt senden. In diesem Beispiel wird der Wert us.atlas.microsoft.com angegeben, um sicherzustellen, dass Ihre Anforderung an die US-Geografie weitergeleitet wird. Ihr SAS-Token lässt Regionen innerhalb der US-Geografie zu.

    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"
    

Vollständiges Beispiel für ein Skript

Zur Ausführung des vollständigen Beispiels müssen sich die folgenden Vorlagendateien in demselben Verzeichnis wie die aktuelle PowerShell-Sitzung befinden:

  • prereq.azuredeploy.json zum Erstellen des Schlüsseltresors und der verwalteten Identität.
  • azuredeploy.json zum Erstellen des Azure Maps-Kontos, Konfigurieren der Rollenzuweisung und verwalteten Identität sowie zum Speichern des SAS-Tokens im Schlüsseltresor.
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"

Beispiel aus der realen Welt

Sie können Anforderungen an Azure Maps-APIs über die meisten Clients ausführen, z. B. C#, Java oder JavaScript. Postman konvertiert eine API-Anforderung in einen einfachen Clientcodeausschnitt in fast jeder Programmiersprache oder jedem Framework, die bzw. das Sie auswählen. Sie können diesen generierten Codeausschnitt in Ihren Front-End-Anwendungen verwenden.

Das folgende kleine JavaScript-Codebeispiel zeigt, wie Sie Ihr SAS-Token bei der Fetch-API von JavaScript verwenden können, um Azure Maps-Informationen abzurufen und zurückzugeben. Im Beispiel wird die Azure Maps-API Get Search Address (Suchadresse abrufen), Version 1.0, verwendet. Geben Sie Ihren eigenen Wert für <your SAS token> an.

Damit dieses Beispiel funktioniert, müssen Sie es aus demselben Ursprung wie die allowedOrigins für den API-Aufruf ausführen. Wenn Sie beispielsweise https://contoso.com im API-Aufruf als allowedOrigins angeben, sollte https://contoso.com die HTML-Seite zum Hosten des JavaScripts sein.

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
  });

Bereinigen von Ressourcen

Wenn Sie die Azure-Ressourcen nicht mehr benötigen, können Sie sie löschen:

az group delete --name {group-name}

Nächste Schritte

Stellen Sie eine ARM-Schnellstartvorlage zum Erstellen eines Azure Maps-Kontos bereit, das ein SAS-Token verwendet:

Ausführlichere Beispiele finden Sie unter:

Suchen der API-Nutzungsmetriken für Ihr Azure Maps-Konto:

Beispiele für die Integration von Azure AD in Azure Maps: