Azure 磁盘加密示例脚本Azure Disk Encryption sample scripts

本文提供了用于准备预加密 VHD 和其他任务的示例脚本。This article provides sample scripts for preparing pre-encrypted VHDs and other tasks.

列出 VM 和机密List VMs and secrets

列出订阅中所有已加密的 VM:List all encrypted VMs in your subscription:

$osVolEncrypted = {(Get-AzVMDiskEncryptionStatus -ResourceGroupName $_.ResourceGroupName -VMName $_.Name).OsVolumeEncrypted}
$dataVolEncrypted= {(Get-AzVMDiskEncryptionStatus -ResourceGroupName $_.ResourceGroupName -VMName $_.Name).DataVolumesEncrypted}
Get-AzVm | Format-Table @{Label="MachineName"; Expression={$_.Name}}, @{Label="OsVolumeEncrypted"; Expression=$osVolEncrypted}, @{Label="DataVolumesEncrypted"; Expression=$dataVolEncrypted}

列出密钥保管库中用于加密 VM 的所有磁盘加密机密:List all disk encryption secrets used for encrypting VMs in a key vault:

Get-AzKeyVaultSecret -VaultName $KeyVaultName | where {$_.Tags.ContainsKey('DiskEncryptionKeyFileName')} | format-table @{Label="MachineName"; Expression={$_.Tags['MachineName']}}, @{Label="VolumeLetter"; Expression={$_.Tags['VolumeLetter']}}, @{Label="EncryptionKeyURL"; Expression={$_.Id}}

Azure 磁盘加密先决条件脚本The Azure Disk Encryption prerequisites scripts

如果你已熟悉进行 Azure 磁盘加密的先决条件,则可以使用 Azure 磁盘加密先决条件 PowerShell 脚本If you're already familiar with the prerequisites for Azure Disk Encryption, you can use the Azure Disk Encryption prerequisites PowerShell script. 有关此 PowerShell 脚本的用法示例,请参阅有关加密 VM 的快速入门For an example of using this PowerShell script, see the Encrypt a VM Quickstart. 可以删除脚本的某个部分中的注释(从第 211 行开始),以加密现有资源组中现有 VM 的所有磁盘。You can remove the comments from a section of the script, starting at line 211, to encrypt all disks for existing VMs in an existing resource group.

下表显示了可在 PowerShell 脚本中使用的参数:The following table shows which parameters can be used in the PowerShell script:

参数Parameter 说明Description 必需?Mandatory?
$resourceGroupName$resourceGroupName KeyVault 所属的资源组的名称。Name of the resource group to which the KeyVault belongs to. 如果不存在具有此名称的资源组,则会新建一个资源组。A new resource group with this name will be created if one doesn't exist. TrueTrue
$keyVaultName$keyVaultName 要将加密密钥放到的 KeyVault 的名称。Name of the KeyVault in which encryption keys are to be placed. 如果不存在具有此名称的保管库,则会新建一个保管库。A new vault with this name will be created if one doesn't exist. TrueTrue
$location$location KeyVault 的位置。Location of the KeyVault. 请确保 KeyVault 和要加密的 VM 位于同一位置。Make sure the KeyVault and VMs to be encrypted are in the same location. 使用 Get-AzLocation 获取位置列表。Get a location list with Get-AzLocation. TrueTrue
$subscriptionId$subscriptionId 要使用的 Azure 订阅的标识符。Identifier of the Azure subscription to be used. 可以使用 Get-AzSubscription 获取订阅 ID。You can get your Subscription ID with Get-AzSubscription. TrueTrue
$aadAppName$aadAppName 用于将机密写入 KeyVault 的 Azure AD 应用程序的名称。Name of the Azure AD application that will be used to write secrets to KeyVault. 如果该应用程序不存在,则会使用此名称创建新的应用程序。A new application with this name will be created if one doesn't exist. 如果此应用已存在,则将 aadClientSecret 参数传递给脚本。If this app already exists, pass aadClientSecret parameter to the script. FalseFalse
$aadClientSecret$aadClientSecret 之前创建的 Azure AD 应用程序的客户端机密。Client secret of the Azure AD application that was created earlier. FalseFalse
$keyEncryptionKeyName$keyEncryptionKeyName KeyVault 中的可选密钥加密密钥的名称。Name of optional key encryption key in KeyVault. 如果不存在具有此名称的密钥,则会新建一个密钥。A new key with this name will be created if one doesn't exist. FalseFalse

资源管理器模板Resource Manager templates

在不使用 Azure AD 应用的情况下加密或解密 VMEncrypt or decrypt VMs without an Azure AD app

使用 Azure AD 应用加密或解密 VM(以前的版本)Encrypt or decrypt VMs with an Azure AD app (previous release)

准备预加密的 Windows VHDPrepare a pre-encrypted Windows VHD

以下部分介绍了必要操作,让你在 Azure IaaS 中准备将预加密的 Windows VHD 部署为加密 VHD。The sections that follow are necessary to prepare a pre-encrypted Windows VHD for deployment as an encrypted VHD in Azure IaaS. 使用该信息在 Azure Site Recovery 或 Azure 上准备和启动全新的 Windows VM (VHD)。Use the information to prepare and boot a fresh Windows VM (VHD) on Azure Site Recovery or Azure. 有关如何准备和上传 VHD 的详细信息,请参阅上传通用化 VHD 并使用它在 Azure 中创建新的 VMFor more information on how to prepare and upload a VHD, see Upload a generalized VHD and use it to create new VMs in Azure.

更新组策略以允许使用非 TPM 保护 OSUpdate group policy to allow non-TPM for OS protection

在“本地计算机策略” > “计算机设置” > “管理模板” > “Windows 组件”下配置名为“BitLocker 驱动器加密”的 BitLocker 组策略设置。Configure the BitLocker Group Policy setting BitLocker Drive Encryption, which you'll find under Local Computer Policy > Computer Configuration > Administrative Templates > Windows Components. 如下图所示,将此设置更改为“操作系统驱动器” > “启动时需要附加身份验证” > “没有兼容的 TPM 时允许 BitLocker” :Change this setting to Operating System Drives > Require additional authentication at startup > Allow BitLocker without a compatible TPM, as shown in the following figure:

Azure 中的 Microsoft Antimalware

安装 BitLocker 功能组件Install BitLocker feature components

对于 Windows Server 2012 或更高版本,请使用以下命令:For Windows Server 2012 and later, use the following command:

dism /online /Enable-Feature /all /FeatureName:BitLocker /quiet /norestart

对于 Windows Server 2008 R2,请使用以下命令:For Windows Server 2008 R2, use the following command:

ServerManagerCmd -install BitLockers

使用 bdehdcfg 为 BitLocker 准备 OS 卷Prepare the OS volume for BitLocker by using bdehdcfg

若要压缩 OS 分区并为 BitLocker 准备计算机,请根据需要执行 bdehdcfgTo compress the OS partition and prepare the machine for BitLocker, execute the bdehdcfg if needed:

bdehdcfg -target c: shrink -quiet 

使用 BitLocker 保护 OS 卷Protect the OS volume by using BitLocker

使用 manage-bde 命令在使用外部密钥保护程序的引导卷上启用加密。Use the manage-bde command to enable encryption on the boot volume using an external key protector. 此外将外部密钥(.bek 文件)放在外部驱动器或卷上。Also place the external key (.bek file) on the external drive or volume. 下次重启后,会在系统/引导卷上启用加密。Encryption is enabled on the system/boot volume after the next reboot.

manage-bde -on %systemdrive% -sk [ExternalDriveOrVolume]
reboot

备注

使用独立的数据/资源 VHD 准备 VM,以使用 BitLocker 获取外部密钥。Prepare the VM with a separate data/resource VHD for getting the external key by using BitLocker.

将加密的 VHD 上传到 Azure 存储帐户Upload encrypted VHD to an Azure storage account

启用 DM-Crypt 加密后,需要将本地加密的 VHD 上传到存储帐户。After DM-Crypt encryption is enabled, the local encrypted VHD needs to be uploaded to your storage account.

    Add-AzVhd [-Destination] <Uri> [-LocalFilePath] <FileInfo> [[-NumberOfUploaderThreads] <Int32> ] [[-BaseImageUriToPatch] <Uri> ] [[-OverWrite]] [ <CommonParameters>]

将预加密 VM 的机密上传到密钥保管库Upload the secret for the pre-encrypted VM to your key vault

必须将前面获取的磁盘加密机密作为机密上传到密钥保管库中。The disk encryption secret that you obtained previously must be uploaded as a secret in your key vault. 这需要向将上传机密的帐户授予 set secret 权限和 wrapkey 权限。This requires granting the set secret permission and the wrapkey permission to the account that will upload the secrets.

# Typically, account Id is the user principal name (in user@domain.com format)
$upn = (Get-AzureRmContext).Account.Id
Set-AzKeyVaultAccessPolicy -VaultName $kvname -UserPrincipalName $acctid -PermissionsToKeys wrapKey -PermissionsToSecrets set

# In local Shell, the account ID is a managed service identity, so specify the username directly 
# $upn = "user@domain.com" 
# Set-AzKeyVaultAccessPolicy -VaultName $kvname -UserPrincipalName $acctid -PermissionsToKeys wrapKey -PermissionsToSecrets set

# When running as a service principal, retrieve the service principal ID from the account ID, and set access policy to that 
# $acctid = (Get-AzureRmContext).Account.Id
# $spoid = (Get-AzureRmADServicePrincipal -ServicePrincipalName $acctid).Id
# Set-AzKeyVaultAccessPolicy -VaultName $kvname -ObjectId $spoid -BypassObjectIdValidation -PermissionsToKeys wrapKey -PermissionsToSecrets set

未使用 KEK 加密的磁盘加密机密Disk encryption secret not encrypted with a KEK

若要在密钥保管库中设置机密,请使用 Set-AzKeyVaultSecretTo set up the secret in your key vault, use Set-AzKeyVaultSecret. 将密码编码为 base64 字符串,然后将其上传到密钥保管库。The passphrase is encoded as a base64 string and then uploaded to the key vault. 此外,请确保在 Key Vault 中创建机密时设置以下标记。In addition, make sure that the following tags are set when you create the secret in the key vault.


 # This is the passphrase that was provided for encryption during the distribution installation
 $passphrase = "contoso-password"

 $tags = @{"DiskEncryptionKeyEncryptionAlgorithm" = "RSA-OAEP"; "DiskEncryptionKeyFileName" = "LinuxPassPhraseFileName"}
 $secretName = [guid]::NewGuid().ToString()
 $secretValue = [Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($passphrase))
 $secureSecretValue = ConvertTo-SecureString $secretValue -AsPlainText -Force

 $secret = Set-AzKeyVaultSecret -VaultName $KeyVaultName -Name $secretName -SecretValue $secureSecretValue -tags $tags
 $secretUrl = $secret.Id

在下一步中使用 $secretUrl 以便在不使用 KEK 的情况下附加 OS 磁盘Use the $secretUrl in the next step for attaching the OS disk without using KEK.

使用 KEK 加密的磁盘加密机密Disk encryption secret encrypted with a KEK

将机密上传到 Key Vault 之前,可根据需要使用密钥加密密钥对其进行加密。Before you upload the secret to the key vault, you can optionally encrypt it by using a key encryption key. 先使用包装 API 加密使用密钥加密密钥的机密。Use the wrap API to first encrypt the secret using the key encryption key. 此包装操作的输出是 base64 URL 编码的字符串,可以使用 Set-AzKeyVaultSecret cmdlet 将其作为机密上传。The output of this wrap operation is a base64 URL encoded string, which you can then upload as a secret by using the Set-AzKeyVaultSecret cmdlet.

    # This is the passphrase that was provided for encryption during the distribution installation
    $passphrase = "contoso-password"

    Add-AzKeyVaultKey -VaultName $KeyVaultName -Name "keyencryptionkey" -Destination Software
    $KeyEncryptionKey = Get-AzKeyVaultKey -VaultName $KeyVault.OriginalVault.Name -Name "keyencryptionkey"

    $apiversion = "2015-06-01"

    ##############################
    # Get Auth URI
    ##############################

    $uri = $KeyVault.VaultUri + "/keys"
    $headers = @{}

    $response = try { Invoke-RestMethod -Method GET -Uri $uri -Headers $headers } catch { $_.Exception.Response }

    $authHeader = $response.Headers["www-authenticate"]
    $authUri = [regex]::match($authHeader, 'authorization="(.*?)"').Groups[1].Value

    Write-Host "Got Auth URI successfully"

    ##############################
    # Get Auth Token
    ##############################

    $uri = $authUri + "/oauth2/token"
    $body = "grant_type=client_credentials"
    $body += "&client_id=" + $AadClientId
    $body += "&client_secret=" + [Uri]::EscapeDataString($AadClientSecret)
    $body += "&resource=" + [Uri]::EscapeDataString("https://vault.azure.cn")
    $headers = @{}

    $response = Invoke-RestMethod -Method POST -Uri $uri -Headers $headers -Body $body

    $access_token = $response.access_token

    Write-Host "Got Auth Token successfully"

    ##############################
    # Get KEK info
    ##############################

    $uri = $KeyEncryptionKey.Id + "?api-version=" + $apiversion
    $headers = @{"Authorization" = "Bearer " + $access_token}

    $response = Invoke-RestMethod -Method GET -Uri $uri -Headers $headers

    $keyid = $response.key.kid

    Write-Host "Got KEK info successfully"

    ##############################
    # Encrypt passphrase using KEK
    ##############################

    $passphraseB64 = [Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($Passphrase))
    $uri = $keyid + "/encrypt?api-version=" + $apiversion
    $headers = @{"Authorization" = "Bearer " + $access_token; "Content-Type" = "application/json"}
    $bodyObj = @{"alg" = "RSA-OAEP"; "value" = $passphraseB64}
    $body = $bodyObj | ConvertTo-Json

    $response = Invoke-RestMethod -Method POST -Uri $uri -Headers $headers -Body $body

    $wrappedSecret = $response.value

    Write-Host "Encrypted passphrase successfully"

    ##############################
    # Store secret
    ##############################

    $secretName = [guid]::NewGuid().ToString()
    $uri = $KeyVault.VaultUri + "/secrets/" + $secretName + "?api-version=" + $apiversion
    $secretAttributes = @{"enabled" = $true}
    $secretTags = @{"DiskEncryptionKeyEncryptionAlgorithm" = "RSA-OAEP"; "DiskEncryptionKeyFileName" = "LinuxPassPhraseFileName"}
    $headers = @{"Authorization" = "Bearer " + $access_token; "Content-Type" = "application/json"}
    $bodyObj = @{"value" = $wrappedSecret; "attributes" = $secretAttributes; "tags" = $secretTags}
    $body = $bodyObj | ConvertTo-Json

    $response = Invoke-RestMethod -Method PUT -Uri $uri -Headers $headers -Body $body

    Write-Host "Stored secret successfully"

    $secretUrl = $response.id

将在下一步中使用 $KeyEncryptionKey$secretUrl 以便在使用 KEK 的情况下附加 OS 磁盘Use $KeyEncryptionKey and $secretUrl in the next step for attaching the OS disk using KEK.

附加 OS 磁盘时指定机密 URLSpecify a secret URL when you attach an OS disk

不使用 KEKWithout using a KEK

附加 OS 磁盘时,需要传递 $secretUrlWhile you're attaching the OS disk, you need to pass $secretUrl. 该 URL 是在“不使用 KEK 对磁盘加密机密进行加密”部分中生成的。The URL was generated in the "Disk-encryption secret not encrypted with a KEK" section.

    Set-AzVMOSDisk `
            -VM $VirtualMachine `
            -Name $OSDiskName `
            -SourceImageUri $VhdUri `
            -VhdUri $OSDiskUri `
            -Windows `
            -CreateOption FromImage `
            -DiskEncryptionKeyVaultId $KeyVault.ResourceId `
            -DiskEncryptionKeyUrl $SecretUrl

使用 KEKUsing a KEK

附加 OS 磁盘时,传递 $KeyEncryptionKey$secretUrlWhen you attach the OS disk, pass $KeyEncryptionKey and $secretUrl. 该 URL 是在“使用 KEK 加密的磁盘加密机密”部分生成的。The URL was generated in the "Disk encryption secret encrypted with a KEK" section.

    Set-AzVMOSDisk `
            -VM $VirtualMachine `
            -Name $OSDiskName `
            -SourceImageUri $CopiedTemplateBlobUri `
            -VhdUri $OSDiskUri `
            -Windows `
            -CreateOption FromImage `
            -DiskEncryptionKeyVaultId $KeyVault.ResourceId `
            -DiskEncryptionKeyUrl $SecretUrl `
            -KeyEncryptionKeyVaultId $KeyVault.ResourceId `
            -KeyEncryptionKeyURL $KeyEncryptionKey.Id