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
18 changes: 14 additions & 4 deletions internal/gcs-sidecar/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -752,9 +752,14 @@ func (b *Bridge) modifySettings(req *request) (err error) {
log.G(ctx).Debugf("block CIM layer digest %s, path: %s\n", layerHashes[i], physicalDevPath)
}

// Top layer is the merged layer that will also be verified
hashesToVerify := layerHashes
mountedCim := []string{layerHashes[0]}
if len(layerHashes) > 1 {
hashesToVerify = layerHashes[1:]
}

err := b.hostState.securityOptions.PolicyEnforcer.EnforceVerifiedCIMsPolicy(req.ctx, containerID, hashesToVerify)
err := b.hostState.securityOptions.PolicyEnforcer.EnforceVerifiedCIMsPolicy(req.ctx, containerID, hashesToVerify, mountedCim)
if err != nil {
return errors.Wrap(err, "CIM mount is denied by policy")
}
Expand All @@ -763,7 +768,7 @@ func (b *Bridge) modifySettings(req *request) (err error) {
volGUID := wcowBlockCimMounts.VolumeGUID

// Cache hashes along with volGUID
b.hostState.blockCIMVolumeHashes[volGUID] = hashesToVerify
b.hostState.blockCIMVolumeHashes[volGUID] = layerHashes

// Store the containerID (associated with volGUID) to mark that hashes are verified for this container
if _, ok := b.hostState.blockCIMVolumeContainers[volGUID]; !ok {
Expand Down Expand Up @@ -886,10 +891,15 @@ func (b *Bridge) modifySettings(req *request) (err error) {
if _, seen := containers[containerID]; !seen {
// This is a container with similar layers as an existing container, hence already mounted.
// Call EnforceVerifiedCIMsPolicy on this new container.
log.G(ctx).Tracef("Verified CIM hashes for reused mount volume %s (container %s)", volGUID.String(), containerID)
if err := b.hostState.securityOptions.PolicyEnforcer.EnforceVerifiedCIMsPolicy(ctx, containerID, hashes); err != nil {
hashesToVerify := hashes
mountedCim := []string{hashes[0]}
if len(hashes) > 1 {
hashesToVerify = hashes[1:]
}
if err := b.hostState.securityOptions.PolicyEnforcer.EnforceVerifiedCIMsPolicy(ctx, containerID, hashesToVerify, mountedCim); err != nil {
return fmt.Errorf("CIM mount is denied by policy for this container: %w", err)
}
log.G(ctx).Tracef("Verified CIM hashes for reused mount volume %s (container %s)", volGUID.String(), containerID)
containers[containerID] = struct{}{}
}
}
Expand Down
1 change: 1 addition & 0 deletions pkg/securitypolicy/framework.rego
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ mount_cims := {"metadata": [addMatches], "allowed": true} {
containers := [container |
container := candidate_containers[_]
layerHashes_ok(container.layers)
input.mountedCim == container.mounted_cim
]

count(containers) > 0
Expand Down
11 changes: 8 additions & 3 deletions pkg/securitypolicy/rego_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1857,6 +1857,7 @@ func (c *securityPolicyWindowsContainer) toWindowsContainer() *WindowsContainer
Command: CommandArgs(stringArrayToStringMap(c.Command)),
EnvRules: envRuleArrayToEnvRules(c.EnvRules),
Layers: Layers(stringArrayToStringMap(c.Layers)),
MountedCim: c.MountedCim,
WorkingDir: c.WorkingDir,
ExecProcesses: execProcesses,
Signals: c.Signals,
Expand Down Expand Up @@ -2163,13 +2164,12 @@ func mountImageForWindowsContainer(policy *regoEnforcer, container *securityPoli
}

// Mount the CIMFS for the Windows container
err := policy.EnforceVerifiedCIMsPolicy(ctx, containerID, layerHashes)
// layerHashes are the individual layer hashes, mountedCim is the merged CIM from the policy
err := policy.EnforceVerifiedCIMsPolicy(ctx, containerID, layerHashes, container.MountedCim)
if err != nil {
return "", fmt.Errorf("error mounting CIMFS: %w", err)
}

//fmt.Printf("CIMFS mounted successfully for container %s with layers %v\n", containerID, layerHashes)

return containerID, nil
}

Expand Down Expand Up @@ -2306,6 +2306,11 @@ func generateConstraintsWindowsContainer(r *rand.Rand, minNumberOfLayers, maxNum
for i := 0; i < numLayers; i++ {
c.Layers = append(c.Layers, generateRootHash(r))
}
// For Windows, mounted_cim is the top/merged layer hash
// After reversal in the runtime, this becomes layerHashes[0]
if len(c.Layers) > 0 {
c.MountedCim = []string{c.Layers[len(c.Layers)-1]}
}
c.ExecProcesses = generateWindowsExecProcesses(r)
c.Signals = generateWindowsSignals(r)
c.AllowStdioAccess = randBool(r)
Expand Down
11 changes: 8 additions & 3 deletions pkg/securitypolicy/regopolicy_windows_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,9 +325,12 @@ func Test_Rego_EnforceVerifiedCIMSPolicy_Multiple_Instances_Same_Container(t *te

for i := 1; i <= containersToCreate; i++ {
arg := "command " + strconv.Itoa(i)
// layers = individual layer hashes, mounted_cim = merged CIM hash
// The runtime sends hashesToVerify=layers (reversed) and mountedCim=merged
c := &securityPolicyWindowsContainer{
Command: []string{arg},
Layers: []string{"1", "2"},
Command: []string{arg},
Layers: []string{"layer1", "layer2"},
MountedCim: []string{"merged_hash"},
}

constraints.containers = append(constraints.containers, c)
Expand All @@ -347,8 +350,10 @@ func Test_Rego_EnforceVerifiedCIMSPolicy_Multiple_Instances_Same_Container(t *te
layerHashes[len(container.Layers)-1-i] = layer
}

// The runtime sends individual layers as hashesToVerify
// and the merged CIM hash separately
id := testDataGenerator.uniqueContainerID()
err = policy.EnforceVerifiedCIMsPolicy(constraints.ctx, id, layerHashes)
err = policy.EnforceVerifiedCIMsPolicy(constraints.ctx, id, layerHashes, container.MountedCim)
if err != nil {
t.Fatalf("failed with %d containers", containersToCreate)
}
Expand Down
1 change: 1 addition & 0 deletions pkg/securitypolicy/securitypolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ type WindowsContainer struct {
Command CommandArgs `json:"command"`
EnvRules EnvRules `json:"env_rules"`
Layers Layers `json:"layers"`
MountedCim []string `json:"mounted_cim"`
WorkingDir string `json:"working_dir"`
ExecProcesses []WindowsExecProcessConfig `json:"-"`
Signals []guestrequest.SignalValueWCOW `json:"-"`
Expand Down
2 changes: 2 additions & 0 deletions pkg/securitypolicy/securitypolicy_internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ type securityPolicyWindowsContainer struct {
// order that the layers are overlayed is important and needs to be enforced
// as part of policy.
Layers []string `json:"layers"`
// The merged CIM hash for Windows containers
MountedCim []string `json:"mounted_cim"`
// WorkingDir is a path to container's working directory, which all the processes
// will default to.
WorkingDir string `json:"working_dir"`
Expand Down
5 changes: 5 additions & 0 deletions pkg/securitypolicy/securitypolicy_marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,10 @@ func writeLayers(builder *strings.Builder, layers []string, indent string) {
writeLine(builder, `%s"layers": %s,`, indent, (stringArray(layers)).marshalRego())
}

func writeMountedCim(builder *strings.Builder, mountedCim []string, indent string) {
writeLine(builder, `%s"mounted_cim": %s,`, indent, (stringArray(mountedCim)).marshalRego())
}

func writeCapabilities(builder *strings.Builder, capabilities *capabilitiesInternal, indent string) {
if capabilities != nil {
writeLine(builder, `%s"capabilities": {`, indent)
Expand Down Expand Up @@ -458,6 +462,7 @@ func writeWindowsContainer(builder *strings.Builder, container *securityPolicyWi
writeCommand(builder, container.Command, indent+indentUsing)
writeEnvRules(builder, container.EnvRules, indent+indentUsing)
writeLayers(builder, container.Layers, indent+indentUsing)
writeMountedCim(builder, container.MountedCim, indent+indentUsing)
writeWindowsExecProcesses(builder, container.ExecProcesses, indent+indentUsing)
writeWindowsSignals(builder, container.Signals, indent+indentUsing)
writeWindowsUser(builder, container.User, indent+indentUsing)
Expand Down
6 changes: 3 additions & 3 deletions pkg/securitypolicy/securitypolicyenforcer.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ type SecurityPolicyEnforcer interface {
EnforceScratchMountPolicy(ctx context.Context, scratchPath string, encrypted bool) (err error)
EnforceScratchUnmountPolicy(ctx context.Context, scratchPath string) (err error)
GetUserInfo(spec *oci.Process, rootPath string) (IDName, []IDName, string, error)
EnforceVerifiedCIMsPolicy(ctx context.Context, containerID string, layerHashes []string) (err error)
EnforceVerifiedCIMsPolicy(ctx context.Context, containerID string, layerHashes []string, mountedCim []string) (err error)
EnforceRegistryChangesPolicy(ctx context.Context, containerID string, registryValues interface{}) error
}

Expand Down Expand Up @@ -316,7 +316,7 @@ func (OpenDoorSecurityPolicyEnforcer) GetUserInfo(spec *oci.Process, rootPath st
return IDName{}, nil, "", nil
}

func (OpenDoorSecurityPolicyEnforcer) EnforceVerifiedCIMsPolicy(ctx context.Context, containerID string, layerHashes []string) error {
func (OpenDoorSecurityPolicyEnforcer) EnforceVerifiedCIMsPolicy(ctx context.Context, containerID string, layerHashes []string, mountedCim []string) error {
return nil
}

Expand Down Expand Up @@ -445,7 +445,7 @@ func (ClosedDoorSecurityPolicyEnforcer) GetUserInfo(spec *oci.Process, rootPath
return IDName{}, nil, "", nil
}

func (ClosedDoorSecurityPolicyEnforcer) EnforceVerifiedCIMsPolicy(ctx context.Context, containerID string, layerHashes []string) error {
func (ClosedDoorSecurityPolicyEnforcer) EnforceVerifiedCIMsPolicy(ctx context.Context, containerID string, layerHashes []string, mountedCim []string) error {
return nil
}

Expand Down
3 changes: 2 additions & 1 deletion pkg/securitypolicy/securitypolicyenforcer_rego.go
Original file line number Diff line number Diff line change
Expand Up @@ -1157,11 +1157,12 @@ func (policy *regoEnforcer) EnforceScratchUnmountPolicy(ctx context.Context, scr
return nil
}

func (policy *regoEnforcer) EnforceVerifiedCIMsPolicy(ctx context.Context, containerID string, layerHashes []string) error {
func (policy *regoEnforcer) EnforceVerifiedCIMsPolicy(ctx context.Context, containerID string, layerHashes []string, mountedCim []string) error {
log.G(ctx).Tracef("Enforcing verified cims in securitypolicy pkg %+v", layerHashes)
input := inputData{
"containerID": containerID,
"layerHashes": layerHashes,
"mountedCim": mountedCim,
}

_, err := policy.enforce(ctx, "mount_cims", input)
Expand Down
Loading