-
Notifications
You must be signed in to change notification settings - Fork 264
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initial support for creating confidential windows UtilityVMs #2388
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package hcsschema | ||
|
||
type FirmwareFile struct { | ||
Parameters []byte `json:"Parameters,omitempty"` | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
//go:build windows | ||
|
||
package main | ||
|
||
import ( | ||
"context" | ||
"os" | ||
|
||
"github.com/containerd/console" | ||
"github.com/urfave/cli" | ||
|
||
"github.com/Microsoft/hcsshim/internal/cmd" | ||
"github.com/Microsoft/hcsshim/internal/log" | ||
"github.com/Microsoft/hcsshim/internal/uvm" | ||
) | ||
|
||
const ( | ||
confidentialArgName = "confidential" | ||
vmgsFilePathArgName = "vmgs-path" | ||
disableSBArgName = "disable-secure-boot" | ||
isolationTypeArgName = "isolation-type" | ||
) | ||
|
||
var ( | ||
cwcowBootVHD string | ||
cwcowEFIVHD string | ||
cwcowScratchVHD string | ||
cwcowEnableConfidential bool | ||
cwcowVMGSPath string | ||
cwcowDisableSecureBoot bool | ||
cwcowIsolationMode string | ||
) | ||
|
||
var cwcowCommand = cli.Command{ | ||
Name: "cwcow", | ||
Usage: "boot a confidential WCOW UVM", | ||
Flags: []cli.Flag{ | ||
cli.StringFlag{ | ||
Name: "exec", | ||
Usage: "Command to execute in the UVM.", | ||
Destination: &wcowCommandLine, | ||
}, | ||
cli.BoolFlag{ | ||
Name: "tty,t", | ||
Usage: "create the process in the UVM with a TTY enabled", | ||
Destination: &wcowUseTerminal, | ||
}, | ||
cli.StringFlag{ | ||
Name: "efi-vhd", | ||
Usage: "VHD at the provided path MUST have the EFI boot partition and be properly formatted for UEFI boot.", | ||
Destination: &cwcowEFIVHD, | ||
Required: true, | ||
}, | ||
cli.StringFlag{ | ||
Name: "boot-cim-vhd", | ||
Usage: "A VHD containing the block CIM that contains the OS files.", | ||
Destination: &cwcowBootVHD, | ||
Required: true, | ||
}, | ||
cli.StringFlag{ | ||
Name: "scratch-vhd", | ||
Usage: "A scratch VHD for the UVM", | ||
Destination: &cwcowScratchVHD, | ||
Required: true, | ||
}, | ||
cli.StringFlag{ | ||
Name: vmgsFilePathArgName, | ||
Usage: "VMGS file path (only applies when confidential mode is enabled). This option is only applicable in confidential mode.", | ||
Destination: &cwcowVMGSPath, | ||
Required: true, | ||
}, | ||
cli.BoolFlag{ | ||
Name: disableSBArgName, | ||
Usage: "Disables Secure Boot when running the UVM in confidential mode. This option is only applicable in confidential mode.", | ||
Destination: &cwcowDisableSecureBoot, | ||
}, | ||
cli.StringFlag{ | ||
Name: isolationTypeArgName, | ||
Usage: "VM Isolation type (one of Disabled, GuestStateOnly, VirtualizationBasedSecurity, SecureNestedPaging or TrustDomain). Applicable only when using the confidential mode. This option is only applicable in confidential mode.", | ||
Destination: &cwcowIsolationMode, | ||
Required: true, | ||
}, | ||
}, | ||
Action: func(c *cli.Context) error { | ||
runMany(c, func(id string) error { | ||
options := uvm.NewDefaultOptionsWCOW(id, "") | ||
options.ProcessorCount = 2 | ||
options.MemorySizeInMB = 2048 | ||
options.AllowOvercommit = false | ||
options.EnableDeferredCommit = false | ||
options.DumpDirectoryPath = "C:\\crashdumps" | ||
|
||
// confidential specific options | ||
options.SecurityPolicyEnabled = true | ||
options.DisableSecureBoot = cwcowDisableSecureBoot | ||
options.GuestStateFilePath = cwcowVMGSPath | ||
options.IsolationType = cwcowIsolationMode | ||
// always enable graphics console with uvmboot - helps with testing/debugging | ||
options.EnableGraphicsConsole = true | ||
options.BootFiles = &uvm.WCOWBootFiles{ | ||
BootType: uvm.BlockCIMBoot, | ||
BlockCIMFiles: &uvm.BlockCIMBootFiles{ | ||
BootCIMVHDPath: cwcowBootVHD, | ||
EFIVHDPath: cwcowEFIVHD, | ||
ScratchVHDPath: cwcowScratchVHD, | ||
}, | ||
} | ||
setGlobalOptions(c, options.Options) | ||
tempDir, err := os.MkdirTemp("", "uvmboot") | ||
if err != nil { | ||
return err | ||
} | ||
defer os.RemoveAll(tempDir) | ||
|
||
vm, err := uvm.CreateWCOW(context.TODO(), options) | ||
if err != nil { | ||
return err | ||
} | ||
defer vm.Close() | ||
if err := vm.Start(context.TODO()); err != nil { | ||
return err | ||
} | ||
if wcowCommandLine != "" { | ||
cmd := cmd.Command(vm, "cmd.exe", "/c", wcowCommandLine) | ||
cmd.Spec.User.Username = `NT AUTHORITY\SYSTEM` | ||
cmd.Log = log.L.Dup() | ||
if wcowUseTerminal { | ||
cmd.Spec.Terminal = true | ||
cmd.Stdin = os.Stdin | ||
cmd.Stdout = os.Stdout | ||
con, err := console.ConsoleFromFile(os.Stdin) | ||
if err == nil { | ||
err = con.SetRaw() | ||
if err != nil { | ||
return err | ||
} | ||
defer func() { | ||
_ = con.Reset() | ||
}() | ||
} | ||
} else { | ||
cmd.Stdout = os.Stdout | ||
cmd.Stderr = os.Stdout | ||
} | ||
err = cmd.Run() | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
_ = vm.Terminate(context.TODO()) | ||
_ = vm.Wait() | ||
return vm.ExitError() | ||
}) | ||
return nil | ||
}, | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -122,6 +122,28 @@ | |||||||||||||
NumaProcessorCounts []uint32 | ||||||||||||||
// NumaMemoryBlocksCounts are the number of memory blocks per vNUMA node. | ||||||||||||||
NumaMemoryBlocksCounts []uint64 | ||||||||||||||
|
||||||||||||||
EnableGraphicsConsole bool // If true, enable a graphics console for the utility VM | ||||||||||||||
ConsolePipe string // The named pipe path to use for the serial console (COM1). eg \\.\pipe\vmpipe | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
func verifyWCOWBootFiles(bootFiles *WCOWBootFiles) error { | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe make this a method and move it to
Suggested change
|
||||||||||||||
if bootFiles.BootType == VmbFSBoot { | ||||||||||||||
if bootFiles.VmbFSFiles == nil { | ||||||||||||||
return fmt.Errorf("VmbFS boot files is empty") | ||||||||||||||
} else if bootFiles.BlockCIMFiles != nil { | ||||||||||||||
return fmt.Errorf("confidential boot files should be empty") | ||||||||||||||
} | ||||||||||||||
} else if bootFiles.BootType == BlockCIMBoot { | ||||||||||||||
if bootFiles.BlockCIMFiles == nil { | ||||||||||||||
return fmt.Errorf("Confidential boot files is empty") | ||||||||||||||
} else if bootFiles.VmbFSFiles != nil { | ||||||||||||||
return fmt.Errorf("VmbFS boot files should be empty") | ||||||||||||||
} | ||||||||||||||
} else { | ||||||||||||||
return fmt.Errorf("invalid boot type specified") | ||||||||||||||
} | ||||||||||||||
return nil | ||||||||||||||
Comment on lines
+143
to
+146
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
might be cleaner overall as: switch bootFiles.BootType {
case VmbFSBoot:
// ...
case BlockCIMBoot:
// ...
default:
}
return fmt.Errorf("invalid boot type specified: %s", bootFiles.BootType) |
||||||||||||||
} | ||||||||||||||
|
||||||||||||||
// Verifies that the final UVM options are correct and supported. | ||||||||||||||
|
@@ -156,6 +178,12 @@ | |||||||||||||
if opts.SCSIControllerCount != 1 { | ||||||||||||||
return errors.New("exactly 1 SCSI controller is required for WCOW") | ||||||||||||||
} | ||||||||||||||
if err := verifyWCOWBootFiles(opts.BootFiles); err != nil { | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. may also want to have a |
||||||||||||||
return err | ||||||||||||||
} | ||||||||||||||
if opts.SecurityPolicyEnabled && opts.GuestStateFilePath == "" { | ||||||||||||||
return fmt.Errorf("GuestStateFilePath must be provided when enabling security policy") | ||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
return nil | ||||||||||||||
} | ||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you add a note saying this is experimental?