Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion internal/gcs-sidecar/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,8 @@ func (b *Bridge) modifySettings(req *request) (err error) {
err := b.hostState.securityOptions.SetConfidentialOptions(ctx,
securityPolicyRequest.EnforcerType,
securityPolicyRequest.EncodedSecurityPolicy,
securityPolicyRequest.EncodedUVMReference)
securityPolicyRequest.EncodedUVMReference,
securityPolicyRequest.EncodedUVMHashEnvelopeReference)
if err != nil {
return errors.Wrap(err, "Failed to set Confidentia UVM Options")
}
Expand Down
1 change: 1 addition & 0 deletions internal/gcs-sidecar/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ func NewHost(initialEnforcer securitypolicy.SecurityPolicyEnforcer, logWriter io
initialEnforcer,
false,
"",
"",
logWriter,
)
return &Host{
Expand Down
4 changes: 3 additions & 1 deletion internal/guest/runtime/hcsv2/uvm.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ func NewHost(rtime runtime.Runtime, vsock transport.Transport, initialEnforcer s
initialEnforcer,
false,
"",
"",
logWriter,
)
return &Host{
Expand Down Expand Up @@ -657,7 +658,8 @@ func (h *Host) modifyHostSettings(ctx context.Context, containerID string, req *
return h.securityOptions.SetConfidentialOptions(ctx,
r.EnforcerType,
r.EncodedSecurityPolicy,
r.EncodedUVMReference)
r.EncodedUVMReference,
r.EncodedUVMHashEnvelopeReference)
case guestresource.ResourceTypePolicyFragment:
r, ok := req.Settings.(*guestresource.SecurityPolicyFragment)
if !ok {
Expand Down
2 changes: 2 additions & 0 deletions internal/oci/uvm.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ func handleWCOWSecurityPolicy(ctx context.Context, a map[string]string, wopts *u
wopts.DisableSecureBoot = ParseAnnotationsBool(ctx, a, annotations.WCOWDisableSecureBoot, false)
wopts.GuestStateFilePath = ParseAnnotationsString(a, annotations.WCOWGuestStateFile, uvm.GetDefaultConfidentialVMGSPath())
wopts.UVMReferenceInfoFile = ParseAnnotationsString(a, annotations.WCOWReferenceInfoFile, uvm.GetDefaultReferenceInfoFilePath())
wopts.UVMHashEnvelopeReferenceInfoFile = ParseAnnotationsString(a, annotations.UVMHashEnvelopeReferenceInfoFile, uvm.GetDefaultHashEnvelopeReferenceInfoFilePath())
wopts.IsolationType = "SecureNestedPaging"
if noSecurityHardware := ParseAnnotationsBool(ctx, a, annotations.NoSecurityHardware, false); noSecurityHardware {
wopts.IsolationType = "GuestStateOnly"
Expand Down Expand Up @@ -376,6 +377,7 @@ func SpecToUVMCreateOpts(ctx context.Context, s *specs.Spec, id, owner string) (
lopts.SecurityPolicy = ParseAnnotationsString(s.Annotations, annotations.LCOWSecurityPolicy, lopts.SecurityPolicy)
lopts.SecurityPolicyEnforcer = ParseAnnotationsString(s.Annotations, annotations.LCOWSecurityPolicyEnforcer, lopts.SecurityPolicyEnforcer)
lopts.UVMReferenceInfoFile = ParseAnnotationsString(s.Annotations, annotations.LCOWReferenceInfoFile, lopts.UVMReferenceInfoFile)
lopts.UVMHashEnvelopeReferenceInfoFile = ParseAnnotationsString(s.Annotations, annotations.UVMHashEnvelopeReferenceInfoFile, lopts.UVMHashEnvelopeReferenceInfoFile)
lopts.KernelBootOptions = ParseAnnotationsString(s.Annotations, annotations.KernelBootOptions, lopts.KernelBootOptions)
lopts.DisableTimeSyncService = ParseAnnotationsBool(ctx, s.Annotations, annotations.DisableLCOWTimeSyncService, lopts.DisableTimeSyncService)
lopts.WritableOverlayDirs = ParseAnnotationsBool(ctx, s.Annotations, iannotations.WritableOverlayDirs, lopts.WritableOverlayDirs)
Expand Down
7 changes: 4 additions & 3 deletions internal/protocol/guestresource/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,10 @@ type SignalProcessOptionsWCOW struct {
// ConfidentialOptions is used to set various confidential container specific
// options.
type ConfidentialOptions struct {
EnforcerType string `json:"EnforcerType,omitempty"`
EncodedSecurityPolicy string `json:"EncodedSecurityPolicy,omitempty"`
EncodedUVMReference string `json:"EncodedUVMReference,omitempty"`
EnforcerType string `json:"EnforcerType,omitempty"`
EncodedSecurityPolicy string `json:"EncodedSecurityPolicy,omitempty"`
EncodedUVMReference string `json:"EncodedUVMReference,omitempty"`
EncodedUVMHashEnvelopeReference string `json:"EncodedUVMHashEnvelopeReference,omitempty"`
}

type SecurityPolicyFragment struct {
Expand Down
13 changes: 7 additions & 6 deletions internal/uvm/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,13 @@ type Options struct {
}

type ConfidentialCommonOptions struct {
GuestStateFilePath string // The vmgs file path to load
SecurityPolicy string // Optional security policy
SecurityPolicyEnabled bool // Set when there is a security policy to apply on actual SNP hardware, use this rathen than checking the string length
SecurityPolicyEnforcer string // Set which security policy enforcer to use (open door or rego). This allows for better fallback mechanic.
UVMReferenceInfoFile string // Path to the file that contains the signed UVM measurements
BundleDirectory string // This allows paths to be constructed relative to a per-VM bundle directory.
GuestStateFilePath string // The vmgs file path to load
SecurityPolicy string // Optional security policy
SecurityPolicyEnabled bool // Set when there is a security policy to apply on actual SNP hardware, use this rathen than checking the string length
SecurityPolicyEnforcer string // Set which security policy enforcer to use (open door or rego). This allows for better fallback mechanic.
UVMReferenceInfoFile string // Path to the file that contains the signed UVM measurements
UVMHashEnvelopeReferenceInfoFile string // Path to the file that contains the hash envelope signed UVM measurements
BundleDirectory string // This allows paths to be constructed relative to a per-VM bundle directory.
}

func verifyWCOWBootFiles(bootFiles *WCOWBootFiles) error {
Expand Down
9 changes: 7 additions & 2 deletions internal/uvm/create_lcow.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ const (
// reference UVM info, which can be made available to workload containers
// and can be used for validation purposes.
UVMReferenceInfoFile = "reference_info.cose"
// UVMHashEnvelopeReferenceInfoFile is the default file name for a COSE_Sign1
// hash envelope reference UVM info, which can be made available to workload
// containers and can be used for validation purposes.
UVMHashEnvelopeReferenceInfoFile = "hash_envelope_reference_info.cose"
)

type ConfidentialLCOWOptions struct {
Expand Down Expand Up @@ -162,8 +166,9 @@ func NewDefaultOptionsLCOW(id, owner string) *OptionsLCOW {
DisableTimeSyncService: false,
ConfidentialLCOWOptions: &ConfidentialLCOWOptions{
ConfidentialCommonOptions: &ConfidentialCommonOptions{
SecurityPolicyEnabled: false,
UVMReferenceInfoFile: UVMReferenceInfoFile,
SecurityPolicyEnabled: false,
UVMReferenceInfoFile: UVMReferenceInfoFile,
UVMHashEnvelopeReferenceInfoFile: UVMHashEnvelopeReferenceInfoFile,
},
},
}
Expand Down
4 changes: 4 additions & 0 deletions internal/uvm/create_wcow.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ func GetDefaultReferenceInfoFilePath() string {
return filepath.Join(defaultConfidentialWCOWOSBootFilesPath(), "reference_info.cose")
}

func GetDefaultHashEnvelopeReferenceInfoFilePath() string {
return filepath.Join(defaultConfidentialWCOWOSBootFilesPath(), "hash_envelope_reference_info.cose")
}

// NewDefaultOptionsWCOW creates the default options for a bootable version of
// WCOW. The caller `MUST` set the `BootFiles` on the returned value.
//
Expand Down
22 changes: 22 additions & 0 deletions internal/uvm/security_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,28 @@ func WithUVMReferenceInfo(referenceRoot string, referenceName string) Confidenti
}
}

// WithUVMHashEnvelopeReferenceInfo reads UVM hash envelope reference info file
// and base64 encodes the content before setting it for the resource. This is
// no-op if the `referenceName` is empty or the file doesn't exist.
func WithUVMHashEnvelopeReferenceInfo(referenceRoot string, referenceName string) ConfidentialUVMOpt {
return func(ctx context.Context, r *guestresource.ConfidentialOptions) error {
if referenceName == "" {
return nil
}
fullFilePath := filepath.Join(referenceRoot, referenceName)
encoded, err := base64EncodeFileContents(fullFilePath)
if err != nil {
if os.IsNotExist(err) {
log.G(ctx).WithField("filePath", fullFilePath).Debug("UVM hash envelope reference info file not found")
return nil
}
return fmt.Errorf("failed to read UVM hash envelope reference info file: %w", err)
}
r.EncodedUVMHashEnvelopeReference = encoded
return nil
}
}

// SetConfidentialUVMOptions sends information required to run the UVM on
// SNP hardware, e.g., security policy and enforcer type, signed UVM reference
// information, etc.
Expand Down
5 changes: 4 additions & 1 deletion internal/uvm/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -375,21 +375,24 @@ func (uvm *UtilityVM) Start(ctx context.Context) (err error) {
uvm.SCSIManager = mgr

if uvm.HasConfidentialPolicy() {
var policy, enforcer, referenceInfoFileRoot, referenceInfoFilePath string
var policy, enforcer, referenceInfoFileRoot, referenceInfoFilePath, hashEnvelopeReferenceInfoFilePath string
if uvm.OS() == "linux" {
policy = uvm.createOpts.(*OptionsLCOW).SecurityPolicy
enforcer = uvm.createOpts.(*OptionsLCOW).SecurityPolicyEnforcer
referenceInfoFilePath = uvm.createOpts.(*OptionsLCOW).UVMReferenceInfoFile
hashEnvelopeReferenceInfoFilePath = uvm.createOpts.(*OptionsLCOW).UVMHashEnvelopeReferenceInfoFile
referenceInfoFileRoot = vmutils.DefaultLCOWOSBootFilesPath()
} else if uvm.OS() == "windows" {
policy = uvm.createOpts.(*OptionsWCOW).SecurityPolicy
enforcer = uvm.createOpts.(*OptionsWCOW).SecurityPolicyEnforcer
referenceInfoFilePath = uvm.createOpts.(*OptionsWCOW).UVMReferenceInfoFile
hashEnvelopeReferenceInfoFilePath = uvm.createOpts.(*OptionsWCOW).UVMHashEnvelopeReferenceInfoFile
}
copts := []ConfidentialUVMOpt{
WithSecurityPolicy(policy),
WithSecurityPolicyEnforcer(enforcer),
WithUVMReferenceInfo(referenceInfoFileRoot, referenceInfoFilePath),
WithUVMHashEnvelopeReferenceInfo(referenceInfoFileRoot, hashEnvelopeReferenceInfoFilePath),
}
if err := uvm.SetConfidentialUVMOptions(ctx, copts...); err != nil {
return err
Expand Down
6 changes: 6 additions & 0 deletions pkg/annotations/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,12 @@ const (
VirtualMachineKernelDrivers = "io.microsoft.virtualmachine.kerneldrivers"
)

// Confidential UVM annotations.
const (
// UVMHashEnvelopeReferenceInfoFile specifies the filename of a hash envelope signed UVM reference file to be passed to UVM.
UVMHashEnvelopeReferenceInfoFile = "io.microsoft.virtualmachine.uvm-hash-envelope-reference-info-file"
)

// uVM CPU annotations.
const (
// CPUGroupID specifies the cpugroup ID that a UVM should be assigned to, if any.
Expand Down
9 changes: 5 additions & 4 deletions pkg/securitypolicy/securitypolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,11 @@ const (
const plan9Prefix = "plan9://"

const (
SecurityContextDirTemplate = "security-context-*"
PolicyFilename = "security-policy-base64"
HostAMDCertFilename = "host-amd-cert-base64"
ReferenceInfoFilename = "reference-info-base64"
SecurityContextDirTemplate = "security-context-*"
PolicyFilename = "security-policy-base64"
HostAMDCertFilename = "host-amd-cert-base64"
ReferenceInfoFilename = "reference-info-base64"
HashEnvelopeReferenceInfoFilename = "hash-envelope-reference-info-base64"
)

// PolicyConfig contains toml or JSON config for security policy.
Expand Down
32 changes: 20 additions & 12 deletions pkg/securitypolicy/securitypolicy_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,21 @@ import (

type SecurityOptions struct {
// state required for the security policy enforcement
PolicyEnforcer SecurityPolicyEnforcer
PolicyEnforcerSet bool
UvmReferenceInfo string
policyMutex sync.Mutex
logWriter io.Writer
PolicyEnforcer SecurityPolicyEnforcer
PolicyEnforcerSet bool
UvmReferenceInfo string
UvmHashEnvelopeReferenceInfo string
policyMutex sync.Mutex
logWriter io.Writer
}

func NewSecurityOptions(enforcer SecurityPolicyEnforcer, enforcerSet bool, uvmReferenceInfo string, logWriter io.Writer) *SecurityOptions {
func NewSecurityOptions(enforcer SecurityPolicyEnforcer, enforcerSet bool, uvmReferenceInfo string, uvmHashEnvelopeReferenceInfo string, logWriter io.Writer) *SecurityOptions {
return &SecurityOptions{
PolicyEnforcer: enforcer,
PolicyEnforcerSet: enforcerSet,
UvmReferenceInfo: uvmReferenceInfo,
logWriter: logWriter,
PolicyEnforcer: enforcer,
PolicyEnforcerSet: enforcerSet,
UvmReferenceInfo: uvmReferenceInfo,
UvmHashEnvelopeReferenceInfo: uvmHashEnvelopeReferenceInfo,
logWriter: logWriter,
}
}

Expand All @@ -46,7 +48,7 @@ func NewSecurityOptions(enforcer SecurityPolicyEnforcer, enforcerSet bool, uvmRe
// encoded security policy and signed UVM reference information The security
// policy and uvm reference information can be further presented to workload
// containers for validation and attestation purposes.
func (s *SecurityOptions) SetConfidentialOptions(ctx context.Context, enforcerType string, encodedSecurityPolicy string, encodedUVMReference string) error {
func (s *SecurityOptions) SetConfidentialOptions(ctx context.Context, enforcerType string, encodedSecurityPolicy string, encodedUVMReference string, encodedUVMHashEnvelopeReference string) error {
s.policyMutex.Lock()
defer s.policyMutex.Unlock()

Expand Down Expand Up @@ -95,6 +97,7 @@ func (s *SecurityOptions) SetConfidentialOptions(ctx context.Context, enforcerTy
s.PolicyEnforcer = p
s.PolicyEnforcerSet = true
s.UvmReferenceInfo = encodedUVMReference
s.UvmHashEnvelopeReferenceInfo = encodedUVMHashEnvelopeReference

return nil
}
Expand Down Expand Up @@ -191,7 +194,7 @@ func writeFileInDir(dir string, filename string, data []byte, perm os.FileMode)
func (s *SecurityOptions) WriteSecurityContextDir(spec *specs.Spec) error {
encodedPolicy := s.PolicyEnforcer.EncodedSecurityPolicy()
hostAMDCert := spec.Annotations[annotations.WCOWHostAMDCertificate]
if len(encodedPolicy) > 0 || len(hostAMDCert) > 0 || len(s.UvmReferenceInfo) > 0 {
if len(encodedPolicy) > 0 || len(hostAMDCert) > 0 || len(s.UvmReferenceInfo) > 0 || len(s.UvmHashEnvelopeReferenceInfo) > 0 {
// Use os.MkdirTemp to make sure that the directory is unique.
securityContextDir, err := os.MkdirTemp(spec.Root.Path, SecurityContextDirTemplate)
if err != nil {
Expand All @@ -212,6 +215,11 @@ func (s *SecurityOptions) WriteSecurityContextDir(spec *specs.Spec) error {
return fmt.Errorf("failed to write UVM reference info: %w", err)
}
}
if len(s.UvmHashEnvelopeReferenceInfo) > 0 {
if err := writeFileInDir(securityContextDir, HashEnvelopeReferenceInfoFilename, []byte(s.UvmHashEnvelopeReferenceInfo), 0777); err != nil {
return fmt.Errorf("failed to write UVM hash envelope reference info: %w", err)
}
}

if len(hostAMDCert) > 0 {
if err := writeFileInDir(securityContextDir, HostAMDCertFilename, []byte(hostAMDCert), 0777); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion test/gcs/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ func getHostErr(rt runtime.Runtime, tp transport.Transport) (*hcsv2.Host, error)
h := hcsv2.NewHost(rt, tp, &securitypolicy.OpenDoorSecurityPolicyEnforcer{}, os.Stdout)
if err := h.SecurityOptions().SetConfidentialOptions(
context.Background(),
"", "", "",
"", "", "", "",
); err != nil {
return nil, fmt.Errorf("could not set host security policy: %w", err)
}
Expand Down