Skip to content

Latest commit

 

History

History
335 lines (245 loc) · 14.6 KB

88-encapsulate-runtime-policies-in-dsse.md

File metadata and controls

335 lines (245 loc) · 14.6 KB

enhancement-88: Encapsulate runtime policies in DSSE-signed envelopes

Release Signoff Checklist

  • Enhancement issue in release milestone, which links to pull request in [keylime/enhancements]
  • Core members have approved the issue with the label implementable
  • Design details are appropriately documented
  • Test plan is in place
  • User-facing documentation has been created in [keylime/keylime-docs]

Summary

This proposal introduces integrated signatures to runtime policies by encapsulating them as DSSE envelopes. This integrated signing standard is an upstream, centralized replacement for the various attached signature formats present in projects like in-toto and TUF (both of which will be using this standard in the near future), and is also supported by the Sigstore project.

This proposal supersedes and builds on the ideas from enhancement proposal 77, authored by Luke Hinds. That proposal focused on mirroring attached signature schemes from in-toto and TUF; since both are moving to DSSE, Keylime should follow suit.

Motivation

Keylime's current policy signing implementation requires that signatures be sent alongside policies themselves, as separate payloads. While suitable for some cases, it is also useful to have a single package where the list and the signature travel in the same payload.

Encapsulation in a standardized signature format would also facilitate easier adoption of Keylime policies into other software supply chain security projects.

Goals

  • Enable a simplified, more secure signature scheme for Keylime policies

Non-Goals

  • No immediate plan to implement signing into the tenant and no extra flags are required, the verifier will check for the signature and signed body and only attempt to validate if they exist.

Proposal

Currently, runtime policies travel as their own payload from tenant to verifier when adding a new agent or creating a new policy using the Runtime Policy API. Signatures travel as separate parts of the payload, and are then verified against the policy by the verifier. Users have to input the policy, the policy's signature, and the key used to create the policy signature.

Instead, the tenant would accept DSSE-formatted envelopes and (optionally) the associated public key as input. Keylime would then be able to perform signature integrity checks through the pipeline, and store the unmodified envelope in its database. This would also enable signature checks after upload time, which is currently not possible.

User Stories (optional)

Story 1

I am deploying Keylime, and I'd like to sign the runtime policy I want to enforce and validate it on the verifier. Before using the Keylime tenant, I create a DSSE-compliant envelope using a private key I use. It contains the policy I wish to use. Once I pass this envelope to the tenant while creating an agent, the envelope is stored in-place on the Keylime verifier, and I can run signature checks on it at will.

Story 2

I am deploying Keylime, and I'd like to store my Keylime policy in a transparency log that supports DSSE envelopes (such as Sigstore). Once I fetch my DSSE-encapsulated policy from Sigstore, I can feed it directly to Keylime with no further processing.

Notes/Constraints/Caveats (optional)

Risks and Mitigations

Design Details

After implementation of proposal 70, a Keylime runtime policy "plaintext" will look like this:

{
    "meta": {
        "version": 0
    },
    "release": 6.5.0,
    "digests": {
        "/root/hello.txt": ["a4dc309f..."]
    },
    "excludes": [],
    "keyrings": {},
    "ima": {
        "ignored_keyrings": [],
        "log_hash_alg": "xxx"
    },
    "ima-buf": {},
    "verification-keys": []
}

This payload is unsigned, and Keylime may continue to accept unsigned runtime policies.

Signing

To create a signed policy compatible with Keylime, the user would have to create a DSSE-compliant envelope, as detailed by the spec. Specifically, the DSSE parameters would be:

  • SERIALIZED_BODY would be the unmodified Keylime policy.
  • PAYLOAD_TYPE would be something unique to Keylime, e.g. application/vnd.keylime+json. IMPORTANT: This must be a Keylime standard.
  • KEYID could be one of two possibilities:
    • A sha256 hash of the public key used to verify the signature to be created. This acts as a map, and would allow for an out-of-band public key.
    • A base64 encoded X509 v3 certificate in PEM format. This is in-band and can be chained to CA for identity.

Then, a DSSE signature envelope would be created using a compliant signing implementation. The resulting envelope would look something like this, as detailed in the DSSE JSON envelope spec:

{
    "payload": "<Base64(SERIALIZED_BODY)>",
    "payloadType": "<PAYLOAD_TYPE>",
    "signatures": [{
        "keyid": "<KEYID>",
        "sig": "<Base64(SIGNATURE)>"
    }]
}

This payload can be transferred unmodified over the wire from the tenant to verifier, and then validated according to the spec.

KEYID details

Keys will be handled differently depending on how the KEYID was created.

  • If the KEYID is a sha256 hash of a pubkey, the associated public key will be stored within the verifier at:

/var/lib/keylime/signing_keys/{hash-of-pubkey}.pkey

  • If the KEYID is an x509 certificate, the public key will be in-band, so a separate keystore is not required. the public key can be extracted from the certificate.

In the future, a chain verification from the the signing cert to a CA may be possible.

Verification

On the verifier, the DSSE payload will be validated. The flow should look something like this:

  • The verifier will check to see if the runtime policy payload is formatted as a DSSE envelope (if not, it will be treated as an unsigned runtime policy)

  • The verifier will either decode the x509 certificate and extract the public key, or will capture the sha256 digest and load the mapped key from /var/lib/keylime/signing_keys/{hash-of-pubkey}.pkey (as specified above in #KEYID details)

  • The verifier will then perform a verification of the DSSE envelope, validating that the signature matches the signed body

  • If any of the steps above fail, then a verifier API will return a failure code.

Test Plan

Unit test will be provided to verify serialization of json input and signature verification.

Upgrade / Downgrade Strategy

While unsigned runtime policies will continue to be accepted, separate signatures will not be.

Dependency requirements

It will be necessary to ship a compliant DSSE signing and verification implementation with Keylime in order to work with DSSE envelopes. There may be upstream implementations from securesystemslib or other libraries used by other DSSE-forward projects like in-toto, and they may be the best option for out-of-band dependencies.

Alternatively, Keylime could also ship its own signing and verification functions that mirror reference implementations seen on the DSSE repo.

Drawbacks

Alternatives

As detailed in proposal 70, Keylime could opt to craft its own payload format. This would reduce cross-compatibility, however, and would limit additional integrations down the line. DSSE has a great page on the rationale for its existence as a standard.

Infrastructure Needed (optional)