sylabs / singularity

SingularityCE is the Community Edition of Singularity, an open source container platform designed to be simple, fast, and secure.
https://sylabs.io/docs/
Other
749 stars 96 forks source link

Verification of Multiple Signatures #1150

Open tri-adam opened 1 year ago

tri-adam commented 1 year ago

When singularity verify is called on an image with a single signature, the expected behaviour is straightforward. If the signature can be verified, all is well, and otherwise there is a problem.

When singularity verify is called on an image with multiple signatures, the expected behaviour is less clear. It could be:

  1. Verification is successful if all signatures are verified. This is the current behaviour.
  2. Verification is successful if one or more (but possibly not all) signatures were verified.

Although the first option is the current behaviour, I would argue that it likely isn't the user's expected behaviour in all cases. My intent may be "verify this image has been signed by a particular authority". In this case, I could ensure I have the public key material for the relevant authority, and call verify. Unfortunately, if the image contains other signatures that are not relevant to me, and I don't have access the the required public key material, verification fails.

To make matters worse, in the above use case, verify doesn't have a way for me to specify the relevant authority. The suggestion in https://github.com/apptainer/apptainer/issues/462 goes part way to helping with this by displaying "verified" or "not verified" for each signature, but still requires the user to (visually or programmatically) parse the output to determine whether a signature from the relevant authority can be verified.

In addition, singularity verify now has a --key option to specify non-PGP key material, which introduces yet another complexity. The user expectation of singularity verify --key may very well be "verify this image can be verified with this key material", but at present the semantics are actually "verify all signatures in this image can be verified with this key material". As mentioned in https://github.com/sylabs/singularity/pull/1120#issuecomment-1330754059, this means that verifying an image signed with both PGP and non-PGP key material actually isn't possible, since there is no way to specify multiple key material sources:

$ singularity sign image.sif
$ singularity sign --key private.pem image.sif

This can't be successfully verified, since using --key disables PGP key material as a source:

$ singularity verify image.sif 
Verifying image: image.sif
FATAL:   Failed to verify container: integrity: key material not provided for DSSE envelope signature
$ singularity verify --key public.pem image.sif 
Verifying image: image.sif
FATAL:   Failed to verify container: integrity: key material not provided for PGP clear-sign signature

As a proposal, I suggest the following semantics:

  1. singularity verify image.sif maintains the current semantics, i.e. all signatures in image.sif are verified using PGP public key material.
  2. singularity verify --key public.pem image.sif verifies image.sif can be verified by public.pem. Same if key material is provided by environment variable (ex. VERIFY_KEY=public.pem singularity verify image.sif).
  3. singularity verify --fingerprint ABCD image.sif verifies image.sif can be verified by the PGP entity with fingerprintABCD. Same if a fingerprint is provided by environment variable (ex. VERIFY_FINGERPRINT=ABCD singularity verify image.sif).
fnikolai commented 1 year ago

@tri-adam After looking at the code, I wonder if the --key in verification is needed.

Instead, users can create self-signed certificates and use them directly in --certificate. https://devopscube.com/create-self-signed-certificates-openssl/

Removing the --key not only keeps the CLI cleaner but also makes it more RFC-compliant. Plus, it keeps the semantics cleaner since verifying an officially signed image has the same flag as verifying your self-signed image.

tri-adam commented 1 year ago

@tri-adam After looking at the code, I wonder why the --key is needed.

The --certificate already provides all the needed information to verify the signature (the public key can be extracted directly from it).

They're two different use cases:

  1. You generate a public/private key pair and use them directly (singularity verify --key <public_key>), or
  2. You generate a private key, and then create a certificate that contains the public key (singularity verify --certificate <certificate_with_public_key>)

The first is simpler, with obvious tradeoffs in functionality (establishing trust through chaining, revocation checks, metadata in the certificate, etc.) For an individual or organization that doesn't have a PKI setup, they might choose to go this route.

The second is obviously more rich in functionality, with the downside being complexity.

Sidenote: I 've added support for self-signed certificates and working on the OCSP.

Awesome! Looking forward to checking that out.

Hit me up on the CE Slack if there's any way I can help (invite link on https://sylabs.io/singularity/). Thanks!

fnikolai commented 1 year ago

Ha ! you are fast ;p I was editing my previous answer when I saw your response.

My concern is about the first point, since it can be represented by self-signed certificates.

tri-adam commented 1 year ago

My concern is about the first point, since it can be represented by self-signed certificates.

Ah, gotcha. I guess the goal here is to support a variety of use cases. Raw keys are sort of the lowest common denominator, and if someone wants to re-use a bare key pair from elsewhere (cosign generate-key-pair, for example), they can. Others will want self-signed certs or full certificate chains. And I could see others wanting other approaches like integration with cloud key management systems. At the end of the day, it'll be an individual choice.

We will need to ensure good documentation for all of this... to help guide users towards the approach that best meets their needs!

Does that make sense?