sigstore/cosign

FR: BYO PKI Revocation: CA-issued cert

Opened this issue · 9 comments

Description

In a Bring your Own PKI scenario, a user may want to specify a CRL file ( in addition to a fullchain file ) that can be used to check if the certificate embedded in a signature artifact has been revoked. This could be done by passing in a --crl switch or environment variable? Something like the following:

COSIGN_EXPERIMENTAL=1 \
SIGSTORE_ROOT_FILE=./your/fullchain.pem \
cosign verify --rekor-url="" --crl ./your/crl.pem repo/someImage:someTag 

My target scenario assumes the CA ( and intermediate CAs ) are trusted; but the signing key/cert is revoked; in which case a --crl type of option which allows a user to opt into that CRL aware behavior could act accordingly. With a correct CA chain & current CRL, they should then be able to dis-trust the signing certificate that is baked into an existing signature artifact.

In thinking of this a OpenSSL primitives perspective, we'd be 1) create the store with CA certs, 2) add crls to the store 3) create the certificate context from the cert stored on the artifact 4) see the certificate context fail to validate due to the CRL.

Since its a Bring Your Own PKI situation, questions about the distribution / maintenance of CRL files is outside of the scope of cosign.

This concept builds off of workflows noted in #1554

Overall I'm in favor of some kind of revocation handling for the BYO PKI uses for Cosign. Note that this contrasts with my previously-stated opinions about revocation, which suggested that it's out-of-scope for Sigstore. That's because "Cosign with BYO PKI" is quite different from "Cosign with Sigstore (even a privately-operated instance)" IMO, and adding revocation support to BYO PKI Cosign doesn't mean adding revocation support to Sigstore.

@haydentherapper notes that CRLs have a lot of issues:

CRLs are really hard to work with - they grow indefinitely, you need to decide how to poll them or else local copies get out of date quickly. There are many examples of CRLs being a pain for web PKI. That doesn't mean that organizations might not still want to leverage them, but Sigstore has avoided revocation for these reasons. Revocation of signing keys or identities or artifacts I think is out of scope for Cosign, and would need to built as a separate project focused on verification. sigstore/policy-controller might be a good candidate.

I agree overall but note that in the BYO PKI setting at least some of these issues aren't in scope: single organizations are able to manage a revocation list much better than all of the CAs in web PKI together.

Random note: I think we should take great pains to separate the BYO PKI experience from the Sigstore experience in general, as there's a lot of friction trying to impose features from one context onto the other. But Cosign does have this awkward dual role as "generic container Signing tool" and "generic Sigstore tool."

Revocation[...]I think is out of scope for Cosign, and would need to built as a separate project focused on verification[....] sigstore/policy-controller might be a good candidate

I actually think that we should avoid divergence between sigstore/policy-controller and Cosign. I do think that BYO PKI behavior doesn't belong in s/s or sigstore-go for reasons like what you describe.

Looping back to this after the holiday!

I do agree that CRLs can be a painful tool to use, and Web PKI is a classic example of them failing at their job. I also think that CRL distribution in the BYO story is a problem for the people doing the BYO and not the tools [ cosign ] responsibility to handle. Someone in that scenario is already opting into an experience which isn't without that staleness question; but it is also a scenario that some organizations may want if they are unable to take advantage of Sigstore / Rekor / Fulcio.

Cosign does have this awkward dual role as "generic container Signing tool" and "generic Sigstore tool."

I think this is kind of the crux of the matter with the BYO story. Docker Content Trust suffers from being the first kid on the block and having limited support; notary v2 doesn't seem to have active progress ( from a outsider perspective ); which leaves cosign as the best available tooling as the generic container signing tool I have come across. That makes it a super appealing tool to want to use for people [ like myself ] who may not be able to leverage Sigstore.

One reason I worry about placing the idea of being revocation awareness living in a kubernetes admission controller is that users who aren't using kubernetes cannot benefit from that. While kubernetes is a popular container orchestration tool, it isn't something that is used by 100% of the world.

FWIW I agree with everything here, and we should figure out the "least bad" way to add revocation here since users will eventually need it. By "here", I mean cosign and policy-controller.

I'm still reluctant about adding this, but if someone does want to tackle this, some recommendations and thoughts:

  • Revocation should be opt-in for clients to not impact those who aren't BYO PKI.
  • Do not use the CRL Distribution Point from the certificate. I wouldn't make this configurable either in my opinion, even with a local caching mechanism. There's risk of DOSing your infrastructure if every verification pulls down a CRL.
  • CRLs grow indefinitely. Are you going to support the standard PKCS#7 CRLs? Or do you want to support the bloom filter based CRLite? You'll find more Golang library support for PKCS#7 CRLs, but that comes with all of the typical baggage.

To make sure I understand the implications, would this impact the CA's ability to issue short-lived certificates? I think BYO PKI with short-lived certs and later revocation would imply a non-RFC 5280 compliant CA:

OpenSSL would likely be able to build such a CA/CRL, but other CA software might need extensions to support especially the latter (building CRLs with expired, revoked certs), even if it supports the identity profile of v2.

My 2c.

As private PKI, Sigstore doesn't need to conform to RFC 5280. We haven't actively tried to deviate, as conformance means that most off the shelf libraries and tools can handle certificate verification, but in cases like this, it would be up to the BYO PKI deployer to meet RFC 5280 compliance.

Sigstore's public instance, which issues short-lived certificates, wouldn't issue CRLs. This issue is about adding CRL support to the tooling. The tooling doesn't mandate certificate lifetime, so a producer would be free to issue long-lived certs either via their own CA or with a private instance of Fulcio configured to issue long-lived certs.

@haydentherapper I certainly agree that one can deviate from WebPKI/RFC 5280 for code signing... in theory. In practice, much of the code (libraries, CAs, ...) is only RFC 5280 compliant. Many broader ecosystem improvements are also driven only in the name of WebPKI. Non-WebPKI aligned usages tend to get marginal support, at best. Relevantly, Cosign is written in Go, whose standard library only claims RFC 5280 compliance and has historically been hesitant to add anything non-RFC 5280.

So, from a standardization perspective, I'd suggest sticking to a well-supported (subset) of the RFC 5280 profile, especially if you want to allow other implementations in the future. I think this is what your last line recommends (if external PKIs issue long-lived certs, they could then do revocation on them -- which would be RFC 5280-aligned).

I'm a bit curious what the semantics of this would be and how would cosign differentiate a long-lived PKI issuer from a short-lived one? An extension? Would an expiry of a long-lived certificate mean invalidation of the signature? Ironically, if the CA/BF didn't drop OCSP and major providers follow suit, I might've recommended that instead of CRLs as a starting point. :-)

Many thanks!


To push back on two points above:

  • Do not use the CRL Distribution Point from the certificate. I wouldn't make this configurable either in my opinion, even with a local caching mechanism. There's risk of DOSing your infrastructure if every verification pulls down a CRL.

Decent CRL distribution infrastructure would be fast and re-serve the last CRL and only periodically rebuild it; advanced (private) CAs support CDN distribution like public CAs. That said, there's still a bandwidth problem and potentially storage as well (if the local client caches the CRL), which makes OCSP in general more suited to this use case. Sadly, WebPKI seems to mostly be walking away from OCSP, which might make support for it in the future harder to advocate for.

  • CRLs grow indefinitely. Are you going to support the standard PKCS#7 CRLs? Or do you want to support the bloom filter based CRLite? You'll find more Golang library support for PKCS#7 CRLs, but that comes with all of the typical baggage.

As I mentioned above, CRLs can, yes, grow to an unbounded size if unlimited issuance within a standard validity period occurs... But they'll naturally be pruned once revoked certs expire assuming compliance with RFC 5280. If short-lived, post-expiry revocation is to be supported, then they will indeed grow.

how would cosign differentiate a long-lived PKI issuer from a short-lived one?

To verify a short-lived certificate, a signed timestamp over the artifact signature needs to be presented and verified, and that timestamp's time is used to verify the certificate. This can also be done for a long-lived certificate, but the tooling doesn't mandate it by default if the system time can verify the certificate (note that sigstore-go allows developers to create verification policies that can require signed timestamps, which Cosign is actively starting to integrate with).

There's another issue on this repo that discusses the idea of having a separate API for non-Fulcio certificates, for bring-your-own PKI use cases. I very much like this idea, as it lets us keep the most commonly used API for Sigstore lean (for verifying certificates conforming to the Fulcio certificate profile), while expanding the other API for use cases such as this.

On my point about RFC 5280 compliance, I bring this up because we don't want to say we conform to all of RFC 5280. I don't expect us to deviate against it because of our reliance on Go's x509 library (though even then, it is a subset of RFC 5280 primarily for TLS certificates, which we've dealt with before when we wanted to use a non-URI/DNS/email SAN), but I don't expect us to implement support for every part of the RFC, at least in the core API.

I'm open to a proposal for adding support for CRLs if someone wants to design and implement it, though I'd be even more open to it if it were a part of the Cosign refactor around sigstore-go's APIs where we have a separate API for handling these non-Sigstore-spec use cases.