Utilizar o Azure Key Vault para passar um valor de parâmetro seguro durante a implementação

Em vez de colocar um valor seguro (como uma palavra-passe) diretamente no seu modelo ou ficheiro de parâmetro, pode obter o valor de um Key Vault do Azure durante uma implementação. Obtém o valor ao referenciar o cofre de chaves e o segredo no ficheiro de parâmetros. O valor nunca é exposto porque referencia apenas o respetivo ID do cofre de chaves.

Importante

Este artigo centra-se em como transmitir um valor confidencial como um parâmetro de modelo. Quando o segredo é transmitido como um parâmetro, o cofre de chaves pode existir numa subscrição diferente do grupo de recursos no qual está a implementar.

Este artigo não aborda como definir uma propriedade de máquina virtual para o URL de um certificado num cofre de chaves. Para obter um modelo de início rápido desse cenário, veja Instalar um certificado do Azure Key Vault numa Máquina Virtual.

Implementar cofres de chaves e segredos

Para aceder a um cofre de chaves durante a implementação do modelo, defina enabledForTemplateDeployment no cofre de chaves como true.

Se já tiver um cofre de chaves, certifique-se de que permite implementações de modelos.

az keyvault update  --name ExampleVault --enabled-for-template-deployment true

Para criar um novo cofre de chaves e adicionar um segredo, utilize:

az group create --name ExampleGroup --location centralus
az keyvault create \
  --name ExampleVault \
  --resource-group ExampleGroup \
  --location centralus \
  --enabled-for-template-deployment true
az keyvault secret set --vault-name ExampleVault --name "ExamplePassword" --value "hVFkk965BuUv"

Enquanto proprietário do cofre de chaves, tem automaticamente acesso para criar segredos. Se precisar de permitir que outro utilizador crie segredos, utilize:

az keyvault set-policy \
  --upn <user-principal-name> \
  --name ExampleVault \
  --secret-permissions set delete get list

As políticas de acesso não são necessárias se o utilizador estiver a implementar um modelo que obtém um segredo. Adicione um utilizador às políticas de acesso apenas se o utilizador precisar de trabalhar diretamente com os segredos. As permissões de implementação são definidas na secção seguinte.

Para obter mais informações sobre como criar cofres de chaves e adicionar segredos, consulte:

Conceder acesso de implementação aos segredos

O utilizador que implementa o modelo tem de ter a Microsoft.KeyVault/vaults/deploy/action permissão para o âmbito do grupo de recursos e do cofre de chaves. Ao verificar este acesso, o Azure Resource Manager impede que um utilizador não aprovado aceda ao segredo ao transmitir o ID do recurso para o cofre de chaves. Pode conceder acesso de implementação aos utilizadores sem conceder acesso de escrita aos segredos.

As funções Proprietário e Contribuidor concedem este acesso. Se criou o cofre de chaves, é o proprietário e tem a permissão.

Para outros utilizadores, conceda a Microsoft.KeyVault/vaults/deploy/action permissão. O procedimento seguinte mostra como criar uma função com a permissão mínima e atribuí-la a um utilizador.

  1. Crie um ficheiro JSON de definição de função personalizada:

    {
      "Name": "Key Vault resource manager template deployment operator",
      "IsCustom": true,
      "Description": "Lets you deploy a resource manager template with the access to the secrets in the Key Vault.",
      "Actions": [
        "Microsoft.KeyVault/vaults/deploy/action"
      ],
      "NotActions": [],
      "DataActions": [],
      "NotDataActions": [],
      "AssignableScopes": [
        "/subscriptions/00000000-0000-0000-0000-000000000000"
      ]
    }
    

    Substitua "00000000-0000-0000-0000-00000000000" pelo ID da subscrição.

  2. Crie a nova função com o ficheiro JSON:

    az role definition create --role-definition "<path-to-role-file>"
    az role assignment create \
      --role "Key Vault resource manager template deployment operator" \
      --scope /subscriptions/<Subscription-id>/resourceGroups/<resource-group-name> \
      --assignee <user-principal-name> \
      --resource-group ExampleGroup
    

    Os exemplos atribuem a função personalizada ao utilizador ao nível do grupo de recursos.

Ao utilizar um cofre de chaves com o modelo de uma Aplicação Gerida, tem de conceder acesso ao principal de serviço do Fornecedor de Recursos da Aplicação . Para obter mais informações, veja Access Key Vault secret when deploying Azure Managed Applications (Aceder Key Vault segredo ao implementar Aplicações Geridas do Azure).

Referenciar segredos com ID estático

Com esta abordagem, faz referência ao cofre de chaves no ficheiro de parâmetros e não ao modelo. A imagem seguinte mostra como o ficheiro de parâmetros referencia o segredo e transmite esse valor ao modelo.

Diagrama a mostrar Resource Manager integração do cofre de chaves com o ID Estático.

Tutorial: Integrar o Azure Key Vault na implementação de Modelos do Resource Manager utiliza este método.

O modelo seguinte implementa um servidor SQL que inclui uma palavra-passe de administrador. O parâmetro de palavra-passe está definido como uma cadeia segura. No entanto, o modelo não especifica a origem desse valor.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "sqlServerName": {
      "type": "string"
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]"
    },
    "adminLogin": {
      "type": "string"
    },
    "adminPassword": {
      "type": "securestring"
    }
  },
  "resources": [
    {
      "type": "Microsoft.Sql/servers",
      "apiVersion": "2021-11-01",
      "name": "[parameters('sqlServerName')]",
      "location": "[parameters('location')]",
      "properties": {
        "administratorLogin": "[parameters('adminLogin')]",
        "administratorLoginPassword": "[parameters('adminPassword')]",
        "version": "12.0"
      }
    }
  ]
}

Agora, crie um ficheiro de parâmetros para o modelo anterior. No ficheiro de parâmetros, especifique um parâmetro que corresponda ao nome do parâmetro no modelo. Para o valor do parâmetro, referencie o segredo do cofre de chaves. Pode referenciar o segredo ao transmitir o identificador de recurso do cofre de chaves e o nome do segredo:

No ficheiro de parâmetros seguinte, o segredo do cofre de chaves já tem de existir e o utilizador fornece um valor estático para o respetivo ID de recurso.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "adminLogin": {
      "value": "exampleadmin"
    },
    "adminPassword": {
      "reference": {
        "keyVault": {
          "id": "/subscriptions/<subscription-id>/resourceGroups/<rg-name>/providers/Microsoft.KeyVault/vaults/<vault-name>"
        },
        "secretName": "ExamplePassword"
      }
    },
    "sqlServerName": {
      "value": "<your-server-name>"
    }
  }
}

Se precisar de utilizar uma versão do segredo que não seja a versão atual, inclua a secretVersion propriedade .

"secretName": "ExamplePassword",
"secretVersion": "cd91b2b7e10e492ebb870a6ee0591b68"

Implemente o modelo e transmita o ficheiro de parâmetros:

az group create --name SqlGroup --location westus2
az deployment group create \
  --resource-group SqlGroup \
  --template-uri <template-file-URI> \
  --parameters <parameter-file>

Referenciar segredos com ID dinâmico

A secção anterior mostrou como transmitir um ID de recurso estático para o segredo do cofre de chaves a partir do parâmetro . Em alguns cenários, tem de referenciar um segredo do cofre de chaves que varia consoante a implementação atual. Em alternativa, pode querer transmitir valores de parâmetros para o modelo em vez de criar um parâmetro de referência no ficheiro de parâmetros. A solução é gerar dinamicamente o ID do recurso para um segredo do cofre de chaves com um modelo ligado.

Não pode gerar dinamicamente o ID do recurso no ficheiro de parâmetros porque as expressões de modelo não são permitidas no ficheiro de parâmetros.

No modelo principal, adiciona o modelo aninhado e transmite um parâmetro que contém o ID de recurso gerado dinamicamente. A imagem seguinte mostra como um parâmetro no modelo ligado referencia o segredo.

Diagrama a ilustrar a geração de ID dinâmico para o segredo do cofre de chaves.

O modelo seguinte cria dinamicamente o ID do cofre de chaves e transmite-o como um parâmetro.

{
  "$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": "The location where the resources will be deployed."
        }
      },
      "vaultName": {
        "type": "string",
        "metadata": {
          "description": "The name of the keyvault that contains the secret."
        }
      },
      "secretName": {
        "type": "string",
        "metadata": {
          "description": "The name of the secret."
        }
      },
      "vaultResourceGroupName": {
        "type": "string",
        "metadata": {
          "description": "The name of the resource group that contains the keyvault."
        }
      },
      "vaultSubscription": {
        "type": "string",
        "defaultValue": "[subscription().subscriptionId]",
        "metadata": {
          "description": "The name of the subscription that contains the keyvault."
        }
      }
  },
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2020-10-01",
      "name": "dynamicSecret",
      "properties": {
        "mode": "Incremental",
        "expressionEvaluationOptions": {
          "scope": "inner"
        },
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "parameters": {
            "adminLogin": {
              "type": "string"
            },
            "adminPassword": {
              "type": "securestring"
            },
            "location": {
              "type": "string"
            }
          },
          "variables": {
            "sqlServerName": "[concat('sql-', uniqueString(resourceGroup().id, 'sql'))]"
          },
          "resources": [
            {
              "type": "Microsoft.Sql/servers",
              "apiVersion": "2021-11-01",
              "name": "[variables('sqlServerName')]",
              "location": "[parameters('location')]",
              "properties": {
                "administratorLogin": "[parameters('adminLogin')]",
                "administratorLoginPassword": "[parameters('adminPassword')]"
              }
            }
          ],
          "outputs": {
            "sqlFQDN": {
              "type": "string",
              "value": "[reference(variables('sqlServerName')).fullyQualifiedDomainName]"
            }
          }
        },
        "parameters": {
          "location": {
            "value": "[parameters('location')]"
          },
          "adminLogin": {
            "value": "ghuser"
          },
          "adminPassword": {
            "reference": {
              "keyVault": {
                "id": "[resourceId(parameters('vaultSubscription'), parameters('vaultResourceGroupName'), 'Microsoft.KeyVault/vaults', parameters('vaultName'))]"
              },
              "secretName": "[parameters('secretName')]"
            }
          }
        }
      }
    }
  ]
}

Passos seguintes