Introduce opaque signer.Signer objects#1776
Conversation
copy/sign.go
Outdated
| } | ||
| defer signer.Close() | ||
|
|
||
| c.Printf("%s\n", internalSigner.ProgressMessage(signer)) |
There was a problem hiding this comment.
Note to self: why does this work? Shouldn't it be signer.ProgressMessage()?
There was a problem hiding this comment.
What would be a good place to document how this is intended to work?
There was a problem hiding this comment.
I have no idea. I think it's OK as is and it was immediately obvious in the code. Just when reading the commits one-by-one I was surprised for a moment.
signature/simple/signer.go
Outdated
| "github.com/containers/image/v5/signature/signer" | ||
| ) | ||
|
|
||
| // simpleSigner is a signer.Signer implementation for simple signing signatures. |
There was a problem hiding this comment.
Nit: Could we embed GPG in the name? It would be more expressive to me when reading.
There was a problem hiding this comment.
(The user-visible documentation is on the new NewSigner function, or possibly for the package, not on package-private simpleSigner.)
The format is not just GPG, and I think it makes sense to be consistent about the name. Originally the format was called “atomic container signatures”. Now we tend to say “simple signing”. IMHO adding another name is not worth it, though I’m not feeling too strongly about it.
GPG is not really essential (from the very start, there’s been at least a documented but rejected "keyType": "X509Certificates"), though I agree that it’s very unlikely any non-GPG format will be added.
Right now NewSigner sort of points at GPG, but probably not quite sufficiently.
Sort of related, there is now a ton of subpackages named …/signature or …/sigstore or …/internal; each individual name seems reasonable, and the small packages seem to be useful to decrease the dependency surface, but it adds up to a fairly bad whole. I’m sure there are better ways to organize, any ideas would be great.
There was a problem hiding this comment.
Should it even be signature/simple? signature/simplesigning would be consistent with internal/signature.SimpleSigning.
There was a problem hiding this comment.
Moved to signature/simplesigning now, but that’s not intended to stop the search for another name.
There was a problem hiding this comment.
simplesigning SGTM
It's somehow a known terminology in our universe.
copy/copy.go
Outdated
|
|
||
| // Signers to use to add signatures during the copy. | ||
| // Callers are still responsible for closing these Signer objects; they can be reused for multiple copy.Image operations in a row. | ||
| Signers []*signer.Signer |
There was a problem hiding this comment.
I don't have a strong opinion on that. One worry I have is boilerplate code for callers. skopeo, libimage and CRI-O would all need updates, wouldn't they?
There was a problem hiding this comment.
Totally, this would need a common utility. (Not CRI-O, it doesn’t create signatures.)
Right now there is a WIP https://github.com/mtrmac/image/tree/fulcio-signing/pkg/cli/sigstore : just importing copy.Image adds dependencies enough to validate Fulcio + Rekor signatures, and to sign using private keys, but importing this cli/sigstore subpackage drags in the Fulcio + Rekor RPC clients.
I actually fairly strongly think that we need to go further than that, and to expose a config file for signing with Fulcio+Rekor (because there are like 6 individual options to set). And then NewSignerFromSigstoreSigningConfigFile would be a natural utility to share across various copy.Image callers to implement that config file.
If the comment is about the deprecation of existing SignBy… options, I now think that’s something that is eventually a good idea, but should not be done in this PR; it’s an internal cleanup for no end-user benefit and the end-user functionality is much more important short-term.
There was a problem hiding this comment.
SGTM
I am mostly worried to end up like in a pre-libimage period where the tools have duplicate code that must be maintained separately.
A config file sounds good to me and makes perfect sense. It seems more user friendly (and code friendly) to have one central place to configure the setup rather than passing things from the CLI through the entire call stack.
d0af47e to
2698265
Compare
mtrmac
left a comment
There was a problem hiding this comment.
Now updated:
- With tests
- The deprecation was moved to another branch, to be done (much?) later
- Renaming
signature/simpletosignature/simplesigning - GPG tests now terminate
gpg-agentprocesses so that we don’t leave several around.
Still a draft because final users don’t exist, but I think this PR is fairly close to finished.
| // FIXME FIXME: gpgme_op_sign with a passphrase succeeds, but somehow confuses the GPGME internal state | ||
| // so that gpgme_op_verify below never completes (it polls on an already closed FD). | ||
| // That’s probably a GPG bug, and needs investigating and fixing, but it isn’t related to this “signer” implementation. | ||
| if len(c.opts) == 0 { |
There was a problem hiding this comment.
This is a bug that certainly needs tracking down: https://github.com/containers/image/issues/1777 .
“Luckily” it probably only affects long-term processes that sign (and verify?), i.e. not Podman and not CRI-O.
| const ( | ||
| // testImageManifestDigest is the Docker manifest digest of "image.manifest.json" | ||
| testImageManifestDigest = digest.Digest("sha256:20bf21ed457b390829cdbeec8795a7bea1626991fda603e0d01b4e7f60427e55") | ||
| testGPGHomeDirectory = "./testdata" |
There was a problem hiding this comment.
See the commit message about using separate GPG home directories.
There still is some flake that is fairly frequently triggered by two subpackages testing GPG concurrently, resulting in a signing operation failing with “end of file”. I haven’t tracked that one down. Short—term, I’d rather have a flake than an untested signing code, but that’s assuming the pain won’t be that big in CI.
|
@mtrmac is this still Draft? |
|
Yes, I want to have a testable Skopeo binary with the anticipated features before committing to an API. Notably the |
7bf6644 to
20a5503
Compare
|
Updated now:
I think this is ready for final review, marked as draft due to the #1779 dependency. |
Should not change behavior. Signed-off-by: Miloslav Trmač <mitr@redhat.com>
…teKeyFileUnstable ... instead of specifically signature.Sigstore. Should not change behavior, the only caller doesn't care. We will introduce an interface where we should allow creating all kinds of signature formats. Signed-off-by: Miloslav Trmač <mitr@redhat.com>
…Implementation Add a new user-visible type signature/signer.Signer; and internal internal/signer.Signer + internal/signer.SignerImplementation. The purpose is to create a completely opaque type that could be created by external callers, maintained for a time, passed to one or more copy.Image calls, and then destroyed, without exposing _any_ actual API to create signatures. We can, possibly, expose more later; for now, this opaque type will allow us to easily change the internal signing interface, while still allowing a fair bit of flexibility for external callers by giving them options when creating the Signer objects. Only adds new interfaces, does not change behavior. Signed-off-by: Miloslav Trmač <mitr@redhat.com>
... to contain the core, shared, signing code that can be augmented by optional Rekor and Fulcio dependencies. Only moves around the existing implementation, should not change behavior. Signed-off-by: Miloslav Trmač <mitr@redhat.com>
Then construct a single-purpose signer.Signer; we will expose it to users next. Should not change behavior. Signed-off-by: Miloslav Trmač <mitr@redhat.com>
This replaces NewSignerWithPrivateKeyFileUnstable, and can be extended to add more options in the future without having for all of them to be in the same subpackage (and all dependencies to be included). The WithPrivateKeyFile option could possibly be in its own subpackage, but because c/image/copy depends on it, that would not be likely to remove many dependencies. Signed-off-by: Miloslav Trmač <mitr@redhat.com>
... to match the object implemented in there. Signed-off-by: Miloslav Trmač <mitr@redhat.com>
This is a signer.Signer wrapper around the existing simple signing API, for consistency. It's just a wrapper which does not substantially change the GPG implementation approach; doing that might add more benefits (e.g. an immediate failure on an invalid key ID). That could possibly be improved in the future, for now the goal is only to migrate copy.Image to using a singer.Signer. To run tests, we need to introduce a _new_ GPG home directory, because (go test) runs tests in subpackages in parallel, and the tests in signature and signature/simple can interfere: a shared gpg-agent will be unlocked by one test and expected to be locked by another, causing spurious failures. So, this adds signature/simplesigning/testdata, but all the GPG files are symlinks to the original location. Signed-off-by: Miloslav Trmač <mitr@redhat.com>
…WithSigner They are no exactly identical (apart from one explicit .String() call). Should not change behavior. Signed-off-by: Miloslav Trmač <mitr@redhat.com>
Consolidate the format specifics and options handling to a single place, and let the rest deal with an undifferentiated list of Signers. This might be user-visible: failures e.g. on invalid key file path are now exposed immediately, instead of only after copying all the large layers. This is a step towards allowing callers to provide their own Signer objects. Signed-off-by: Miloslav Trmač <mitr@redhat.com>
Add copy.Options.Signers, so that callers can construct their own Signer objects and c/image/copy doesn't grow dependencies on all possible signature formats (notably on the Fulcio / Rekor RPC clients), and so that interactive initialization is easier. Signed-off-by: Miloslav Trmač <mitr@redhat.com>
In TestCreateSignatures, test just the identity and error handling here; full-scale testing that the images are signed and can be verified is better done in integration tests. Now that it is a bit easier, also test Options.Signers. Signed-off-by: Miloslav Trmač <mitr@redhat.com>
|
Rebased (with no changes), ready for merging. |
This adds a new, very opaque,
signer.Signertype, allowing users to construct it for the existing simple signing and sigstore implementations, and to pass them tocopy.Imageincopy.Options.Signers.The goal is to:
copy.Imagecalls (like inskopeo sync)copy.Imageon individual signing implementations:copy.Imagewon’t necessarily drag in all of the Rekor / Fulcio RPC infrastructure for specialized callers that don’t need it.Signerimplementations without having to mirror every single option in a newcopy.OptionsfieldThis is missing tests, and hasn’t actually been used for Fulcio / Rekor yet (compare extremely premature https://github.com/mtrmac/image/tree/fulcio-signing ); filing it early to discuss the API and general approach.
@vrothberg PTAL