Compartilhar via


Proteger uma conta do Azure Mapas com um token SAS

Este artigo descreve como criar uma conta do Azure Mapas com um token SAS armazenado de forma segura que você pode usar para chamar a API REST do Azure Mapas.

Pré-requisitos

  • Uma assinatura do Azure. Caso ainda não tenha uma conta do Azure, inscreva-se para obter uma conta gratuita.

  • Permissão de função Proprietário na assinatura do Azure. Você precisa das permissões de Proprietário para:

    • Criar um cofre de chaves no Azure Key Vault.
    • Crie uma identidade gerenciada atribuída pelo usuário.
    • Atribuir a identidade gerenciada a uma função.
    • Criar uma conta do Azure Mapas.
  • A CLI do Azure instalada para implantar os recursos.

Cenário de exemplo: armazenamento seguro de token SAS

Uma credencial de token SAS concede o nível de acesso especificado por ele a todos que o possuam até expirar ou seu acesso ser revogado. Os aplicativos que usam a autenticação de token SAS devem armazenar as chaves de forma segura.

Esse cenário armazena um token SAS de forma segura como segredo no Key Vault e distribui o token em um cliente público. Eventos de ciclo de vida do aplicativo podem gerar novos tokens SAS sem interromper conexões ativas que usam tokens existentes.

Para obter mais informações sobre como configurar o Key Vault, confira o guia do desenvolvedor do Azure Key Vault.

O cenário de exemplo a seguir usa duas implantações de modelo do ARM (Azure Resource Manager) para executar as seguintes etapas:

  1. Crie um cofre da chave.
  2. Crie uma identidade gerenciada atribuída pelo usuário.
  3. Atribuir a função RBAC (controle de acesso baseado em função) do Azure Mapas à identidade gerenciada atribuída pelo usuário.
  4. Criar uma conta do Azure Mapas com uma configuração CORS (compartilhamento de recursos entre origens) e anexar a identidade gerenciada atribuída pelo usuário.
  5. Criar e salvar um token SAS no Azure Key Vault.
  6. Recuperar o segredo do token SAS do Azure Key Vault.
  7. Criar uma solicitação da API REST do Azure Mapas que usa o token SAS.

Ao terminar, você deverá ver os resultados da API REST Search Address (Non-Batch) do Azure Mapas no PowerShell com a CLI do Azure. Os recursos do Azure são implantados com permissões para se conectar à conta do Azure Mapas. Há controles de limite máximo de taxa, regiões permitidas, política de CORS configurada para localhost e RBAC do Azure.

Implantação de recursos do Azure com CLI do Azure

As etapas a seguir descrevem como criar e configurar uma conta do Azure Mapas com autenticação de token SAS. Neste exemplo, a CLI do Azure é executada em uma instância do PowerShell.

  1. Entrar na sua assinatura do Azure com az login.

  2. Registre o Key Vault, as Identidades Gerenciadas e o Azure Mapas para sua assinatura.

    az provider register --namespace Microsoft.KeyVault
    az provider register --namespace Microsoft.ManagedIdentity
    az provider register --namespace Microsoft.Maps
    
  3. Recupere sua ID de objeto do 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. Crie um arquivo de modelo chamado prereq.azuredeploy.json com o seguinte conteúdo:

    {
        "$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. Implante os recursos de pré-requisito que você criou na etapa anterior. Forneça seu próprio valor para <group-name>. Use o mesmo location da conta do Azure Mapas.

    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. Crie um arquivo de modelo azuredeploy.json para provisionar a conta do Azure Mapas, a atribuição de função e o token SAS.

    Observação

    Desativação do tipo de preço Gen1 do Azure Mapas

    O tipo de preço Gen1 foi preterido e será desativado em 15/09/26. O tipo de preço Gen2 substitui o Gen1 (S0 e S1). Se em sua conta do Azure Mapas estiver selecionado o tipo de preço Gen1, você poderá alternar para o Gen2 antes da desativação, caso contrário, ele será atualizado automaticamente. Para obter mais informações, consulte Gerenciar o tipo de preço de sua conta Azure Mapas.

    {
        "$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. Implante o modelo com os parâmetros de ID do Key Vault e os recursos de identidade gerenciada que você criou na etapa anterior. Forneça seu próprio valor para <group-name>. Ao criar o token SAS, você definirá o parâmetro allowedRegions como eastus, westus2 e westcentralus. Em seguida, você pode usar esses locais para fazer solicitações HTTP ao ponto de extremidade us.atlas.microsoft.com.

    Importante

    Você salva o token SAS no cofre de chaves para impedir que as credenciais dele apareçam nos logs de implantação do Azure. O tags do segredo do token SAS também contém o início, o fim e o nome da chave de entrada para mostrar quando o token SAS expirará.

     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. Localize e salve uma cópia do segredo do token SAS único do 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. Teste o token SAS fazendo uma solicitação para um ponto de extremidade do Azure Mapas. Este exemplo especifica us.atlas.microsoft.com para garantir suas rotas de solicitação na área geográfica dos EUA. Seu token SAS permite regiões dentro da área geográfica dos EUA.

    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"
    

Exemplo de script completo

Para executar o exemplo completo, os seguintes arquivos de modelo precisarão estar no mesmo diretório da sessão atual do PowerShell:

  • prereq.azuredeploy.json para criar o cofre de chaves e a identidade gerenciada.
  • azuredeploy.json para criar a conta do Azure Mapas, configurar a atribuição de função e a identidade gerenciada e armazenar o token SAS no cofre de chaves.
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"

Exemplo do mundo real

Você pode executar solicitações para APIs do Azure Mapas da maioria dos clientes, como C#, Java ou JavaScript. As plataformas de desenvolvimento de APIs como bruno ou Postman podem converter uma solicitação de API em um snippet de código de cliente básico em quase qualquer linguagem de programação ou estrutura que você escolher. Você pode usar os snippets de código gerados nos seus aplicativos de front-end.

O pequeno exemplo de código JavaScript a seguir mostra como você pode usar seu token SAS com a API de Busca do JavaScript para obter e retornar informações do Azure Mapas. O exemplo usa a API Obter Endereço de Pesquisa , versão 1.0. Forneça seu próprio valor para <your SAS token>.

Para que este exemplo funcione, execute-o de dentro da mesma origem de allowedOrigins para a chamada à API. Por exemplo, se você fornecer https://contoso.com como allowedOrigins na chamada à API, a página HTML que hospeda o script JavaScript deverá 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
  });

Limpar os recursos

Quando você não precisar mais dos recursos do Azure, poderá excluí-los:

az group delete --name {group-name}

Próximas etapas

Implante um modelo do ARM de início rápido para criar uma conta do Azure Mapas que usa um token SAS:

Para obter exemplos mais detalhados, consulte:

Localize as métricas de uso da API para sua conta do Azure Mapas:

Explore amostras que mostram como integrar o Microsoft Entra ID ao Azure Mapas: