Aprovisionar claves habilitadas para el enclave

Se aplica a: SQL Server 2019 (15.x) y versiones posteriores en Windows Azure SQL Database

En este artículo se describe cómo aprovisionar claves habilitadas para el enclave que admiten cálculos dentro de los enclaves seguros del lado servidor que se usan en Always Encrypted con enclaves seguros.

Los procesos y las instrucciones generales para administrar claves de Always Encrypted son válidos también para aprovisionar claves habilitadas para el enclave. En este artículo se tratan los detalles específicos de Always Encrypted con enclaves seguros.

Para aprovisionar una clave maestra de columna habilitada para el enclave con SQL Server Management Studio o PowerShell, asegúrese de que la nueva clave admite cálculos de enclave. Esto hará que la herramienta (SSMS o PowerShell) genere la instrucción CREATE COLUMN MASTER KEY, que establece ENCLAVE_COMPUTATIONS en los metadatos de la clave maestra de columnas en la base de datos. Para obtener más información, vea CREATE COLUMN MASTER KEY (Transact-SQL).

La herramienta también firmará digitalmente las propiedades maestras de columna con la clave maestra de columna, y almacenará la firma en los metadatos de la base de datos. La firma evita la manipulación maliciosa de la configuración ENCLAVE_COMPUTATIONS. Los controladores cliente de SQL comprueban las firmas antes de permitir el uso del enclave. Esto proporciona a los administradores de seguridad el control de qué datos de columnas pueden calcularse dentro del enclave.

Después de definir la clave maestra de columna en los metadatos, la ENCLAVE_COMPUTATIONS propiedad es inmutable y no se puede cambiar. Para habilitar los cálculos de enclave mediante una clave de cifrado de columnas que cifra una clave maestra de columna existente, gire la clave maestra de columna y reemplácela por una clave maestra de columna habilitada para el enclave. Vea Rotación de claves habilitadas para el enclave.

Nota:

Actualmente, tanto SSMS como PowerShell admiten claves maestras de columna habilitadas para el enclave almacenadas en Azure Key Vault o en el almacén de certificados de Windows. No se admiten módulos de seguridad de hardware (con CNG o CAPI).

Para crear una clave de cifrado de columna compatible con enclaves, debe asegurarse de seleccionar una clave maestra de columna compatible con enclaves para cifrar la nueva clave.

En las siguientes secciones se proporcionan más detalles sobre cómo aprovisionar claves habilitadas para el enclave por medio de SSMS y PowerShell.

Aprovisionamiento de claves habilitadas para el enclave mediante SQL Server Management Studio

En SQL Server Management Studio puede aprovisionar lo siguiente:

  • Una clave maestra de columna habilitada para el enclave, mediante el cuadro de diálogo Nueva clave maestra de columna.
  • Una clave de cifrado de columna habilitada para enclaves usando el cuadro de diálogo Nueva clave de cifrado de columna.

El Asistente de Always Encrypted también permite crear una clave maestra de columna compatible con enclaves y una clave de cifrado de columna compatible con enclaves.

Instale la versión más reciente de SQL Server Management Studio (SSMS).

Aprovisionamiento de claves maestras de columna habilitadas para el enclave con el cuadro de diálogo Nueva clave maestra de columna

Para aprovisionar una clave maestra de columna con enclave habilitado, siga los pasos de Aprovisionar claves maestras de columna con el cuadro de diálogo Nueva clave maestra de columna. Asegúrese de seleccionar Permitir cálculos de enclave. Vea la siguiente captura de pantalla:

Permitir el cómputo en enclaves

Nota:

La casilla Permitir cálculos de enclave solo aparece si se ha configurado un enclave seguro para la base de datos. Si usa SQL Server, consulte Configuración del enclave seguro en SQL Server. Si usa Azure SQL Database, consulte Habilite Always Encrypted con enclaves seguros para su Azure SQL Database.

Sugerencia

Para saber si una clave maestra de columna está habilitada para el enclave, haga clic con el botón derecho en ella en el Explorador de objetos y seleccione Propiedades. Si la clave está habilitada para enclave, Enclave Computations: Allowed aparece en la ventana de propiedades de la clave. También puede usar la vista sys.column_master_keys (Transact-SQL).

Aprovisionamiento de claves de cifrado de columna habilitadas para el enclave con el cuadro de diálogo Nueva clave de cifrado de columnas

Para aprovisionar una clave de cifrado de columna habilitada para el enclave, siga los pasos descritos en Aprovisionamiento de claves de cifrado de columna con el cuadro de diálogo Nueva clave de cifrado de columnas. Al seleccionar una clave maestra de columna, asegúrese de que sea compatible con enclave.

Sugerencia

Para saber si una clave de cifrado de columna está habilitada para el enclave, haga clic con el botón derecho en ella en el Explorador de objetos y seleccione Propiedades. Si la clave es compatible con enclave, Cálculos de enclave: Permitidos aparece en la ventana que muestra las propiedades de la clave.

Aprovisionar claves compatibles con enclaves mediante PowerShell

Si quiere aprovisionar claves habilitadas para el enclave mediante PowerShell, necesitará el módulo de PowerShell SqlServer versión 22 o posterior.

Nota:

Microsoft recomienda usar PowerShell 7 o posterior al ejecutar scripts de PowerShell de Always Encrypted. PowerShell 7 proporciona compatibilidad multiplataforma mejorada, un mejor rendimiento y la compatibilidad más reciente con el módulo SqlServer (v22+), que es necesario para muchos escenarios de Always Encrypted.

En general, los flujos de trabajo de aprovisionamiento de claves de PowerShell (con y sin separación de roles) para Always Encrypted (descritos en Aprovisionamiento de claves de Always Encrypted con PowerShell) son válidos también con las claves habilitadas para el enclave. En esta sección se describen detalles específicos de las claves habilitadas para el enclave.

El módulo de PowerShell SqlServer amplía los cmdlets New-SqlCertificateStoreColumnMasterKeySettings y New-SqlAzureKeyVaultColumnMasterKeySettings con el parámetro -AllowEnclaveComputations, que permite especificar una clave maestra de columna habilitada para el enclave durante el proceso de aprovisionamiento. Cualquiera de estos cmdlets crea un objeto local que contiene las propiedades de una clave maestra de columna (almacenada en Azure Key Vault o en el almacén de certificados de Windows). Si se especifica, la propiedad -AllowEnclaveComputations marca la clave como habilitada para enclaves dentro del objeto local. También hace que el cmdlet acceda a la clave maestra de columna referida (en Azure Key Vault o en el almacén de certificados de Windows) para firmar las propiedades de la clave digitalmente. Una vez creado el objeto de configuración de una nueva clave maestra de columna habilitada para el enclave, se puede usar en una invocación posterior del cmdlet New-SqlColumnMasterKey para crear un objeto de metadatos que describa la nueva clave en la base de datos.

El aprovisionamiento de claves de cifrado de columna compatibles con enclave no difiere del aprovisionamiento de claves de cifrado de columna que no son compatibles con enclave. Solo hay que asegurarse de que la clave maestra de columna usada para cifrar la nueva clave de cifrado de columna sea compatible con enclave.

Nota:

El módulo SqlServer de PowerShell no admite actualmente el aprovisionamiento de claves compatibles con enclave almacenadas en módulos de seguridad de hardware (mediante CNG o CAPI).

Ejemplo: aprovisionar claves compatibles con enclave mediante el almacén de certificados de Windows

En el siguiente ejemplo completo se muestra cómo aprovisionar claves habilitadas para el enclave, almacenando la clave maestra de columna en el almacén de certificados de Windows. El script se basa en el ejemplo de Almacén de certificados de Windows sin separación de roles (ejemplo). Es importante tener en cuenta el uso del parámetro -AllowEnclaveComputations en el cmdlet New-SqlCertificateStoreColumnMasterKeySettings, que es la única diferencia entre los flujos de trabajo de los dos ejemplos.

[CmdletBinding()]
param(
	[Parameter(Mandatory = $false)]
	[string]$DatabaseName = '<database name>',

	[Parameter(Mandatory = $false)]
	[string]$ServerName = "<server name>",

	[Parameter(Mandatory = $false)]
	[string]$CertificateSubject = "AlwaysEncryptedCert",

	[Parameter(Mandatory = $false)]
	[string]$CmkName = "CMK",

	[Parameter(Mandatory = $false)]
	[string]$CekName = "CEK"
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

Import-Module SqlServer -MinimumVersion 22.0.50 -ErrorAction Stop

Write-Host "[AE] Locating certificate '$CertificateSubject' in CurrentUser\\My"
$cert = Get-ChildItem -Path Cert:CurrentUser\My |
	Where-Object { $_.Subject -eq "CN=$CertificateSubject" } |
	Sort-Object NotAfter -Descending |
	Select-Object -First 1

if (-not $cert) {
	Write-Host "[AE] Certificate not found. Creating self-signed certificate."
	$cert = New-SelfSignedCertificate `
		-Subject $CertificateSubject `
		-CertStoreLocation Cert:CurrentUser\My `
		-KeyExportPolicy Exportable `
		-Type DocumentEncryptionCert `
		-KeyUsage DataEncipherment `
		-KeySpec KeyExchange
}

Write-Host "[AE] Connecting to SQL Server '$ServerName' / Database '$DatabaseName'"
$connStr = "Server=$ServerName;Database=$DatabaseName;Integrated Security=True;Encrypt=True;TrustServerCertificate=True;Connection Timeout=30"

try {
	$database = Get-SqlDatabase -ConnectionString $connStr -ErrorAction Stop
}
catch {
	Write-Error "Failed to connect to '$ServerName' database '$DatabaseName'. Verify instance name SQL2025, database existence, and local permissions."
	throw
}

Write-Host "[AE] Creating CMK settings from certificate thumbprint"
$cmkSettings = New-SqlCertificateStoreColumnMasterKeySettings -CertificateStoreLocation "CurrentUser" -Thumbprint $cert.Thumbprint -AllowEnclaveComputations

Write-Host "[AE] Ensuring CMK '$CmkName' exists"
$existingCmk = Get-SqlColumnMasterKey -InputObject $database | Where-Object { $_.Name -eq $CmkName }
if (-not $existingCmk) {
	New-SqlColumnMasterKey -Name $CmkName -InputObject $database -ColumnMasterKeySettings $cmkSettings | Out-Null
}

Write-Host "[AE] Ensuring CEK '$CekName' exists"
$existingCek = Get-SqlColumnEncryptionKey -InputObject $database | Where-Object { $_.Name -eq $CekName }
if (-not $existingCek) {
	New-SqlColumnEncryptionKey -Name $CekName -InputObject $database -ColumnMasterKey $CmkName | Out-Null
}

Write-Host "Completed successfully"

Ejemplo: aprovisionar claves habilitadas para el enclave mediante Azure Key Vault

En el siguiente ejemplo completo se muestra cómo aprovisionar claves habilitadas para el enclave mediante el almacenamiento de la clave maestra de columna en un almacén de claves en Azure Key Vault. El script se basa en el ejemplo de Azure Key Vault sin separación de roles (ejemplo). Es importante tener en cuenta dos diferencias entre el flujo de trabajo de las claves compatibles con enclave y el de las claves que no lo son.

  • En el siguiente script, New-SqlCertificateStoreColumnMasterKeySettings usa el parámetro -AllowEnclaveComputations para que la nueva clave maestra de columna esté habilitada para el enclave.
  • El siguiente script usa el cmdlet Get-AzAccessToken para obtener un token de acceso para almacenes de claves. Esto es necesario, ya que New-SqlAzureKeyVaultColumnMasterKeySettings debe tener acceso a Azure Key Vault para firmar las propiedades de la clave maestra de columna.
param(
	[Parameter(Mandatory = $true)] [string]$SubscriptionId,
	[Parameter(Mandatory = $true)] [string]$ResourceGroupName,
	[Parameter(Mandatory = $true)] [string]$AzureLocation,
	[Parameter(Mandatory = $true)] [string]$KeyVaultName,
	[Parameter(Mandatory = $true)] [string]$KeyName,
	[Parameter(Mandatory = $true)] [string]$ServerName,
	[Parameter(Mandatory = $true)] [string]$DatabaseName,
	[string]$CmkName = "CMK",
	[string]$CekName = "CEK",
	[bool]$AssignRbacToCurrentPrincipal = $true
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

Import-Module Az.Accounts -ErrorAction Stop
Import-Module Az.Resources -ErrorAction Stop
Import-Module Az.KeyVault -ErrorAction Stop
Import-Module SqlServer -ErrorAction Stop

function Get-CurrentPrincipalObjectId {
	param([string]$AccountId)

	$userSignedIn = Get-AzADUser -SignedIn -ErrorAction SilentlyContinue
	if ($userSignedIn) { return $userSignedIn.Id }

	$user = Get-AzADUser -UserPrincipalName $AccountId -ErrorAction SilentlyContinue
	if ($user) { return $user.Id }

	$sp = Get-AzADServicePrincipal -DisplayName $AccountId -ErrorAction SilentlyContinue | Select-Object -First 1
	if ($sp) { return $sp.Id }

	throw "Could not resolve Microsoft Entra object id for account '$AccountId'."
}

try {
	Write-Host "[AE] Signing in and selecting subscription"
	Connect-AzAccount | Out-Null
	$ctx = Set-AzContext -SubscriptionId $SubscriptionId

	Write-Host "[AE] Ensuring resource group exists"
	$resourceGroup = Get-AzResourceGroup -Name $ResourceGroupName -ErrorAction SilentlyContinue
	if (-not $resourceGroup) {
		$resourceGroup = New-AzResourceGroup -Name $ResourceGroupName -Location $AzureLocation
	}

	Write-Host "[AE] Ensuring key vault exists (RBAC mode)"
	$vault = Get-AzKeyVault -VaultName $KeyVaultName -ResourceGroupName $ResourceGroupName -ErrorAction SilentlyContinue
	if (-not $vault) {
		$vault = New-AzKeyVault -VaultName $KeyVaultName -ResourceGroupName $ResourceGroupName -Location $AzureLocation -EnableRbacAuthorization
	}

	if (-not $vault.EnableRbacAuthorization) {
		throw "Key Vault '$KeyVaultName' is not using RBAC authorization. Enable RBAC authorization on the vault before running this script."
	}

	if ($AssignRbacToCurrentPrincipal) {
		Write-Host "[AE] Ensuring RBAC role assignment"
		$principalSignInName = $ctx.Account.Id
		$roleName = "Key Vault Crypto Officer"
		$existingRole = Get-AzRoleAssignment -SignInName $principalSignInName -Scope $vault.ResourceId -RoleDefinitionName $roleName -ErrorAction SilentlyContinue
		if (-not $existingRole) {
			New-AzRoleAssignment -SignInName $principalSignInName -Scope $vault.ResourceId -RoleDefinitionName $roleName | Out-Null
		}
	}

	Write-Host "[AE] Ensuring column master key material exists in Key Vault"
	$akvKey = Get-AzKeyVaultKey -VaultName $KeyVaultName -Name $KeyName -ErrorAction SilentlyContinue
	if (-not $akvKey) {
		$akvKey = Add-AzKeyVaultKey -VaultName $KeyVaultName -Name $KeyName -Destination "Software"
	}

	Write-Host "[AE] Connecting to Azure SQL and creating metadata"
	$keyVaultAccessToken = (Get-AzAccessToken -ResourceUrl "https://vault.azure.net").Token
	$connStr = "Server=tcp:$ServerName.database.windows.net,1433;Database=$DatabaseName;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;Authentication=Active Directory Interactive"
	$database = Get-SqlDatabase -ConnectionString $connStr -Encrypt Mandatory
	$cmkSettings = New-SqlAzureKeyVaultColumnMasterKeySettings -KeyUrl $akvKey.Key.Kid -AllowEnclaveComputations

	$existingCmk = Get-SqlColumnMasterKey -InputObject $database | Where-Object { $_.Name -eq $CmkName }
	if (-not $existingCmk) {
		New-SqlColumnMasterKey -Name $CmkName -InputObject $database -ColumnMasterKeySettings $cmkSettings | Out-Null
	}

	$existingCek = Get-SqlColumnEncryptionKey -InputObject $database | Where-Object { $_.Name -eq $CekName }
	if (-not $existingCek) {
		New-SqlColumnEncryptionKey -Name $CekName -InputObject $database -ColumnMasterKey $CmkName -KeyVaultAccessToken $keyVaultAccessToken | Out-Null
	}

	Write-Host "Completed successfully"
}
catch {
	Write-Error "Script failed: $($_.Exception.Message)"
	throw
}