securitypolicy: Handle SCITT envelope and transparent fragments#2779
securitypolicy: Handle SCITT envelope and transparent fragments#2779micromaomao wants to merge 10 commits into
Conversation
d3be079 to
05c03c7
Compare
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR adds support for transparency receipts and Transparency Trust Lists (TTLs) to the security policy fragment injection workflow, and bumps the policy framework/API versions and cosesign1go dependency accordingly.
Changes:
- Introduces TTL ingestion (
load_transparency_trust_list) and receipt validation duringLoadFragment. - Extends fragment injection to support multiple blob media types (policy fragments vs TTLs) and allows SVN to be provided via COSE header.
- Updates framework/API versions and vendored module/dependency versions.
Reviewed changes
Copilot reviewed 15 out of 24 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| vendor/modules.txt | Updates vendored cosesign1go module version and go version metadata. |
| go.mod | Bumps github.com/Microsoft/cosesign1go to v1.6.0-alpha1. |
| go.sum | Adds checksums for updated cosesign1go versions. |
| pkg/securitypolicy/version_framework | Bumps framework version to 0.5.0 for new enforcement behavior. |
| pkg/securitypolicy/version_api | Bumps API version to 0.12.0 to expose the new enforcement point. |
| pkg/securitypolicy/securitypolicyenforcer.go | Extends enforcer interface: LoadFragment options + TTL loading API. |
| pkg/securitypolicy/securitypolicyenforcer_rego.go | Implements receipt validation/TTL storage + rollback snapshotting. |
| pkg/securitypolicy/securitypolicy_options.go | Adds media type dispatch, header SVN extraction, TTL parsing/loading. |
| pkg/securitypolicy/framework.rego | Adds new policy constructs: header SVN, required receipts, TTL roots + new rule. |
| pkg/securitypolicy/api.rego | Registers load_transparency_trust_list enforcement point (0.12.0). |
| pkg/securitypolicy/policy.rego | Wires load_transparency_trust_list to framework rule. |
| pkg/securitypolicy/open_door.rego | Allows TTL loading under open-door policy. |
| pkg/securitypolicy/regopolicy_linux_test.go | Adds/updates tests for header SVN, TTL loading, and receipt requirements. |
| pkg/ctrdtaskapi/update.go | Adds mediaType to fragment injection request shape. |
| internal/uvm/security_policy.go | Passes media type through to guest resource settings. |
| internal/protocol/guestresource/resources.go | Adds MediaType field to guest SecurityPolicyFragment. |
| internal/regopolicyinterpreter/regopolicyinterpreter.go | Adds RegoQueryResult.Array() helper for TTL rule results. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| receiptIssuers := make([]string, 0, len(receiptIssuersSet)) | ||
| for issuer := range receiptIssuersSet { | ||
| receiptIssuers = append(receiptIssuers, issuer) | ||
| } |
f2dae99 to
9f91c1b
Compare
|
required_receipt_issuers -> receipt_issuers |
|
| "fragments": apply_defaults("fragment", fragment_fragments, framework_version), | ||
| "external_processes": apply_defaults("external_process", fragment_external_processes, framework_version) | ||
| "external_processes": apply_defaults("external_process", fragment_external_processes, framework_version), | ||
| "transparency_roots": apply_defaults("transparency_roots", fragment_transparency_roots, framework_version), |
There was a problem hiding this comment.
Question - should the tooling add this in by default so that the infra fragment can add TTLs.
Answer - no, we want to reduce the power of the infra fragment and make things more explicit.
KenGordon
left a comment
There was a problem hiding this comment.
As per minor inline comments but also the overall policy shape discussed in the top level comment/discussion.
| // section 3.2 of | ||
| // https://datatracker.ietf.org/doc/html/draft-ietf-scitt-receipts-ccf-profile-02 | ||
| // Returns the recomputed Merkle root and the data-hash from the leaf (this | ||
| // needs to be verified by the caller against an expected value). |
There was a problem hiding this comment.
Explain why this is CCF - ie a subtype of the SCITT schemes. ie not meaning just for Amaury.
Signed-off-by: Tingmao Wang <tingmaowang@microsoft.com>
This version update is backwards compatible with v1.4.0, so gcs still builds. It adds support for parsing new "SCITT"-style COSESign1 envelops, and the issuer and feed is automatically extracted from their new location in the CWT claims, if we get a new style fragment. It also adds support for parsing receipts and TTLs. Signed-off-by: Tingmao Wang <tingmaowang@microsoft.com>
Refactor LoadFragment parameter to add a HeaderSvn field. If the SVN is set in the protected headers, pass it to LoadFragment, which will let framework validate that it is at least the minimum required SVN before loading any fragment Rego code. Assisted-by: GitHub Copilot:auto copilot-review Signed-off-by: Tingmao Wang <tingmaowang@microsoft.com>
Signed-off-by: Tingmao Wang <tingmaowang@microsoft.com>
Assisted-by: GitHub Copilot:auto copilot-review Signed-off-by: Tingmao Wang <tingmaowang@microsoft.com>
Let InjectFragment accept an extra media type field, populated by azcri, which will determine if we're handling a Rego policy fragment or a Transparency Trust List (TTL). Backward compatibility is maintained by defaulting to application/cose-x509+rego. Add a new load_transparency_trust_list enforcement point so that whether a TTL is accepted can be gated by policy, and the policy can select which ledgers the TTL can add keys for. The framework uses transparency_trust_lists in a policy / fragments as the set of allowed TTL signers. Use cosesign1.ParseTTLPayload to parse the payload. Bump version_api to 0.12.0. Add apply_defaults for transparency_trust_lists Assisted-by: GitHub Copilot copilot-review Signed-off-by: Tingmao Wang <tingmaowang@microsoft.com>
Fragments may now declare receipt_issuers, a list of ledgers from which a valid transparency receipt, verifiable with loaded TTLs, must be present on the fragment's COSE envelope before the fragment is allowed to load. Add a Receipts field to LoadFragmentOptions, populated from the COSE envelope in InjectFragment. The Rego enforcer validates each receipt against the keys for its claimed issuer only, so a ledger cannot sign a receipt pretending to be a different ledger, and passes the set of validated issuers to the policy as input.receipt_issuers in both load_fragment phases. framework.rego load_fragment now checks receipt_issuers against input.receipt_issuers and denies with 'missing receipt from <ledger>'; check_fragment defaults the field to [] so older policies are unaffected. Receipt validation is behind a swappable closure so tests can exercise the logic without a real CCF receipt. Signed-off-by: Tingmao Wang <tingmaowang@microsoft.com>
9f91c1b to
2cf640e
Compare
Assisted-by: GitHub Copilot copilot-review Signed-off-by: Tingmao Wang <tingmaowang@microsoft.com>
Assisted-by: GitHub Copilot copilot-review Signed-off-by: Tingmao Wang <tingmaowang@microsoft.com>
aa13087 to
6f8623b
Compare
…t's required receipt_issuers list. This allows a fragment to be signed by any ledger keys introduced by specific TTLs, either constraining the eligible TTL's subject, or allow any trusted TTL. Assisted-by: GitHub Copilot copilot-review Signed-off-by: Tingmao Wang <tingmaowang@microsoft.com>
| policy.ttlKeysLock.Lock() | ||
| defer policy.ttlKeysLock.Unlock() | ||
|
|
| ctx, span := oc.StartSpan(ctx, "securitypolicy::InjectFragment") | ||
| defer span.End() | ||
| defer func() { oc.SetSpanStatus(span, err) }() | ||
| span.AddAttributes(trace.StringAttribute("fragment", fmt.Sprintf("%+v", fragment))) | ||
|
|
Require corresponding containerd / azcri changes to send MediaType in PolicyFragment struct.
TODO:
Tested with LCOW using this policy: