Skip to content

Commit 5a8ff77

Browse files
author
William Lam
committed
Functions to configure vTPM on standalone ESXi host
1 parent 9a069d5 commit 5a8ff77

File tree

1 file changed

+360
-0
lines changed

1 file changed

+360
-0
lines changed
Lines changed: 360 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,360 @@
1+
# Author: William Lam
2+
# Description: PowerCLI functions to configure host encryption for a standanlone ESXi host to support vTPM without vCenter Server
3+
4+
Function New-256BitKey {
5+
<#
6+
.NOTES
7+
===========================================================================
8+
Created by: William Lam
9+
Organization: VMware
10+
Blog: www.williamlam.com
11+
Twitter: @lamw
12+
===========================================================================
13+
.DESCRIPTION
14+
This function returns randomly generated 256 bit key encoded using base64
15+
.EXAMPLE
16+
New-256BitKey
17+
#>
18+
# Generate 256 bit key
19+
# Thank you ChatGPT for this code
20+
$randomKey = [byte[]]::new(32)
21+
$rand = [System.Security.Cryptography.RandomNumberGenerator]::Create()
22+
$rand.GetBytes($randomKey)
23+
24+
# Encode the key using Base64
25+
return [Convert]::ToBase64String($randomKey)
26+
}
27+
28+
Function Prepare-VMHostForEncryption {
29+
<#
30+
.NOTES
31+
===========================================================================
32+
Created by: William Lam
33+
Organization: VMware
34+
Blog: www.williamlam.com
35+
Twitter: @lamw
36+
===========================================================================
37+
.DESCRIPTION
38+
This function prepares the ESXi host for encryption
39+
.EXAMPLE
40+
Prepare-VMHostForEncryption
41+
#>
42+
$cm = Get-View $global:DefaultVIServer.ExtensionData.Content.CryptoManager
43+
44+
$cryptoState = (Get-VMHost).ExtensionData.Runtime.CryptoState
45+
46+
if($cryptoState -eq "incapable") {
47+
Write-Host -ForegroundColor Yellow "`nPreparing ESXi Host for encryption ..."
48+
$cm.CryptoManagerHostPrepare()
49+
Write-Host -ForegroundColor Green "Successfully prepared ESXi Host for encryption ...`n"
50+
} else {
51+
Write-Host "`nESXi Host has already been prepared for encryption ...`n"
52+
}
53+
}
54+
55+
Function New-InitialVMHostKey {
56+
<#
57+
.NOTES
58+
===========================================================================
59+
Created by: William Lam
60+
Organization: VMware
61+
Blog: www.williamlam.com
62+
Twitter: @lamw
63+
===========================================================================
64+
.DESCRIPTION
65+
This function creates and/or ipmorts host key
66+
.PARAMETER Operation
67+
CREATE or IMPORT
68+
.PARAMETER KeyName
69+
Name of the VM Key
70+
.PARAMETER CSVTPMKeyFile
71+
Name of CSV file to save TPM keys (Default: tpm-keys.csv)
72+
.EXAMPLE
73+
# Request new VM Key
74+
New-InitialVMHostKey -Operation CREATE -KeyName "host-key-1"
75+
.EXAMPLE
76+
# Imports an existing VM Key
77+
New-InitialVMHostKey -Operation IMPORT -KeyName "host-key-1" -CSVTPMKeyFile tpm-keys.csv
78+
79+
#>
80+
param(
81+
[Parameter(Mandatory=$true)][ValidateSet("CREATE","IMPORT")][string]$Operation,
82+
[Parameter(Mandatory=$true)][String]$KeyName,
83+
[Parameter(Mandatory=$false)][String]$CSVTPMKeyFile="tpm-keys.csv"
84+
)
85+
86+
$cryptoState = (Get-VMHost).ExtensionData.Runtime.CryptoState
87+
88+
if($cryptoState -eq "safe") {
89+
Write-Host -ForegroundColor Red "`nESXi host has already been configured with initial host key ...`n"
90+
break
91+
}
92+
93+
if($cryptoState -ne "prepared") {
94+
Write-Host -ForegroundColor Red "`nESXi host has not been prepared for encryption ...`n"
95+
break
96+
}
97+
98+
$cm = Get-View $global:DefaultVIServer.ExtensionData.Content.CryptoManager
99+
100+
# Create or import initial host key
101+
if($Operation -eq "CREATE") {
102+
Write-Host -ForegroundColor Yellow "Generating random 256 bit host key ..."
103+
$hostBase64Key = New-256BitKey
104+
$keyAlgorithim = "AES-256"
105+
} else {
106+
$csvfile = Import-Csv $CSVTPMKeyFile
107+
foreach ($line in $csvfile) {
108+
if($line.KEYID -eq $KeyName -and $line.TYPE -eq "HOST") {
109+
Write-Host -ForegroundColor Yellow "Importing existing host key from $CSVTPMKeyFile ..."
110+
$hostBase64Key = $line.DATA
111+
$keyAlgorithim = $line.ALGORITHIM
112+
break
113+
}
114+
}
115+
}
116+
117+
if($hostBase64Key -eq $null) {
118+
Write-Host -ForegroundColor Red "Failed to find host key ${KeyName} ...`n"
119+
break
120+
}
121+
122+
$hostKeyId = New-Object VMware.Vim.CryptoKeyId
123+
$hostKeyId.keyId = $KeyName
124+
125+
$hostKeySpec = New-Object VMware.Vim.CryptoKeyPlain
126+
$hostKeySpec.KeyId = $hostKeyId
127+
$hostKeySpec.Algorithm = $keyAlgorithim
128+
$hostKeySpec.KeyData = $hostBase64Key
129+
130+
Write-Host -ForegroundColor Yellow "Adding ESXi Host Key ${KeyName} ..."
131+
try {
132+
$cm.CryptoManagerHostEnable($hostKeySpec)
133+
} catch {
134+
Write-Host -ForegroundColor Red "Failed to add host key ${KeyName} ...`n"
135+
break
136+
}
137+
138+
# Automatically backup host key to CSV file
139+
if($Operation -eq "CREATE") {
140+
if (Test-Path -Path $CSVTPMKeyFile -PathType Leaf) {
141+
Write-Host -ForegroundColor Yellow "ESXi TPM Keys file $CSVTPMKeyFile exists, please use import operation"
142+
} else {
143+
$newcsv = {} | Select "KEYID","ALGORITHIM","TYPE","DATA" | Export-Csv $CSVTPMKeyFile
144+
$csvfile = Import-Csv $CSVTPMKeyFile
145+
$csvfile.KEYID = $KeyName
146+
$csvfile.ALGORITHIM = $keyAlgorithim
147+
$csvfile.TYPE = "HOST"
148+
$csvfile.DATA = $hostBase64Key
149+
Write-Host -ForegroundColor Yellow "Exporting ${KeyName} to $CSVTPMKeyFile ..."
150+
$csvfile | Export-CSV -Path $CSVTPMKeyFile
151+
}
152+
}
153+
Write-Host -ForegroundColor Green "Successfully added initial host encryption key ${KeyName} ...`n"
154+
}
155+
156+
Function New-VMTPMKey {
157+
<#
158+
.NOTES
159+
===========================================================================
160+
Created by: William Lam
161+
Organization: VMware
162+
Blog: www.williamlam.com
163+
Twitter: @lamw
164+
===========================================================================
165+
.DESCRIPTION
166+
This function creates and/or ipmorts Host key
167+
.PARAMETER Operation
168+
CREATE or IMPORT
169+
.PARAMETER KeyName
170+
Name of the VM Key
171+
.PARAMETER CSVTPMKeyFile
172+
Name of CSV file to save TPM keys (Default: tpm-keys.csv)
173+
.EXAMPLE
174+
# Request new Host Key
175+
New-VMTPMKey -Operation CREATE -KeyName "windows-11-key"
176+
.EXAMPLE
177+
# Imports an existing Host Key
178+
New-VMTPMKey -Operation IMPORT -KeyName "windows-11-key" -CSVTPMKeyFile tpm-keys.csv
179+
180+
#>
181+
param(
182+
[Parameter(Mandatory=$true)][ValidateSet("CREATE","IMPORT")][string]$Operation,
183+
[Parameter(Mandatory=$true)][String]$KeyName,
184+
[Parameter(Mandatory=$false)][String]$CSVTPMKeyFile="tpm-keys.csv"
185+
)
186+
187+
$cm = Get-View $global:DefaultVIServer.ExtensionData.Content.CryptoManager
188+
189+
# Ensure ESXi host encryption is enabled
190+
if($cm.Enabled) {
191+
# Create or import VM key
192+
if($Operation -eq "CREATE") {
193+
Write-Host -ForegroundColor Yellow "Generating random 256 bit VM key ..."
194+
$vmBase64Key = New-256BitKey
195+
$keyAlgorithim = "AES-256"
196+
} else {
197+
$csvfile = Import-Csv $CSVTPMKeyFile
198+
foreach ($line in $csvfile) {
199+
if($line.KEYID -eq $KeyName -and $line.TYPE -eq "VM") {
200+
Write-Host -ForegroundColor Yellow "Importing existing VM key from $CSVTPMKeyFile ..."
201+
$vmBase64Key = $line.DATA
202+
$keyAlgorithim = $line.ALGORITHIM
203+
break
204+
}
205+
}
206+
}
207+
208+
if($vmBase64Key -eq $null) {
209+
Write-Host -ForegroundColor Red "Failed to find VM key ${KeyName} ...`n"
210+
break
211+
}
212+
213+
$vmKeyId = New-Object VMware.Vim.CryptoKeyId
214+
$vmKeyId.keyId = $KeyName
215+
216+
$vmKeySpec = New-Object VMware.Vim.CryptoKeyPlain
217+
$vmKeySpec.KeyId = $vmKeyId
218+
$vmKeySpec.Algorithm = $keyAlgorithim
219+
$vmKeySpec.KeyData = $vmBase64Key
220+
221+
Write-Host -ForegroundColor Yellow "Adding VM key ${KeyName} ..."
222+
try {
223+
$cm.AddKey($vmKeySpec)
224+
} catch {
225+
Write-Host -ForegroundColor Red "Failed to add VM key ${KeyName} ...`n"
226+
break
227+
}
228+
229+
# Automatically backup VM key to CSV file
230+
if($Operation -eq "CREATE") {
231+
if (Test-Path -Path $CSVTPMKeyFile -PathType Leaf) {
232+
$tmp = [PSCustomObject] [ordered]@{
233+
KEYID = $KeyName;
234+
ALGORITHIM = $keyAlgorithim;
235+
TYPE = "VM";
236+
DATA = $vmBase64Key
237+
}
238+
Write-Host -ForegroundColor Yellow "Exporting ${KeyName} to $CSVTPMKeyFile ..."
239+
$tmp | Export-CSV -Append -NoTypeInformation -Path $CSVTPMKeyFile
240+
} else {
241+
Write-Error "Unable to find $CSVTPMKeyFile ..."
242+
}
243+
}
244+
Write-Host -ForegroundColor Green "Successfully added VM encryption key ${KeyName} ...`n"
245+
} else {
246+
Write-Host -ForegroundColor Red "`nESXi host has not been prepared for encryption ...`n"
247+
}
248+
}
249+
250+
Function Remove-VMTPMKey {
251+
<#
252+
.NOTES
253+
===========================================================================
254+
Created by: William Lam
255+
Organization: VMware
256+
Blog: www.williamlam.com
257+
Twitter: @lamw
258+
===========================================================================
259+
.DESCRIPTION
260+
This function removes an existing VM key
261+
.PARAMETER KeyName
262+
Name of the VM Key
263+
.PARAMETER Force
264+
Force remove VM Key
265+
.EXAMPLE
266+
# Remove VM key
267+
Remove-VMTPMKey -KeyName "windows-11-key"
268+
.EXAMPLE
269+
# Forcefully remove VM key
270+
Remove-VMTPMKey -KeyName "windows-11-key" -Force $true
271+
#>
272+
param(
273+
[Parameter(Mandatory=$true)][String]$KeyName,
274+
[Parameter(Mandatory=$false)][Boolean]$Force=$false
275+
)
276+
277+
$cm = Get-View $global:DefaultVIServer.ExtensionData.Content.CryptoManager
278+
279+
$key = $cm.ListKeys($null) | where {$_.KeyId -eq $KeyName}
280+
Write-Host -ForegroundColor Yellow "Removing VM key ${KeyName} ..."
281+
try {
282+
$cm.RemoveKey($key,$Force)
283+
} catch {
284+
Write-Host -ForegroundColor Red "Failed to remove VM key, maybe in use or use -Force option to forcefully remove ...`n"
285+
break
286+
}
287+
Write-Host -ForegroundColor Green "Successfully removed VM key ...`n"
288+
}
289+
290+
Function Get-VMHostTPMKeys {
291+
<#
292+
.NOTES
293+
===========================================================================
294+
Created by: William Lam
295+
Organization: VMware
296+
Blog: www.williamlam.com
297+
Twitter: @lamw
298+
===========================================================================
299+
.DESCRIPTION
300+
This function returns all Host/VM keys
301+
.EXAMPLE
302+
Get-VMHostTPMKeys
303+
#>
304+
305+
$cm = Get-View $global:DefaultVIServer.ExtensionData.Content.CryptoManager
306+
307+
if($cm.Enabled) {
308+
$cm.ListKeys($null)
309+
} else {
310+
Write-Host -ForegroundColor Red "`nESXi host has not been prepared for encryption or does not contain initial host key ...`n"
311+
}
312+
}
313+
Function Reconfigure-VMWithvTPM {
314+
<#
315+
.NOTES
316+
===========================================================================
317+
Created by: William Lam
318+
Organization: VMware
319+
Blog: www.williamlam.com
320+
Twitter: @lamw
321+
===========================================================================
322+
.DESCRIPTION
323+
This function adds vTPM to existing VM and applies an existing VM key for encryption
324+
.PARAMETER KeyName
325+
Name of the VM Key
326+
.PARAMETER VMName
327+
Name of the VM to add vTPM
328+
.EXAMPLE
329+
Reconfigure-VMWithvTPM -KeyName "windows-11-key" -VMName "Windows-11"
330+
#>
331+
param(
332+
[Parameter(Mandatory=$true)][String]$KeyName,
333+
[Parameter(Mandatory=$true)][String]$VMName
334+
)
335+
336+
$vm = Get-VM $VMName
337+
338+
$cm = Get-View $global:DefaultVIServer.ExtensionData.Content.CryptoManager
339+
340+
# Retrieve VM key
341+
$cryptoSpec = New-Object VMware.Vim.CryptoSpecEncrypt
342+
$cryptoSpec.CryptoKeyId = $cm.ListKeys($null) | where {$_.KeyId -eq $KeyName}
343+
344+
$spec = New-Object VMware.Vim.VirtualMachineConfigSpec
345+
346+
# Set VM encryption key
347+
$spec.Crypto = $cryptoSpec
348+
349+
# Add TPM device
350+
$spec.deviceChange = New-Object VMware.Vim.VirtualDeviceConfigSpec
351+
$spec.deviceChange[0].operation = 'add'
352+
$spec.deviceChange[0].device = New-Object VMware.Vim.VirtualTPM
353+
$spec.DeviceChange[0].Device.Key = 11000
354+
355+
# Reconfigure VM
356+
Write-Host -ForegroundColor Yellow "Adding vTPM to ${VMName} using encryption key ${KeyName} ..."
357+
$task = $vm.ExtensionData.ReconfigVM_Task($spec)
358+
$task1 = Get-Task -Id ("Task-$($task.value)")
359+
$task1 | Wait-Task
360+
}

0 commit comments

Comments
 (0)