-
Notifications
You must be signed in to change notification settings - Fork 551
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow specifying CA chain when not using Fulcio #1554
Comments
+1 to allowing this somehow. I've been meaning to think more about it forever but haven't had the time. Thanks for opening it! |
Also, Something like:
Currently |
@dlorenc Do you have a preference for new flags like |
I'd probably defer to @haydentherapper on that! |
I was interested in making changes around this, thanks for bringing this up! I'd prefer a new flag Note that we need to change how Cosign verifies a certificate chain. Currently Cosign is only expecting a leaf certificate without a chain, because the hosted Fulcio infrastructure issues leaf certificates directly off a root CA. We'll need to also pass in intermediate certificates to Something to discuss further is specifying the root via flag for verification. In order to trust a certificate, Cosign currently expects the root CA certificate to be signed via a mechanism called TUF (tl;dr is securing trusted files), and you can provide your own CA roots signed through TUF via the |
For actual verification in a Kubernetes cluster I was looking at Kyverno's image verification support. It doesn't appear to be documented yet, but its policies now allow specifying What you're describing with TUF makes sense for command line verification. However for something like kyverno policy, I'm not entirely sure it's needed. The ability to provide policy configuration is privileged. "Enterprise" use cases could use an existing organizational CA, but may not use TUF, Fulcio or Rekor. What happens if I specify |
That's a good point, I was considering the command line flags. I agree that it's fine that the Cosign package API supports specifying roots without TUF, but the Cosign flags should not.
Correct, if roots are provided here directly, this does not go through TUF. For Cosign, in |
I can work on this later this week, unless @bburky was planning to work on this. |
@haydentherapper I was thinking of working on it some, but I'm still not really too familiar with the codebase yet, please go ahead and start it. I'll see if I can review your PR. I hacked in a |
I'll split this change into two - The first will add support for intermediate certs for those using the Cosign library. For adding support for verification using flags, I'd like to think through this a bit more, in particular for those who want to bring their own PKI but not use TUF. For example, currently, |
I'm walking back the earlier comment about not allowing the root certificate to be specified. With the assumptions the code currently makes, it's assumed that Fulcio, Rekor and TUF usage go hand in hand. It would require a bit of refactoring to allow a root CA specified by TUF and used with a provided certificate. I think there is still value in allowing a root to be pinned by TUF, but this can be done separately. I'm going to allow the full certificate chain to be specified in the |
All PRs have been submitted now. If there's any issues, in particular with PKCS11 tokens, let me know! |
Thanks for working on all the changes to implement this! I think this should enable cosign to support a lot of organizational use cases where internal PKI exists. I left comments on a few of the issues, let me know if anything needs clarification. |
I think we also need to support this for the EDIT: maybe this is not the right issue for that, because the above only applies when you are using Fulcio. But if you're using Fulcio without a corresponding TUF instance (e.g., in local dev) it's quite useful. |
I can add support to Something to note is we now support uploading certificate chains to Rekor, but Cosign does not support reading entries with a chain uploaded. |
I think that's okay. Here's the issue I've been running into (with Fulcio running in docker-compose fulcio@d834c5): $ cosign sign-blob --fulcio-url=http://localhost:5555 /dev/null
Using payload from: /dev/null
Generating ephemeral keys...
Retrieving signed certificate...
Your browser will now be opened to:
https://oauth2.sigstore.dev/auth/auth?access_type=online&client_id=sigstore&...
Error: signing /dev/null: getting key from Fulcio: verifying SCT: failed to verify ECDSA signature
main.go:46: error during command execution: signing /dev/null: getting key from Fulcio: verifying SCT: failed to verify ECDSA signature I'd like to manually grab the root CA from Fulcio ( |
Totally reasonable! I'll take a look at adding this. When I've been testing out Fulcio locally, I either provide the insecure flag, or set up a local TUF repository. |
Looked into adding this - A couple of thoughts:
|
I think the "BYO-root" use case is broken. Imagine I have some certs ( $ step certificate create \
--no-password \
--insecure \
--profile root-ca \
root-ca root-ca.crt root-ca.key
$ step certificate create \
--no-password \
--insecure \
--profile intermediate-ca \
--ca ./root-ca.crt \
--ca-key ./root-ca.key \
intermediate-ca intermediate-ca.crt intermediate-ca.key
$ # Need to use a template to make a code signing cert
$ cat > cert.tpl <<-EOF
{
"subject": {{ toJson .Subject }},
"sans": {{ toJson .SANs }},
"keyUsage": ["digitalSignature"],
"extKeyUsage": ["codeSigning"]
}
EOF
$ step certificate create \
--no-password \
--insecure \
--template cert.tpl \
--ca ./intermediate-ca.crt \
--ca-key ./intermediate-ca.key \
foo foo.crt foo.key I can use them to sign an image: $ REPO="ttl.sh/$(head -c 8 /dev/urandom | xxd -p)"
$ TAG="5m"
$ SRC_IMAGE=gcr.io/distroless/static-debian11
$ export COSIGN_EXPERIMENTAL=1
$
$ # Copy an image to a short-lived repo
$ crane copy $SRC_IMAGE "$REPO:$TAG"
$
$ # Sign
$ COSIGN_PASSWORD=password cosign import-key-pair --key foo.key
$ cat intermediate-ca.crt root-ca.crt > chain.crt
$ COSIGN_PASSWORD=password cosign sign --key import-cosign.key \
--certificate-chain chain.crt \
--certificate foo.crt \
"$REPO:$TAG"
$ # Verify with the cert/chain from above, provided explicitly:
$ cosign verify --certificate-chain chain.crt --certificate foo.crt "$REPO:$TAG" That works. I'd expect to be able to verify using $ SIGSTORE_ROOT_FILE=root-ca.crt cosign verify "$REPO:$TAG"
Error: no matching signatures:
x509: certificate signed by unknown authority
main.go:62: error during command execution: no matching signatures:
x509: certificate signed by unknown authority But that fails. I can do it myself in a pretty hacky way: $ SIG=$(cosign triangulate "$REPO:$TAG")
$ crane manifest $SIG > manifest.json
$ cat manifest.json \
| jq '.layers[0].annotations."dev.sigstore.cosign/certificate"' -r \
| grep . \ # https://github.com/sigstore/cosign/issues/2237
> registry.crt
$ cat manifest.json \
| jq '.layers[0].annotations."dev.sigstore.cosign/chain"' -r \
| grep . \ # https://github.com/sigstore/cosign/issues/2237
> registry.chain.crt
$ # Pull out the provided root cert from the chain and check that it matches.
$ sed -n '/END CERTIFICATE/,$p' registry.chain.crt | tail -n +2 > registry.root.crt
$ diff root-ca.crt registry.root.crt || echo "no match!"
$ cosign verify --certificate-chain registry.chain.crt --certificate registry.crt "$REPO:$TAG" This feels like a use case that should be supported; I'd argue for a first-class |
Will take a look! At a glance, my guess is the correct intermediate is not being found, but it might be something else. |
Ah ha, I think I figured out what's happening:
The step where I said "ah ha" is where I expect the intermediates to be populated when not explicitly provided. This was intentionally added to avoid intermediates always needing to be specified, that you'd just need to pin the root. I then realized that because we always initialize a CertPool, even if it's empty, it's still non-nil, so we never populate the intermediate from the chain. So, two ways to fix this:
|
re: |
Looks like this was an accidental regression, at one point we were lazily loading the intermediate pool - https://github.com/sigstore/cosign/pull/1804/files I think this change occurred when we moved over code from sigstore/sigstore. I'll fix this! |
I agree with you in principle, but as a matter of pragmatism, using an existing root is a real use case, and setting up TUF is a hassle. Even if the tooling were polished, you have to stand up a new repository, and manage the keys. Think about migrating from a traditional code-signing PKI to Sigstore (like your Adopting Sigstore Incrementally post, the "Self-managed keys in identity-based code signing certificate with auditability" section).
Agreed, which is why we should promote it to a real flag and test/document it 😛 |
This fixes a regression where intermediates, when not present in the intermediate certificate pool, would be fetched from the OCI chain annotation. Ref sigstore#1554, which includes more details Signed-off-by: Hayden Blauzvern <hblauzvern@google.com>
This fixes a regression where intermediates, when not present in the intermediate certificate pool, would be fetched from the OCI chain annotation. Ref sigstore#1554, which includes more details Signed-off-by: Hayden Blauzvern <hblauzvern@google.com>
This fixes a regression where intermediates, when not present in the intermediate certificate pool, would be fetched from the OCI chain annotation. Ref sigstore#1554, which includes more details Signed-off-by: Hayden Blauzvern <hblauzvern@google.com>
…#2244) This fixes a regression where intermediates, when not present in the intermediate certificate pool, would be fetched from the OCI chain annotation. Ref #1554, which includes more details Signed-off-by: Hayden Blauzvern <hblauzvern@google.com> Signed-off-by: Hayden Blauzvern <hblauzvern@google.com>
I am trying to setup container image signing without having to setup and maintain a service for TL. We already have a PKI system with identity certificates available that I want to use for signing the container images. So, far, I have been able to use I am not sure if I am trying to do something stupid over here, but is there some reason why we can't get the certificate & chain from the manifest and validate the signature only with the ROOT ca being provided to the |
Can you try |
@haydentherapper ^ That doesn't work unless you have
|
FWIW, i tried verification using Kyverno and it seems to work by just adding the cert chain in the ClusterPolicy. This is the verification code in Kyverno. So, it seems like this is just a matter of allowing verification (and perhaps a better way to pass the root-cert/chain to the CLI) in the CLI? I'll try to spend some time digging through the code. |
Ah yes, that would require checking the transparency log by default. We should be supporting this use case of automatically fetching the certificate and chain from the annotations. We are working on removing the experimental flag and will be providing a flag to explicitly not check the tlog. For now, I believe you can set “rekor-url” to an empty string, which should disable tlog checks even when the experimental flag is turned on. If it doesn’t, let us know, we can push a fix to support that case. |
Aha, you are absolutely right! Setting the |
Glad you got it working! Apologies that this UX is...unfortunate right now. Normally I would insist that we clean it up, but I think in this case there's going to be some unification where we flip |
In terms UX, my initial expectation was to use I agree that removing the |
This should be complete now. There's some lingering issues like supporting |
When using a local PEM key file, a PKCS#11 key, or a KMS key a user should be able to specify
--cert
and something like--chain
to specify thedev.sigstore.cosign/certificate
anddev.sigstore.cosign/chain
.The following already works to specify the certificate, and correctly adds it to the cosign signature:
However,
--cert
is silently ignored in the following command (the certificate from the token is used instead of the provided one): (this is a separate bug really, should I create a new issue for it?)It is not possible with either of these to specify the CA chain. If my certificate is signed by existing PKI, I would like to include the intermediate certificates and root in the signature.
Two possible implementations would be:
--chain
which includes a chain of certificates.--cert
file to include both the leaf cert, and a chain of intermediates.--chain
they do not need to.Providing the certificate chain is incompatible with using Fulcio, and should return an error.
The text was updated successfully, but these errors were encountered: