Skip to content

c-wcow policy and blockcim tooling - #2870

Open
Maksim An (anmaxvl) wants to merge 2 commits into
microsoft:mainfrom
anmaxvl:wcow-policy-tooling
Open

c-wcow policy and blockcim tooling#2870
Maksim An (anmaxvl) wants to merge 2 commits into
microsoft:mainfrom
anmaxvl:wcow-policy-tooling

Conversation

@anmaxvl

@anmaxvl Maksim An (anmaxvl) commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Add Confidential WCOW security-policy generation + a block CIM root-hash dumper

Summary

This PR adds authoring-side support for generating Confidential WCOW (Windows) security policies, mirroring the existing C‑LCOW image-based flow, plus a small standalone tool for reading a block CIM's sealed root hash. The runtime enforcement side (verified CIM mounts) already existed; this fills in the policy-generation side so a policy can be produced from an image reference and will match what the runtime computes at mount time.

Motivation

For Confidential WCOW, a policy must pin each layer's verified Block CIM root digest. Getting that digest to match the runtime turned out to be subtle: the CimName embedded in a block CIM's PrimaryBlockTable contributes to the sealed root hash. containerd's cimfs snapshotter names every layer's CIM layer.cim (each in its own directory) and the merged CIM merged.cim; the tooling must reproduce this exactly, otherwise identical layer content yields a different digest. The blockcimdump tool was built to diagnose this on-disk and is included as a reusable debugging aid.

Changes

securitypolicy: Confidential WCOW policy generation

  • securitypolicy: new WindowsContainerConfig (image-based) and CreateWindowsContainerPolicy, WithWindows* options, and Windows rego/fragment marshalling. Windows policy is rego-only; the JSON marshaller is rejected for Windows and removed as a registered marshaller. regoString() escapes backslashes/quotes so Windows paths and user strings survive marshalling.
  • securitypolicy: new -os linux|windows flag routing marshalling per OS; PolicyWindowsContainersFromConfigs fetches the Windows-platform image and computes verified Block CIM digests.
  • helpers/windows.go: imports each layer into a verified single-file Block CIM and reads its sealed root digest. Each layer is imported into its own directory with CimName = "layer.cim" (merged: "merged.cim"), matching containerd's snapshotter/differ exactly, since the embedded CimName contributes to the digest. SECURITYPOLICY_BLOCKCIM_DIR preserves the intermediate *.bcim for inspection.
  • Existing LCOW policy-generation behavior is preserved; the Windows path is taken only for windows_container config entries.

tools/blockcimdump: block CIM root-hash dumper

  • Pure‑Go, cross-platform tool that reads the sealed root hash of a block CIM (containerd's layer.vhd or the tooling's *.bcim) directly from on-disk metadata, without the Windows CIM APIs — the same value cimfs.GetVerificationInfo returns.
  • Auto-detects cluster size from the header ((1<<Exponent)*SectorSize, -cluster overrides); -hash prints only the root hash; also dumps the BlockDeviceHeader and PrimaryBlockTable (per-entry CimName + content hash).

Testing

  • go build of pkg/securitypolicy/..., internal/tools/..., and the test module — clean.
  • go test pkg. — pass.
  • blockcimdump -hash against a containerd layer.vhd returns the expected sealed root digest; after the CimName fix, the tooling-produced layer reproduces the same digest.
  • gofmt + go vet clean on changed files.

@anmaxvl
Maksim An (anmaxvl) requested a review from a team as a code owner August 11, 2026 08:57
Add a small, pure-Go, cross-platform tool that reads the sealed root
hash of a block CIM (containerd's layer.vhd or the securitypolicy
tooling's *.bcim) directly from its on-disk metadata, without the
Windows CIM APIs.

The sealed root hash is the value cimfs.GetVerificationInfo returns and
what a confidential policy digest compares against, so being able to
read it on any platform makes digest mismatches debuggable. The tool
also prints the BlockDeviceHeader and PrimaryBlockTable (including each
entry's CimName and content hash), which is what surfaced that the
embedded CimName contributes to the root digest.

- Cluster size is auto-detected from the header ((1<<Exponent)*
  SectorSize), overridable via -cluster.
- -hash prints only the root hash for scripting.

Signed-off-by: Maksim An <maksiman@microsoft.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the security policy tooling and library to support C-WCOW (Windows) policy generation using Block CIM digests, introduces a standalone blockcimdump inspection tool, and removes legacy JSON policy output in favor of Rego.

Changes:

  • Add Windows container policy config/model support (windows_container), plus Windows-specific policy/fragment marshalling APIs.
  • Update securitypolicytool to target Linux vs Windows (-os) and restrict output types to Rego/fragment.
  • Add Windows Block CIM digest computation helpers and a new blockcimdump tool for inspecting sealed root hashes.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
test/pkg/securitypolicy/policy.go Add test helpers to build Base64 Windows policies from config opts.
pkg/securitypolicy/windows_tooling_test.go Add unit tests for Windows container policy creation/marshalling and escaping.
pkg/securitypolicy/securitypolicy.go Add WindowsContainerConfig + PolicyConfig.WindowsContainers and Windows container policy builder.
pkg/securitypolicy/securitypolicy_marshal.go Make Rego the default marshaller; add Windows policy/fragment marshalling; improve string escaping.
pkg/securitypolicy/securitypolicy_internal.go Add Windows containers to fragments and include MountedCim in internal conversion.
pkg/securitypolicy/opts.go Add Windows container config opts and WithWindowsContainers.
internal/tools/securitypolicy/README.md Update docs for Rego-only output and add C-WCOW usage/examples.
internal/tools/securitypolicy/main.go Add `-os [linux
internal/tools/securitypolicy/helpers/windows.go Implement Windows Block CIM digest computation via CIM APIs.
internal/tools/securitypolicy/helpers/windows_test.go Add validation test for Windows container configs (requires image_name).
internal/tools/securitypolicy/helpers/windows_others.go Provide non-Windows stub error for digest computation.
internal/tools/securitypolicy/helpers/helpers.go Add Windows-container policy materialization from image-based configs.
internal/tools/blockcimdump/main.go New CLI tool to inspect Block CIM metadata/root hash without CIM APIs.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread internal/tools/securitypolicy/helpers/helpers.go Outdated
Comment thread internal/tools/securitypolicy/helpers/windows.go Outdated
Comment thread pkg/securitypolicy/securitypolicy_marshal.go
Comment on lines +75 to +80
func TestMarshalWindowsPolicyRejectsJSON(t *testing.T) {
_, err := MarshalWindowsPolicy("json", false, nil, nil, nil, false, false, false, false, false, false, false, false)
if err == nil {
t.Fatal("expected JSON marshalling to be rejected for Windows policies")
}
}
Comment thread pkg/securitypolicy/securitypolicy_marshal.go Fixed
Comment thread pkg/securitypolicy/securitypolicy_marshal.go Fixed
Comment thread pkg/securitypolicy/securitypolicy_marshal.go Fixed
Comment thread pkg/securitypolicy/securitypolicy_marshal.go Fixed
Comment thread pkg/securitypolicy/securitypolicy_marshal.go Fixed
Comment thread pkg/securitypolicy/securitypolicy_marshal.go Fixed
Comment thread pkg/securitypolicy/securitypolicy_marshal.go Fixed
Comment thread pkg/securitypolicy/securitypolicy_marshal.go Fixed
Comment thread pkg/securitypolicy/securitypolicy_marshal.go Fixed
Comment thread pkg/securitypolicy/securitypolicy_marshal.go Fixed
Extend the securitypolicy package and tooling to generate rego policies
for Confidential WCOW (Windows) images, mirroring the existing C-LCOW
image-based flow. The runtime enforcement side (verified CIM mounts)
already existed; this adds the authoring side so a matching policy can
be produced from an image reference.

Key changes:
- pkg/securitypolicy: add WindowsContainerConfig (image-based) and
  CreateWindowsContainerPolicy, WithWindows* opts, and Windows rego/
  fragment marshalling. Windows policy is rego only; the JSON marshaller
  is rejected for Windows. regoString() escapes backslashes/quotes so
  Windows paths and user strings survive marshalling.
- internal/tools/securitypolicy: add -os linux|windows and route
  marshalling per OS; PolicyWindowsContainersFromConfigs fetches the
  windows platform image and computes verified Block CIM digests.
- helpers/windows.go: import each layer into a verified single-file
  Block CIM and read its sealed root digest. Each layer is imported into
  its own directory with CimName "layer.cim" (merged: "merged.cim"),
  exactly matching containerd's cimfs snapshotter/differ, since the
  embedded CimName contributes to the sealed root digest. Setting
  SECURITYPOLICY_BLOCKCIM_DIR preserves the intermediate *.bcim for
  inspection.

Existing LCOW policy generation behavior is intentionally preserved; the
Windows path is only taken for windows_container config entries.

Signed-off-by: Maksim An <maksiman@microsoft.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants