Używanie usługi Azure Key Vault do przekazywania bezpiecznej wartości parametru podczas wdrażania

Zamiast umieszczać bezpieczną wartość (np. hasło) bezpośrednio w pliku szablonu lub parametrów, możesz pobrać wartość z usługi Azure Key Vault podczas wdrażania. Wartość można pobrać, odwołując się do magazynu kluczy i wpisu tajnego w pliku parametrów. Wartość nigdy nie jest uwidoczniana, ponieważ używane jest tylko odwołanie do jej identyfikatora magazynu kluczy.

Ważne

W tym artykule opisano sposób przekazywania poufnej wartości jako parametru szablonu. Gdy wpis tajny jest przekazywany jako parametr, magazyn kluczy może istnieć w innej subskrypcji niż wdrażana grupa zasobów.

W tym artykule nie opisano sposobu ustawiania właściwości maszyny wirtualnej na adres URL certyfikatu w magazynie kluczy. Aby zapoznać się z szablonem szybkiego startu tego scenariusza, zobacz Instalowanie certyfikatu z usługi Azure Key Vault na maszynie wirtualnej.

Wdrażanie magazynów kluczy i wpisów tajnych

Aby uzyskać dostęp do magazynu kluczy podczas wdrażania szablonu, ustaw dla enabledForTemplateDeployment magazynu kluczy wartość true.

Jeśli masz już magazyn kluczy, upewnij się, że zezwala na wdrożenia szablonów.

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

Aby utworzyć nowy magazyn kluczy i dodać wpis tajny, użyj:

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"

Jako właściciel magazynu kluczy masz automatycznie dostęp do tworzenia wpisów tajnych. Jeśli musisz zezwolić innemu użytkownikowi na tworzenie wpisów tajnych, użyj:

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

Zasady dostępu nie są potrzebne, jeśli użytkownik wdraża szablon, który pobiera wpis tajny. Dodaj użytkownika do zasad dostępu tylko wtedy, gdy użytkownik musi pracować bezpośrednio z wpisami tajnymi. Uprawnienia wdrożenia są definiowane w następnej sekcji.

Aby uzyskać więcej informacji na temat tworzenia magazynów kluczy i dodawania wpisów tajnych, zobacz:

Udzielanie dostępu wdrożenia do wpisów tajnych

Użytkownik wdrażający szablon musi mieć Microsoft.KeyVault/vaults/deploy/action uprawnienie do zakresu grupy zasobów i magazynu kluczy. Sprawdzając ten dostęp, usługa Azure Resource Manager uniemożliwia niezatwierdzonym użytkownikowi dostęp do wpisu tajnego, przekazując identyfikator zasobu dla magazynu kluczy. Dostęp do wdrożenia można udzielić użytkownikom bez udzielania dostępu do zapisu wpisów tajnych.

Role Właściciel i Współautor przyznają ten dostęp. Jeśli utworzono magazyn kluczy, jesteś właścicielem i masz uprawnienie.

W przypadku innych użytkowników przyznaj Microsoft.KeyVault/vaults/deploy/action uprawnienie. Poniższa procedura pokazuje, jak utworzyć rolę z minimalnym uprawnieniem i przypisać ją do użytkownika.

  1. Utwórz plik JSON definicji roli niestandardowej:

    {
      "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"
      ]
    }
    

    Zastąp wartość "00000000-0000-0000-0000-000000000000" identyfikatorem subskrypcji.

  2. Utwórz nową rolę przy użyciu pliku 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
    

    Przykłady przypisują rolę niestandardową do użytkownika na poziomie grupy zasobów.

W przypadku korzystania z magazynu kluczy z szablonem aplikacji zarządzanej należy udzielić dostępu do jednostki usługi dostawcy zasobów urządzenia. Aby uzyskać więcej informacji, zobacz Access Key Vault secret when deploying Azure Managed Applications (Uzyskiwanie dostępu do wpisu tajnego usługi Key Vault podczas wdrażania aplikacji zarządzanych platformy Azure).

Odwołania do wpisów tajnych z identyfikatorem statycznym

W przypadku tego podejścia należy odwołać się do magazynu kluczy w pliku parametrów, a nie szablonu. Na poniższej ilustracji pokazano, jak plik parametrów odwołuje się do wpisu tajnego i przekazuje wartość do szablonu.

Diagram przedstawiający integrację magazynu kluczy usługi Resource Manager z identyfikatorem statycznym.

Samouczek: integracja usługi Azure Key Vault z wdrożeniem szablonu usługi Resource Manager używa tej metody.

Poniższy szablon wdraża serwer SQL zawierający hasło administratora. Parametr hasła jest ustawiony na bezpieczny ciąg. Jednak szablon nie określa, skąd pochodzi ta wartość.

{
  "$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"
      }
    }
  ]
}

Teraz utwórz plik parametrów dla poprzedniego szablonu. W pliku parametrów określ parametr zgodny z nazwą parametru w szablonie. W przypadku wartości parametru należy odwołać się do wpisu tajnego z magazynu kluczy. Odwołujesz się do wpisu tajnego, przekazując identyfikator zasobu magazynu kluczy i nazwę wpisu tajnego:

W poniższym pliku parametrów wpis tajny magazynu kluczy musi już istnieć i należy podać wartość statyczną dla jego identyfikatora zasobu.

{
  "$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>"
    }
  }
}

Jeśli musisz użyć wersji wpisu tajnego innej niż bieżąca wersja, dołącz secretVersion właściwość .

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

Wdróż szablon i przekaż plik parametrów:

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

Odwołania do wpisów tajnych z identyfikatorem dynamicznym

W poprzedniej sekcji pokazano, jak przekazać statyczny identyfikator zasobu dla wpisu tajnego magazynu kluczy z parametru . W niektórych scenariuszach należy odwołać się do wpisu tajnego magazynu kluczy, który różni się w zależności od bieżącego wdrożenia. Możesz też przekazać wartości parametrów do szablonu, a nie utworzyć parametru referencyjnego w pliku parametrów. Rozwiązaniem jest dynamiczne generowanie identyfikatora zasobu dla wpisu tajnego magazynu kluczy przy użyciu połączonego szablonu.

Nie można dynamicznie wygenerować identyfikatora zasobu w pliku parametrów, ponieważ wyrażenia szablonu nie są dozwolone w pliku parametrów.

W szablonie nadrzędnym dodasz zagnieżdżony szablon i przekażesz parametr zawierający dynamicznie wygenerowany identyfikator zasobu. Na poniższej ilustracji pokazano, jak parametr w połączonym szablonie odwołuje się do wpisu tajnego.

Diagram ilustrujący generowanie identyfikatorów dynamicznych dla wpisu tajnego magazynu kluczy.

Poniższy szablon dynamicznie tworzy identyfikator magazynu kluczy i przekazuje go jako parametr.

{
  "$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')]"
            }
          }
        }
      }
    }
  ]
}

Następne kroki