准备工作
- 一台 Windows 10 及以上的电脑
- 此电脑与 ESXi 主机互通
- 此电脑有良好的互联网连接
- ESXi 不能使用免费许可证
步骤一、安装 PowerCLI
以管理员模式运行 Windows PowerShell,运行以下命令。
Set-ExecutionPolicy -ExecutionPolicy Bypass
Install-Module -Name VMware.PowerCLI
安装过程中需要输入 Y 或者 A,视网络情况可能需要较长时间。
步骤二、准备脚本
William Lam 编写了一个vTPMStandaloneESXiFunctions.ps1
脚本,将其保存到桌面备用。
https://github.com/lamw/vmware-scripts/blob/master/powershell/vTPMStandaloneESXiFunctions.ps1
# Author: William Lam
# Description: PowerCLI functions to configure host encryption for a standanlone ESXi host to support vTPM without vCenter Server
Function New-256BitKey {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.williamlam.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
This function returns randomly generated 256 bit key encoded using base64
.EXAMPLE
New-256BitKey
#>
# Generate 256 bit key
# Thank you ChatGPT for this code
$randomKey = [byte[]]::new(32)
$rand = [System.Security.Cryptography.RandomNumberGenerator]::Create()
$rand.GetBytes($randomKey)
# Encode the key using Base64
return [Convert]::ToBase64String($randomKey)
}
Function Prepare-VMHostForEncryption {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.williamlam.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
This function prepares the ESXi host for encryption
.EXAMPLE
Prepare-VMHostForEncryption
#>
$cm = Get-View $global:DefaultVIServer.ExtensionData.Content.CryptoManager
$cryptoState = (Get-VMHost).ExtensionData.Runtime.CryptoState
if($cryptoState -eq "incapable") {
Write-Host -ForegroundColor Yellow "`nPreparing ESXi Host for encryption ..."
$cm.CryptoManagerHostPrepare()
Write-Host -ForegroundColor Green "Successfully prepared ESXi Host for encryption ...`n"
} else {
Write-Host "`nESXi Host has already been prepared for encryption ...`n"
}
}
Function New-InitialVMHostKey {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.williamlam.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
This function creates and/or ipmorts host key
.PARAMETER Operation
CREATE or IMPORT
.PARAMETER KeyName
Name of the VM Key
.PARAMETER CSVTPMKeyFile
Name of CSV file to save TPM keys (Default: tpm-keys.csv)
.EXAMPLE
# Request new VM Key
New-InitialVMHostKey -Operation CREATE -KeyName "host-key-1"
.EXAMPLE
# Imports an existing VM Key
New-InitialVMHostKey -Operation IMPORT -KeyName "host-key-1" -CSVTPMKeyFile tpm-keys.csv
#>
param(
[Parameter(Mandatory=$true)][ValidateSet("CREATE","IMPORT")][string]$Operation,
[Parameter(Mandatory=$true)][String]$KeyName,
[Parameter(Mandatory=$false)][String]$CSVTPMKeyFile="tpm-keys.csv"
)
$cryptoState = (Get-VMHost).ExtensionData.Runtime.CryptoState
if($cryptoState -eq "safe") {
Write-Host -ForegroundColor Red "`nESXi host has already been configured with initial host key ...`n"
break
}
if($cryptoState -ne "prepared") {
Write-Host -ForegroundColor Red "`nESXi host has not been prepared for encryption ...`n"
break
}
$cm = Get-View $global:DefaultVIServer.ExtensionData.Content.CryptoManager
# Create or import initial host key
if($Operation -eq "CREATE") {
Write-Host -ForegroundColor Yellow "Generating random 256 bit host key ..."
$hostBase64Key = New-256BitKey
$keyAlgorithim = "AES-256"
} else {
$csvfile = Import-Csv $CSVTPMKeyFile
foreach ($line in $csvfile) {
if($line.KEYID -eq $KeyName -and $line.TYPE -eq "HOST") {
Write-Host -ForegroundColor Yellow "Importing existing host key from $CSVTPMKeyFile ..."
$hostBase64Key = $line.DATA
$keyAlgorithim = $line.ALGORITHIM
break
}
}
}
if($hostBase64Key -eq $null) {
Write-Host -ForegroundColor Red "Failed to find host key ${KeyName} ...`n"
break
}
$hostKeyId = New-Object VMware.Vim.CryptoKeyId
$hostKeyId.keyId = $KeyName
$hostKeySpec = New-Object VMware.Vim.CryptoKeyPlain
$hostKeySpec.KeyId = $hostKeyId
$hostKeySpec.Algorithm = $keyAlgorithim
$hostKeySpec.KeyData = $hostBase64Key
Write-Host -ForegroundColor Yellow "Adding ESXi Host Key ${KeyName} ..."
try {
$cm.CryptoManagerHostEnable($hostKeySpec)
} catch {
Write-Host -ForegroundColor Red "Failed to add host key ${KeyName} ...`n"
break
}
# Automatically backup host key to CSV file
if($Operation -eq "CREATE") {
if (Test-Path -Path $CSVTPMKeyFile -PathType Leaf) {
Write-Host -ForegroundColor Yellow "ESXi TPM Keys file $CSVTPMKeyFile exists, please use import operation"
} else {
$newcsv = {} | Select "KEYID","ALGORITHIM","TYPE","DATA" | Export-Csv $CSVTPMKeyFile
$csvfile = Import-Csv $CSVTPMKeyFile
$csvfile.KEYID = $KeyName
$csvfile.ALGORITHIM = $keyAlgorithim
$csvfile.TYPE = "HOST"
$csvfile.DATA = $hostBase64Key
Write-Host -ForegroundColor Yellow "Exporting ${KeyName} to $CSVTPMKeyFile ..."
$csvfile | Export-CSV -Path $CSVTPMKeyFile
}
}
Write-Host -ForegroundColor Green "Successfully added initial host encryption key ${KeyName} ...`n"
}
Function New-VMTPMKey {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.williamlam.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
This function creates and/or ipmorts Host key
.PARAMETER Operation
CREATE or IMPORT
.PARAMETER KeyName
Name of the VM Key
.PARAMETER CSVTPMKeyFile
Name of CSV file to save TPM keys (Default: tpm-keys.csv)
.EXAMPLE
# Request new Host Key
New-VMTPMKey -Operation CREATE -KeyName "windows-11-key"
.EXAMPLE
# Imports an existing Host Key
New-VMTPMKey -Operation IMPORT -KeyName "windows-11-key" -CSVTPMKeyFile tpm-keys.csv
#>
param(
[Parameter(Mandatory=$true)][ValidateSet("CREATE","IMPORT")][string]$Operation,
[Parameter(Mandatory=$true)][String]$KeyName,
[Parameter(Mandatory=$false)][String]$CSVTPMKeyFile="tpm-keys.csv"
)
$cm = Get-View $global:DefaultVIServer.ExtensionData.Content.CryptoManager
# Ensure ESXi host encryption is enabled
if($cm.Enabled) {
# Create or import VM key
if($Operation -eq "CREATE") {
Write-Host -ForegroundColor Yellow "Generating random 256 bit VM key ..."
$vmBase64Key = New-256BitKey
$keyAlgorithim = "AES-256"
} else {
$csvfile = Import-Csv $CSVTPMKeyFile
foreach ($line in $csvfile) {
if($line.KEYID -eq $KeyName -and $line.TYPE -eq "VM") {
Write-Host -ForegroundColor Yellow "Importing existing VM key from $CSVTPMKeyFile ..."
$vmBase64Key = $line.DATA
$keyAlgorithim = $line.ALGORITHIM
break
}
}
}
if($vmBase64Key -eq $null) {
Write-Host -ForegroundColor Red "Failed to find VM key ${KeyName} ...`n"
break
}
$vmKeyId = New-Object VMware.Vim.CryptoKeyId
$vmKeyId.keyId = $KeyName
$vmKeySpec = New-Object VMware.Vim.CryptoKeyPlain
$vmKeySpec.KeyId = $vmKeyId
$vmKeySpec.Algorithm = $keyAlgorithim
$vmKeySpec.KeyData = $vmBase64Key
Write-Host -ForegroundColor Yellow "Adding VM key ${KeyName} ..."
try {
$cm.AddKey($vmKeySpec)
} catch {
Write-Host -ForegroundColor Red "Failed to add VM key ${KeyName} ...`n"
break
}
# Automatically backup VM key to CSV file
if($Operation -eq "CREATE") {
if (Test-Path -Path $CSVTPMKeyFile -PathType Leaf) {
$tmp = [PSCustomObject] [ordered]@{
KEYID = $KeyName;
ALGORITHIM = $keyAlgorithim;
TYPE = "VM";
DATA = $vmBase64Key
}
Write-Host -ForegroundColor Yellow "Exporting ${KeyName} to $CSVTPMKeyFile ..."
$tmp | Export-CSV -Append -NoTypeInformation -Path $CSVTPMKeyFile
} else {
Write-Error "Unable to find $CSVTPMKeyFile ..."
}
}
Write-Host -ForegroundColor Green "Successfully added VM encryption key ${KeyName} ...`n"
} else {
Write-Host -ForegroundColor Red "`nESXi host has not been prepared for encryption ...`n"
}
}
Function Remove-VMTPMKey {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.williamlam.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
This function removes an existing VM key
.PARAMETER KeyName
Name of the VM Key
.PARAMETER Force
Force remove VM Key
.EXAMPLE
# Remove VM key
Remove-VMTPMKey -KeyName "windows-11-key"
.EXAMPLE
# Forcefully remove VM key
Remove-VMTPMKey -KeyName "windows-11-key" -Force $true
#>
param(
[Parameter(Mandatory=$true)][String]$KeyName,
[Parameter(Mandatory=$false)][Boolean]$Force=$false
)
$cm = Get-View $global:DefaultVIServer.ExtensionData.Content.CryptoManager
$key = $cm.ListKeys($null) | where {$_.KeyId -eq $KeyName}
Write-Host -ForegroundColor Yellow "Removing VM key ${KeyName} ..."
try {
$cm.RemoveKey($key,$Force)
} catch {
Write-Host -ForegroundColor Red "Failed to remove VM key, maybe in use or use -Force option to forcefully remove ...`n"
break
}
Write-Host -ForegroundColor Green "Successfully removed VM key ...`n"
}
Function Get-VMHostTPMKeys {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.williamlam.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
This function returns all Host/VM keys
.EXAMPLE
Get-VMHostTPMKeys
#>
$cm = Get-View $global:DefaultVIServer.ExtensionData.Content.CryptoManager
if($cm.Enabled) {
$cm.ListKeys($null)
} else {
Write-Host -ForegroundColor Red "`nESXi host has not been prepared for encryption or does not contain initial host key ...`n"
}
}
Function Reconfigure-VMWithvTPM {
<#
.NOTES
===========================================================================
Created by: William Lam
Organization: VMware
Blog: www.williamlam.com
Twitter: @lamw
===========================================================================
.DESCRIPTION
This function adds vTPM to existing VM and applies an existing VM key for encryption
.PARAMETER KeyName
Name of the VM Key
.PARAMETER VMName
Name of the VM to add vTPM
.EXAMPLE
Reconfigure-VMWithvTPM -KeyName "windows-11-key" -VMName "Windows-11"
#>
param(
[Parameter(Mandatory=$true)][String]$KeyName,
[Parameter(Mandatory=$true)][String]$VMName
)
$vm = Get-VM $VMName
$cm = Get-View $global:DefaultVIServer.ExtensionData.Content.CryptoManager
# Retrieve VM key
$cryptoSpec = New-Object VMware.Vim.CryptoSpecEncrypt
$cryptoSpec.CryptoKeyId = $cm.ListKeys($null) | where {$_.KeyId -eq $KeyName}
$spec = New-Object VMware.Vim.VirtualMachineConfigSpec
# Set VM encryption key
$spec.Crypto = $cryptoSpec
# Add TPM device
$spec.deviceChange = New-Object VMware.Vim.VirtualDeviceConfigSpec
$spec.deviceChange[0].operation = 'add'
$spec.deviceChange[0].device = New-Object VMware.Vim.VirtualTPM
$spec.DeviceChange[0].Device.Key = 11000
# Reconfigure VM
Write-Host -ForegroundColor Yellow "Adding vTPM to ${VMName} using encryption key ${KeyName} ..."
$task = $vm.ExtensionData.ReconfigVM_Task($spec)
$task1 = Get-Task -Id ("Task-$($task.value)")
$task1 | Wait-Task
}
步骤三、准备 ESXi 主机加密
运行以下命令连接到你的 ESXi 主机。
Connect-VIServer -Server 192.168.xx.xx -User root -Password "xxxx"
如果提示证书不信任,则运行以下命令忽略验证。
Set-PowerCLIConfiguration -InvalidCertificateAction Ignore
一切就绪后,加载步骤二中的脚本并运行。
. ./vTPMStandaloneESXiFunctions.ps1
Prepare-VMHostForEncryption
接下来需要设置初始 ESXi 主机加密密钥,并为密钥提供一个名称。
New-InitialVMHostKey -Operation CREATE -KeyName "host-key-1"
注意此操作仅需要运行一次!
接下来,就可以生成新的虚拟机加密密钥,然后使用该密钥对给定虚拟机的 vTPM 设备进行加密。
New-VMTPMKey -Operation CREATE -KeyName "windows-11-key"
最后,将虚拟机关机并添加 vTPM 设备,使用之前生成的特定虚拟机加密密钥对其进行加密。
Reconfigure-VMWithvTPM -KeyName "windows-11-key" -VMName "Windows-11"
如果一切顺利,现在就可以在虚拟机中看到 vTPM,如下图所示。
大功告成,可以安装 Windows 11 了。
如果需要移除虚拟机加密密钥,可以使用以下命令。如果需要强制删除虚拟机加密密钥,可以加上 -Force $true
选项。
Remove-VMTPMKey -KeyName "windows-11-key"
注意事项
默认情况下,ESXi 不会在重启时存储或保存任何加密密钥!需要重新添加已分配给虚拟机的所有主机和任何虚拟机加密密钥,否则将无法启动虚拟机。这是 vCenter Server 通过管理由 SKP 或 NKP 提供给相应 ESXi 主机的加密密钥以确保其可用性而提供的主要优势和功能之一。
作为一种变通方法,每次使用 PowerCLI 功能生成主机或虚拟机加密密钥时,脚本都会实施自动加密密钥备份。默认情况下,加密密钥会自动保存到名为 tpm-keys.csv 的 CSV 文件中,也可以选择自己的文件名。使用加密密钥备份文件可以轻松地将所有加密密钥重新导入 ESXi 主机。
这时,拥有一个物理 TPM 将非常有用!如果服务器拥有符合 TPM 2.0 标准的物理 TPM 芯片(需要 FIFO 协议,而非 CRB 协议,后者通常存在于许多消费平台中,且不受支持),那么就可以使用此处概述的说明在 ESXi 中启用密钥持久性功能,这样就可以自动持久保存已添加到 ESXi 主机的所有加密密钥(无论是通过使用 vSphere API 还是通过 vCenter Server 手动添加),并将其存储在 TPM 芯片上。
如果没有符合 TPM 2.0 标准的物理芯片,那么只需确保备份已生成的主机和虚拟机加密密钥,这些密钥默认保存在 tpm-keys.csv 文件中。将采用类似的启用工作流程来准备 ESXi 主机,但不是生成新的主机加密密钥,而是直接导入先前创建的现有主机和虚拟机加密密钥。
Prepare-VMHostForEncryption
New-InitialVMHostKey -Operation IMPORT -KeyName "host-key-1" -CSVTPMKeyFile tpm-keys.csv
New-VMTPMKey -Operation IMPORT -KeyName "windows-11-key" -CSVTPMKeyFile tpm-keys.csv
Get-VMHostTPMKeys
如果成功导入了密钥,现在就可以打开已分配了生成的虚拟机加密密钥的任何虚拟机!
文章评论