Uso de Azure Key Vault para pasar el valor de parámetro seguro durante la implementación

En lugar de pasar un valor seguro (como una contraseña) directamente en la plantilla o el archivo de parámetro, puede recuperar el valor de Azure Key Vault durante una implementación. El valor se recupera haciendo referencia a Key Vault y al secreto del archivo de parámetros. El valor nunca se expone debido a que solo hace referencia a su identificador de almacén de claves.

Importante

Este artículo se centra en cómo se pasa un valor confidencial como parámetro de plantilla. Cuando el secreto se pasa como parámetro, el almacén de claves puede existir en una suscripción diferente a la del grupo de recursos en el que se realiza la implementación.

En este artículo no se explica cómo establecer una propiedad de máquina virtual en la dirección URL de un certificado en un almacén de claves. Para obtener una plantilla de inicio rápido de este escenario, consulte Instalar un certificado de Azure Key Vault en una máquina virtual.

Implementación de almacenes de claves y secretos

Para acceder a un almacén de claves durante la implementación de plantilla, establezca enabledForTemplateDeployment en el almacén de claves en true.

Si ya tiene un almacén de claves, asegúrese de que permite implementaciones de plantilla.

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

Para crear un nuevo almacén de claves y agregar un secreto, use:

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"

Como propietario del almacén de claves, tiene acceso de forma automática a la creación de secretos. Si necesita permitir que otro usuario cree secretos, use:

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

Las directivas de acceso no son necesarias si el usuario está implementando una plantilla que recupera un secreto. Agregue un usuario a las directivas de acceso solo si el usuario necesita trabajar directamente con los secretos. Los permisos de implementación se definen en la sección siguiente.

Para más información sobre cómo crear almacenes de claves y agregar secretos, vea:

Concesión de acceso de implementación a los secretos

El usuario que implementa la plantilla debe tener el permiso Microsoft.KeyVault/vaults/deploy/action en el ámbito del grupo de recursos y el almacén de claves. Al comprobar este acceso, Azure Resource Manager evita que un usuario no aprobado acceda al secreto pasando el identificador de recurso para el almacén de claves. Puede conceder acceso de implementación a los usuarios sin conceder acceso de escritura a los secretos.

Los roles Propietario y Colaborador conceden este acceso. Si creó el almacén de claves, es el propietario y tiene el permiso.

Para otros usuarios, conceda el permiso Microsoft.KeyVault/vaults/deploy/action. El siguiente procedimiento muestra cómo crear un rol con los permisos mínimos y cómo asignarlo a un usuario.

  1. Creación de un archivo JSON de definición de rol personalizado

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

    Reemplace "00000000-0000-0000-0000-000000000000" por el identificador de la suscripción.

  2. Cree el nuevo rol con el archivo 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
    

    En los ejemplos se asigna el rol personalizado al usuario en el nivel de grupo de recursos.

Si usa un almacén de claves con la plantilla para una aplicación administrada, debe conceder acceso a la entidad de servicio del proveedor de recursos de dispositivo. Para más información, consulte Acceso al secreto de Key Vault al implementar Azure Managed Applications.

Referencia a secretos con identificador estático

Con este enfoque, se hace referencia al almacén de claves del archivo de parámetros, no de la plantilla. La siguiente imagen muestra que el archivo de parámetros hace referencia al secreto y pasa dicho valor a la plantilla.

Diagrama que muestra una integración de almacén de claves de Resource Manager con un id. estático.

Tutorial: Integración de Azure Key Vault en Template Deployment de Resource Manager usa este método.

En la plantilla siguiente se implementa un servidor SQL que incluye una contraseña de administrador. El parámetro de contraseña se establece en una cadena segura. No obstante, en la plantilla no se especifica de dónde procede ese 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"
      }
    }
  ]
}

Ahora, cree un archivo de parámetros para la plantilla anterior. En el archivo de parámetros, especifique un parámetro que coincida con el nombre del parámetro de la plantilla. Para el valor del parámetro, haga referencia al secreto del almacén de claves. Se hace referencia al secreto pasando el identificador de recurso de almacén de claves y el nombre del secreto:

En el siguiente archivo de parámetros, debe existir el secreto del almacén de claves y tendrá que proporcionar un valor estático para su identificador 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>"
    }
  }
}

Si necesita utilizar una versión del secreto distinta de la actual, incluya la propiedad secretVersion.

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

Implemente la plantilla y pase el archivo 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>

Referencia a secretos con identificador dinámico

En la sección anterior se mostró cómo pasar un identificador de recurso estático para el secreto del almacén de claves con el parámetro. En algunos escenarios, debe hacer referencia a un secreto del almacén de claves, que varía en función de la implementación actual. O bien, puede pasar valores de parámetros a la plantilla en lugar de crear un parámetro de referencia en el archivo de parámetros. La solución es generar de forma dinámica el identificador de recurso de un secreto del almacén de claves mediante una plantilla vinculada.

El identificador del recurso no se puede generar dinámicamente en el archivo de parámetros, ya que no se permiten expresiones de plantilla en este tipo de archivos.

En la plantilla principal, agregue la plantilla anidada y pase un parámetro que contenga el identificador de recurso generado dinámicamente. La siguiente imagen muestra la forma en que un parámetro en la plantilla vinculada hace referencia el secreto.

Diagrama que ilustra la generación dinámica de id. para el secreto del almacén de claves.

La siguiente plantilla crea dinámicamente el identificador de almacén de claves y lo pasa como un 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')]"
            }
          }
        }
      }
    }
  ]
}

Pasos siguientes