Usare Azure Key Vault per passare il valore di un parametro sicuro durante la distribuzione

Anziché inserire un valore sicuro (ad esempio una password) direttamente nel modello o nel file di parametri, è possibile recuperare il valore da un insieme di credenziali delle chiavi di Azure durante una distribuzione. Il valore viene recuperato facendo riferimento all'insieme di credenziali delle chiavi e alla chiave privata nel file dei parametri. Il valore non viene mai esposto, in quanto si fa riferimento solo all'ID dell'insieme di credenziali chiave.

Importante

Questo articolo è incentrato su come passare un valore sensibile come parametro di modello. Quando il segreto viene passato come parametro, l'insieme di credenziali delle chiavi può esistere in una sottoscrizione diversa rispetto al gruppo di risorse in cui si esegue la distribuzione.

Questo articolo non tratta l’argomento su come impostare una proprietà della macchina virtuale su un URL di un certificato in un insieme di credenziali delle chiavi. Per un modello di avvio rapido di questo scenario, vedere Installare un certificato da Azure Key Vault in una macchina virtuale.

Distribuire insiemi di credenziali delle chiavi e segreti

Per accedere a un insieme di credenziali delle chiavi durante la distribuzione del modello, impostare nell'insieme di credenziali delle chiavi su enabledForTemplateDeployment true.

Se si dispone già di un insieme di credenziali delle chiavi, assicurarsi che consenta le distribuzioni di modelli.

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

Per creare un nuovo insieme di credenziali delle chiavi e aggiungere un segreto, usare:

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"

Come proprietario dell'insieme di credenziali delle chiavi, si ha automaticamente accesso alla creazione di segreti. Se è necessario consentire a un altro utente di creare segreti, usare:

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

I criteri di accesso non sono necessari se l'utente distribuisce un modello che recupera un segreto. Aggiungere un utente ai criteri di accesso solo se l'utente deve lavorare direttamente con i segreti. Le autorizzazioni di distribuzione sono definite nella sezione successiva.

Per altre informazioni sulla creazione di insiemi di credenziali delle chiavi e sull'aggiunta di segreti, vedere:

Concedere l'accesso alla distribuzione ai segreti

L'utente che distribuisce il modello deve disporre dell'autorizzazione Microsoft.KeyVault/vaults/deploy/action per l'ambito del gruppo di risorse e dell'insieme di credenziali delle chiavi. Controllando questo accesso, Azure Resource Manager impedisce a un utente non approvato di accedere al segreto passando l'ID risorsa per l'insieme di credenziali delle chiavi. È possibile concedere l'accesso alla distribuzione agli utenti senza concedere l'accesso in scrittura ai segreti.

Entrambi i ruoli Proprietario e Collaboratore possono concedere l'accesso. L’utente che ha creato l'insieme di credenziali delle chiavi è il proprietario e ha l'autorizzazione.

Per altri utenti, concedere l'autorizzazione Microsoft.KeyVault/vaults/deploy/action . La procedura seguente illustra come creare un ruolo con l'autorizzazione minima e assegnarla a un utente.

  1. Creare un file JSON di definizione del ruolo personalizzato:

    {
      "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/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e"
      ]
    }
    

    Sostituire "00000000-0000-0000-0000-000000000000" con l’ID sottoscrizione.

  2. Creare il nuovo ruolo usando il file 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
    

    I campioni assegnano il ruolo personalizzato all'utente a livello di gruppo di risorse.

Quando si usa un insieme di credenziali delle chiavi con il modello per un'applicazione gestita, è necessario concedere l'accesso all'entità servizio del provider di risorse dell'appliance. Per altre informazioni, vedere Segreto di accesso di Key Vault quando si distribuiscono Applicazioni gestite di Azure.

Fare riferimento a segreti con un ID statico

Con questo approccio, si fa riferimento all'insieme di credenziali delle chiavi nel file dei parametri, non nel modello. L'immagine seguente mostra come il file dei parametri fa riferimento al segreto e passa tale valore al modello.

Diagramma che mostra l'integrazione dell'insieme di credenziali delle chiavi di Resource Manager con l'ID statico.

Esercitazione: Integrare Azure Key Vault nella distribuzione di modelli di Resource Manager usa questo metodo.

Il modello seguente distribuisce un server SQL che include una password di amministratore. Il parametro della password è impostato su una stringa sicura, Ma il modello non specifica da dove proviene tale valore.

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

Creare ora un file dei parametri per il modello precedente. Nel file dei parametri specificare un parametro corrispondente al nome del parametro nel modello. Per il valore del parametro, fare riferimento al segreto dall'insieme di credenziali delle chiavi. Si fa riferimento al segreto passando l'identificatore della risorsa dell'insieme di credenziali delle chiavi e il nome del segreto:

Nel file dei parametri seguente il segreto dell'insieme di credenziali delle chiavi deve esistere già e si deve fornire un valore statico per il relativo ID risorsa.

{
  "$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 è necessario usare una versione del segreto diversa dalla versione corrente, usare la proprietà secretVersion.

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

Distribuire il modello e passare il file dei parametri:

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

Fare riferimento a segreti con un ID dinamico

La sezione precedente ha illustrato come passare un ID risorsa statico per il segreto dell'insieme di credenziali delle chiavi dal parametro. In alcuni scenari è necessario fare riferimento a un segreto dell'insieme di credenziali delle chiavi che varia in base alla distribuzione corrente. In alternativa, è possibile passare i valori dei parametri al modello anziché creare un parametro di riferimento nel file di parametri. La soluzione consiste nel generare dinamicamente l'ID risorsa per un segreto dell'insieme di credenziali delle chiavi usando un modello collegato.

Non è possibile generare in modo dinamico l'ID risorsa nel file dei parametri, perché le espressioni del modello non sono consentite nel file dei parametri.

Nel modello padre aggiungere il modello annidato e passare un parametro contenente l'ID risorsa generato dinamicamente. La figura seguente mostra come un parametro nel modello collegato fa riferimento al segreto.

Diagramma che illustra la generazione dinamica di ID per il segreto dell'insieme di credenziali delle chiavi.

Il modello seguente crea l'ID dell'insieme di credenziali delle chiavi in modo dinamico e lo passa come parametro.

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

Passaggi successivi