Support for starting confidential containers - #2495
Conversation
f10bd37 to
bc466fc
Compare
|
@KenGordon commit d324057 in this PR handles passing policy through host data, in case you want to review the change. |
We already added support for starting confidential UVMs. This commit adds support for running confidential pods (via containerd) by including a non-empty security policy in the pod config annotations. The files (VHDs & guest statef file) required for starting such a confidential UVM MUST be available in a directory named `WindowsBootFiles/confidential` that is located next to the shim binary. Since some LCOW & WCOW annotations have conflicting/confusing names, existing LCOW annotation vars are renamed to have the "LCOW" prefix. Signed-off-by: Amit Barve <ambarve@microsoft.com>
Adds support for mounting block CIM based container image layers inside the UVM. (ResourceTypeWCOWBlockCims is only supported by sidecar GCS at the moment. Inbox GCS will add this support soon.) Signed-off-by: Amit Barve <ambarve@microsoft.com>
When the policy digest is included in the host data field of the UVM config, the SNP hardware is able to directly access that and include that in the attestation report. Signed-off-by: Amit Barve <ambarve@microsoft.com>
EFI VHDs should always be attached as read-only by default to block UVMs from writing to it and corrupting its contents. A new annotation is added to allow attaching EFI VHDs in writable mode when debugging boot failures and such. When this annotation is included a copy of the EFI VHD is made next to the scratch VHD. This is based on the assumption that generally the scratch of the UVM would be stored in its own snapshot directory so adding another VHD in there shouldn't be a problem. It should get cleaned up when the snapshot is removed. This commit also adds the code to always grant VM group access to the VHDs and guest state files to avoid access denied failures. Signed-off-by: Amit Barve <ambarve@microsoft.com>
Signed-off-by: Amit Barve <ambarve@microsoft.com>
Done. Looks good, I did mention maybe taking the comment wrt the purpose of the host data. |
|
Sorry, pressed the wrong button when commenting. Opps. |
KenGordon
left a comment
There was a problem hiding this comment.
I have added some comments about changes but there is nothing I would say should get in the way of merging it so we can get the rest merged and the demo building.
|
|
||
| // handleWCOWSecurityPolicy handles parsing confidential pods related options and setting | ||
| // implied options from the results for WCOW. | ||
| func handleWCOWSecurityPolicy(ctx context.Context, a map[string]string, wopts *uvm.OptionsWCOW) error { |
There was a problem hiding this comment.
You should take a look at handleSecurityPolicy in the LCOW path. There is a flag:
// allow actual isolated boot etc to be ignored if we have no hardware. Required for dev
// this is not a security issue as the attestation will fail without a genuine report
noSecurityHardware := ParseAnnotationsBool(ctx, a, annotations.NoSecurityHardware, false)
and if it is set then SecurityPolicyEnabled is false. This there CAN BE a opts.SecurityPolicy when SecurityPolicyEnabled is false. That opts.SecurityPolicy will be sent to the UVM by SetConfidentialUVMOptions at the first opportunity (see
func (uvm *UtilityVM) Start(ctx context.Context) (err error) {)
The point of all this complexity is to allow us to run the Confidential stack on non confidential hardware, as nobody has a laptop/desktop that is SNP enabled. You have a choice about how the boot behaves. In the LCOW case the non SNP "confidential" mode boots exactly like regular ContainerPlat, so the hcs json is the same. In a WCOW version of this you might or might not choose to use the full new-style boot. I suggest you do use that boot and that everything is identical except that the PSP driver will tell the guest agent there is no PSP. This lets us test/experiment with the whole stack without SNP hardware or VM.
There was a problem hiding this comment.
BTW, yes the SecurityPolicyEnabled flag would be better named something like EncryptedHardwareEnabled or something like it.
There was a problem hiding this comment.
I see there is another flag to disable/enable secure boot. We ought to double check that we get a different measurement when it is disabled.
There was a problem hiding this comment.
In the current CWCOW setup, if you use the WCOWIsolationType annotation to set it to use "VBS" isolation and use the WCOWGuestStateFile annotation to pass the appropriate VMGS file for VBS (instead of the default SNP one), it will actually let you boot the confidential pod on a non-SNP hardware. That's how I have been testing it thus far. Would that be enough for us?
Yes if you disable secure boot but are still booting with a VBS or SNP VMGS, it does fail to boot. So we won't even get to the measurement part.
There was a problem hiding this comment.
Is it easy to update a binary inside the UVM with this scheme? Or will secure boot enforce code integrity and insist on proper signing (or signing that is hard to do on a local build).
| return fmt.Errorf("allow overcommit MUST be false for confidential pods") | ||
| } | ||
|
|
||
| wopts.SecurityPolicyEnforcer = ParseAnnotationsString(a, annotations.WCOWSecurityPolicyEnforcer, wopts.SecurityPolicyEnforcer) |
There was a problem hiding this comment.
TBC next week when Tingmao is back but you probably do not need this enforcer type now. It used to be used to switch between json and rego policies and was just a hangover but Tingmao touched that last and can say if this can be ignored.
|
|
||
| // GuestStateFile specifies the path of the vmgs file to use if required. Only applies in SNP mode. | ||
| GuestStateFile = "io.microsoft.virtualmachine.lcow.gueststatefile" | ||
| // LCOWGuestStateFile specifies the path of the vmgs file to use if required. Only applies in SNP mode. |
There was a problem hiding this comment.
For purely internal annotations, eg lcow.gueststatefile, where we control the client or where no client ever sets it (TBC with ACI) then I suggest not having wcow.gueststatefile and lcow.gueststatefile but just the one for both. Otherwise there is quite a bit of unnecessary duplication. Some of our tests do have pod.json files that set these explicitly but I can fix those to use a shared one. Again, this is not needed immediately.
There was a problem hiding this comment.
Yeah, I will handle this as a part of a separate PR to reduce churn on this PR.
| } | ||
| return nil | ||
|
|
||
| case guestresource.ResourceTypeCWCOWCombinedLayers: |
There was a problem hiding this comment.
@ambarve As discussed, this was added intentionally. It is just logging in this commit, but my changes need containerID and is being used for enforcement. Please revert this commit.
containerID is required for all gcs requests in confidential mode. Most of the requests already include it but CombineLayers and MountBlockCIM request types don't. This commit adds that to these request types. Signed-off-by: Amit Barve <ambarve@microsoft.com>
| wcowBlockCimMounts := modifyGuestSettingsRequest.Settings.(*guestresource.WCOWBlockCIMMounts) | ||
| if modifyGuestSettingsRequest.RequestType == guestrequest.RequestTypeRemove { | ||
| return fmt.Errorf("not implemented") | ||
| } |
There was a problem hiding this comment.
@ambarve Thanks for the changes. What about RequestTypeAdd? Is it because the default Request type is Add? I understood from our discussion that you would add a no-op (for now) for both types.
There was a problem hiding this comment.
The types are either Add or Remove. We do want the current handling to happen for Add. When I add the implementation for Remove (in a separate PR), I will restructure the code a bit better for to have a switch case on the type of request.
There was a problem hiding this comment.
Ok. I think you want the current handling only on RequestTypeAdd type and not on RequestTypeRemove. So a switch case is necessary - a separate PR sounds good.
| // It may be an error to have a security policy but not expose it to the | ||
| // container as in that case it can never be checked as correct by a verifier. | ||
| if oci.ParseAnnotationsBool(ctx, settings.OCISpecification.Annotations, annotations.UVMSecurityPolicyEnv, true) { | ||
| if oci.ParseAnnotationsBool(ctx, settings.OCISpecification.Annotations, annotations.LCOWSecurityPolicyEnv, true) { |
There was a problem hiding this comment.
There will need to be code exactly like this in the WCOW case too. As I mentioned elsewhere, this is likely a local scope annotation and we should have the same for both and not have duplicate code.
This PR adds the support for running confidential UVMs/Pods and then running containers inside such pods. It also brings in some additional fixes related to confidential pods.
Support for starting confidential pods
This commit allows running confidential pods/UtilityVMs by including a non-empty security
policy in the pod config annotations. The files (VHDs & guest statef file) required for
starting such a confidential UVM MUST be available in a directory named
WindowsBootFiles/confidentialthat is located next to the shim binary.Support for starting confidential containers
Adds support for mounting block CIM based container image layers inside the UVM.
(ResourceTypeWCOWBlockCims is only supported by sidecar GCS at the moment. Inbox GCS will
add this support soon.)
Include policy digest in the host data for confidential UVM
When the policy digest is included in the host data field of the UVM config, the SNP
hardware is able to directly access that and include that in the attestation report.
Attach EFI VHD in read-only mode by default
EFI VHDs should always be attached as read-only by default to block UVMs from writing to
it and corrupting its contents. A new annotation is added to allow attaching EFI VHDs in
writable mode when debugging boot failures and such. When this annotation is included a
copy of the EFI VHD is made next to the scratch VHD. This is based on the assumption that
generally the scratch of the UVM would be stored in its own snapshot directory so adding
another VHD in there shouldn't be a problem. It should get cleaned up when the snapshot is
removed. This commit also adds the code to always grant VM group access to the VHDs and guest state
files to avoid access denied failures.
format container scratch in superfloppy mode