Skip to content
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

DO NOT MERGE IRRESPONSIBLE: Cosign integration #1599

Closed
wants to merge 21 commits into from

Conversation

mtrmac
Copy link
Collaborator

@mtrmac mtrmac commented Jul 6, 2022

This is a single integration branch of the Cosign prototypes.

💀💀💀DO NOT MERGE THIS WITHOUT ADDING TEST COVERAGE

See #1598.


(Outstanding) merge/review order:

copy/copy.go Outdated
SignBy string // If non-empty, asks for a signature to be added during the copy, and specifies a key ID, as accepted by signature.NewGPGSigningMechanism().SignDockerManifest(),
SignPassphrase string // Passphare to use when signing with the key ID from `SignBy`.
SignByCosignPrivateKeyFile string // If non-empty, asks for a signature to be added during the copy, using a Cosign private key file at the provided path.
SignByCosignPrivateKeyPassphrase []byte // Passphare to use when signing with `SignByCosignPrivateKeyFile`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
SignByCosignPrivateKeyPassphrase []byte // Passphare to use when signing with `SignByCosignPrivateKeyFile`.
SignCosignPrivateKeyPassphrase []byte // Passphare to use when signing with `SignByCosignPrivateKeyFile`.

Just to be consistent with SignBy and SignPassphrase

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in #1597 .

@@ -596,6 +637,125 @@ func (d *dockerImageDestination) putOneSignature(url *url.URL, signature []byte)
}
}

func (d *dockerImageDestination) putSignaturesToCosignAttachments(ctx context.Context, signatures []signature.Cosign, manifestDigest digest.Digest) error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it could be useful to add some (debug) logs and status on the report writer.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug logs added in #1595 .

We can add a report writer, or progress bar updates, with the new private interfaces; that would require a bit of new interfaces / infrastructure.

if err != nil {
return err
}
sigDesc.Annotations = sig.UntrustedAnnotations
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that using sig is dangerous. If there are multiple signatures, wouldn't all users of UntrustedAnnotations point to the field of the last item in the slice?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fresher eyes after my lunch break are not concerned anymore. Only pointers to members of the loop variable are dangerous.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nevertheless, doing more explicit copies when creating/consuming signatures would be worth the peace of mind.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As of updated #1595 , signature objects are only accessible via copying constructors and copying getters.

}

sigDesc, err := d.putBlobBytesAsOCI(ctx, sig.UntrustedPayload, sig.UntrustedMIMEType, private.PutBlobOptions{
Cache: none.NoCache, // FIXME: Pass BlobInfoCache to signature accessors? Or is this just pointless noise??
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mtrmac, do you think the blob cache could speed things up?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those FIXMEs are because I just wasn’t ready to deal with that interface change at that time either way. We could pass that.

Looking at it more, the info cache (which is what the above is) is useful for:

  • compressed/uncompressed correspondence. Irrelevant because we are not changing that for signatures, and a signature payload is not likely to match a “real” layer.
  • TryReusingBlob*, where we are consuming the cache (the call from PutBlob* is write only). And it doesn’t even make much sense — I’d naively, without measurement, expect most of the cost of dealing with these small blobs to be the round-trips, so any extra round-trips checking for blobs to mount instead of just writing them are likely to make things worse.

So none.NoCache might be the right thing to do here anyway: At least with the current attachment implementation, we would just be adding entries (which we never delete) and growing the database for no benefit.


WRT the blob data cache, note that it is write-through; if attached to a destination, it writes the data to local storage in addition to writing them to a destination. So that’s not making writes any faster. The blob cache helps on reads, and that might be somewhat significant here if network reads are slower than disk reads (which is reportedly not always the case…). So… how often does one pull an image after pushing it? If it happens frequently, I’d expect the image to already be in c/storage (… and, true, we do a copy with most of the round-trips anyway…) In that case I think teaching the copy code not to copy an already-existing image (or just already-existing signatures?) would be better than the blob cache, because c/storage has delete operations and is under better user control.


In general, it is a bit of a concern that working with the cosign attachments is round-trip heavy (though not much heavier than a https:// look-side). We might eventually want to worry about optimizing out individual redundant attachment copies, especially if some of them could grow quite large (SBOMs? I have never seen one in the wild). And, potentially much worse, we might need to stream the attachment payloads instead of just reading them into memory.

I think we can deal later with that if it ever shows up as an user-reported issue. The new …WithFormat API shows we have the conceptual flexibility.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced the FIXMEs with comments in #1595 .

}

for _, sig := range signatures {
found := false
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: can we rename found to something similar to alreadyOnRegistry? It adds some more context that would help me brain-parse the code.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in #1595 .

}
sigDesc.Annotations = sig.UntrustedAnnotations
ociManifest.Layers = append(ociManifest.Layers, sigDesc)
ociConfig.RootFS.DiffIDs = append(ociConfig.RootFS.DiffIDs, sigDesc.Digest)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the diff IDs needed? I couldn't find something in the cosign spec but recall that cosign just ships an empty config.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t know.

It’s quite possible they aren’t needed. I also thought cosign ships a completely empty config, but when looking what to write into that config, I found DiffID entries in a Cosign-generated file. That might be a go-containerregistry artifact, the API has concepts like “add a layer” which adds it both to the manifest and to DiffIDs.

At least distribution/distribution seems not to care, except if the client is schema1-only.

Historically Quay has been the registry with the strictest validation we’ve been hearing about, I have no idea what they do.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for checking!

I also suspect go-containerregistry to be the source. I am totally fine to add the DiffIDs.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It’s a good thing to point out and to track — if we don’t need to add DiffIDs, we would eliminate a blob write for the config on every copy that adds signatures to an existing image with signatures.

@mtrmac mtrmac force-pushed the cosign-integration branch 2 times, most recently from 6a7bbad to 6a1b669 Compare July 6, 2022 16:23
mtrmac added 20 commits July 7, 2022 13:47
Currently, this just allows serializing and deserializing
it as a blob.

NOTE: This makes an implementation decision about the blob format:
we use OpenPGP signatures with no marker, any new formats will
start with a zero byte and an ASCII line identifying the format of the rest.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
It's not actually dealing with the lookaside; just with the configuration.
And we are going to introduce more configuration.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
…rageBaseURL

This will allow us to only load the configuration once.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
This will allow us to load the configuration and then ask
for multiple items.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
This is a bit more repetitive in most callers.  The benefit is
that we only read the files once per newImageSource, even if there
are multiple mirrors.

We will also read more items from the config.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
... so that users can choose whether to do the extra
manifest lookups, and record signatures.

NOTE: This defaults to false.

FIXME: Documentation

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
…t.fetchManifest

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
We need it for writing signatures.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
We are going to need a way to upload to a tag without affecting
dockerImageDestination.manifestDigest.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
NOTE design decisions:
- We can read Cosign data from lookaside
- We ONLY write Cosign data to Cosign attachments, never
  to lookaside; because lookaside is set up by default, that
  would be too confusing.
- We ONLY use Cosign attachments at all if the user opts in
  via registries.d.

  One concern is performance impact of the extra round-trip
  for large-scale operations like (skopeo sync).

  Short-term, a much more worrying is the risk that we probably
  have the "is this failure just a missing atachment manifest,
  or a real failure reading it?" heuristic wrong, so without an
  opt-in, _all_ image reads are going to fail.  This might eventually
  go away after more testing.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
Private key only, no Fulcio/Rekor.

The extra dependencies are not ideal, but not too bad
(notably the scary go-tuf addition is only a small subpackage), looking only
at files added in new subpackage, not additions caused by updates of existing dependencies:

 vendor/github.com/golang/protobuf/jsonpb/decode.go                                   |  524 ++++++++++++++++
 vendor/github.com/golang/protobuf/jsonpb/encode.go                                   |  559 ++++++++++++++++++
 vendor/github.com/golang/protobuf/jsonpb/json.go                                     |   69 +++
 vendor/github.com/google/go-containerregistry/LICENSE                                |  202 +++++++
 vendor/github.com/google/go-containerregistry/pkg/name/README.md                     |    3 +
 vendor/github.com/google/go-containerregistry/pkg/name/check.go                      |   43 ++
 vendor/github.com/google/go-containerregistry/pkg/name/digest.go                     |   96 +++
 vendor/github.com/google/go-containerregistry/pkg/name/doc.go                        |   42 ++
 vendor/github.com/google/go-containerregistry/pkg/name/errors.go                     |   42 ++
 vendor/github.com/google/go-containerregistry/pkg/name/options.go                    |   83 +++
 vendor/github.com/google/go-containerregistry/pkg/name/ref.go                        |   75 +++
 vendor/github.com/google/go-containerregistry/pkg/name/registry.go                   |  136 +++++
 vendor/github.com/google/go-containerregistry/pkg/name/repository.go                 |  121 ++++
 vendor/github.com/google/go-containerregistry/pkg/name/tag.go                        |  108 ++++
 vendor/github.com/letsencrypt/boulder/LICENSE.txt                                    |  375 ++++++++++++
 vendor/github.com/letsencrypt/boulder/core/challenges.go                             |   27 +
 vendor/github.com/letsencrypt/boulder/core/interfaces.go                             |   14 +
 vendor/github.com/letsencrypt/boulder/core/objects.go                                |  536 +++++++++++++++++
 vendor/github.com/letsencrypt/boulder/core/proto/core.pb.go                          | 1100 ++++++++++++++++++++++++++++++++++
 vendor/github.com/letsencrypt/boulder/core/proto/core.proto                          |   95 +++
 vendor/github.com/letsencrypt/boulder/core/util.go                                   |  298 ++++++++++
 vendor/github.com/letsencrypt/boulder/errors/errors.go                               |  150 +++++
 vendor/github.com/letsencrypt/boulder/features/featureflag_string.go                 |   45 ++
 vendor/github.com/letsencrypt/boulder/features/features.go                           |  158 +++++
 vendor/github.com/letsencrypt/boulder/goodkey/blocked.go                             |   98 +++
 vendor/github.com/letsencrypt/boulder/goodkey/good_key.go                            |  432 ++++++++++++++
 vendor/github.com/letsencrypt/boulder/goodkey/weak.go                                |   66 +++
 vendor/github.com/letsencrypt/boulder/identifier/identifier.go                       |   32 +
 vendor/github.com/letsencrypt/boulder/probs/probs.go                                 |  349 +++++++++++
 vendor/github.com/letsencrypt/boulder/revocation/reasons.go                          |   74 +++
 vendor/github.com/letsencrypt/boulder/sa/proto/sa.pb.go                              | 3449 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 vendor/github.com/letsencrypt/boulder/sa/proto/sa.proto                              |  272 +++++++++
 vendor/github.com/letsencrypt/boulder/sa/proto/sa_grpc.pb.go                         | 1515 +++++++++++++++++++++++++++++++++++++++++++++++
 vendor/github.com/letsencrypt/boulder/sa/proto/subsets.go                            |   46 ++
 vendor/github.com/sigstore/sigstore/COPYRIGHT.txt                                    |   14 +
 vendor/github.com/sigstore/sigstore/LICENSE                                          |  202 +++++++
 vendor/github.com/sigstore/sigstore/pkg/cryptoutils/certificate.go                   |  170 ++++++
 vendor/github.com/sigstore/sigstore/pkg/cryptoutils/generic.go                       |   31 +
 vendor/github.com/sigstore/sigstore/pkg/cryptoutils/password.go                      |   96 +++
 vendor/github.com/sigstore/sigstore/pkg/cryptoutils/privatekey.go                    |  144 +++++
 vendor/github.com/sigstore/sigstore/pkg/cryptoutils/publickey.go                     |  174 ++++++
 vendor/github.com/sigstore/sigstore/pkg/signature/doc.go                             |   17 +
 vendor/github.com/sigstore/sigstore/pkg/signature/ecdsa.go                           |  244 ++++++++
 vendor/github.com/sigstore/sigstore/pkg/signature/ed25519.go                         |  197 ++++++
 vendor/github.com/sigstore/sigstore/pkg/signature/message.go                         |  111 ++++
 vendor/github.com/sigstore/sigstore/pkg/signature/options.go                         |   57 ++
 vendor/github.com/sigstore/sigstore/pkg/signature/options/context.go                 |   36 ++
 vendor/github.com/sigstore/sigstore/pkg/signature/options/digest.go                  |   35 ++
 vendor/github.com/sigstore/sigstore/pkg/signature/options/keyversion.go              |   50 ++
 vendor/github.com/sigstore/sigstore/pkg/signature/options/noop.go                    |   49 ++
 vendor/github.com/sigstore/sigstore/pkg/signature/options/rand.go                    |   41 ++
 vendor/github.com/sigstore/sigstore/pkg/signature/options/remoteverification.go      |   32 +
 vendor/github.com/sigstore/sigstore/pkg/signature/options/rpcauth.go                 |   58 ++
 vendor/github.com/sigstore/sigstore/pkg/signature/options/signeropts.go              |   40 ++
 vendor/github.com/sigstore/sigstore/pkg/signature/payload/payload.go                 |  104 ++++
 vendor/github.com/sigstore/sigstore/pkg/signature/publickey.go                       |   25 +
 vendor/github.com/sigstore/sigstore/pkg/signature/rsapkcs1v15.go                     |  225 +++++++
 vendor/github.com/sigstore/sigstore/pkg/signature/rsapss.go                          |  260 ++++++++
 vendor/github.com/sigstore/sigstore/pkg/signature/signer.go                          |   89 +++
 vendor/github.com/sigstore/sigstore/pkg/signature/signerverifier.go                  |   69 +++
 vendor/github.com/sigstore/sigstore/pkg/signature/util.go                            |   55 ++
 vendor/github.com/sigstore/sigstore/pkg/signature/verifier.go                        |  100 ++++
 vendor/github.com/theupdateframework/go-tuf/LICENSE                                  |   27 +
 vendor/github.com/theupdateframework/go-tuf/encrypted/encrypted.go                   |  226 +++++++
 vendor/github.com/titanous/rocacheck/LICENSE                                         |   22 +
 vendor/github.com/titanous/rocacheck/README.md                                       |    7 +
 vendor/github.com/titanous/rocacheck/rocacheck.go                                    |   52 ++
 vendor/golang.org/x/crypto/internal/poly1305/bits_compat.go                          |   40 ++
 vendor/golang.org/x/crypto/internal/poly1305/bits_go1.13.go                          |   22 +
 vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go                            |   10 +
 vendor/golang.org/x/crypto/internal/poly1305/poly1305.go                             |   99 ++++
 vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.go                            |   48 ++
 vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s                             |  109 ++++
 vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go                          |  310 ++++++++++
 vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go                          |   48 ++
 vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s                           |  182 ++++++
 vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.go                            |   76 +++
 vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.s                             |  504 ++++++++++++++++
 vendor/golang.org/x/crypto/internal/subtle/aliasing.go                               |   33 ++
 vendor/golang.org/x/crypto/internal/subtle/aliasing_purego.go                        |   36 ++
 vendor/golang.org/x/crypto/nacl/secretbox/secretbox.go                               |  173 ++++++
 vendor/golang.org/x/crypto/ocsp/ocsp.go                                              |  789 +++++++++++++++++++++++++
 vendor/golang.org/x/crypto/salsa20/salsa/hsalsa20.go                                 |  144 +++++
 vendor/golang.org/x/crypto/salsa20/salsa/salsa208.go                                 |  199 +++++++
 vendor/golang.org/x/crypto/salsa20/salsa/salsa20_amd64.go                            |   24 +
 vendor/golang.org/x/crypto/salsa20/salsa/salsa20_amd64.s                             |  881 +++++++++++++++++++++++++++
 vendor/golang.org/x/crypto/salsa20/salsa/salsa20_noasm.go                            |   15 +
 vendor/golang.org/x/crypto/salsa20/salsa/salsa20_ref.go                              |  231 ++++++++
 vendor/golang.org/x/crypto/scrypt/scrypt.go                                          |  212 +++++++
 vendor/golang.org/x/crypto/sha3/doc.go                                               |   66 +++
 vendor/golang.org/x/crypto/sha3/hashes.go                                            |   97 +++
 vendor/golang.org/x/crypto/sha3/hashes_generic.go                                    |   28 +
 vendor/golang.org/x/crypto/sha3/keccakf.go                                           |  413 +++++++++++++
 vendor/golang.org/x/crypto/sha3/keccakf_amd64.go                                     |   14 +
 vendor/golang.org/x/crypto/sha3/keccakf_amd64.s                                      |  391 ++++++++++++
 vendor/golang.org/x/crypto/sha3/register.go                                          |   19 +
 vendor/golang.org/x/crypto/sha3/sha3.go                                              |  193 ++++++
 vendor/golang.org/x/crypto/sha3/sha3_s390x.go                                        |  285 +++++++++
 vendor/golang.org/x/crypto/sha3/sha3_s390x.s                                         |   34 ++
 vendor/golang.org/x/crypto/sha3/shake.go                                             |  173 ++++++
 vendor/golang.org/x/crypto/sha3/shake_generic.go                                     |   20 +
 vendor/golang.org/x/crypto/sha3/xor.go                                               |   24 +
 vendor/golang.org/x/crypto/sha3/xor_generic.go                                       |   28 +
 vendor/golang.org/x/crypto/sha3/xor_unaligned.go                                     |   68 +++
 vendor/google.golang.org/grpc/channelz/channelz.go                                   |   36 ++
 vendor/google.golang.org/grpc/internal/balancer/gracefulswitch/gracefulswitch.go     |  382 ++++++++++++
 vendor/google.golang.org/grpc/internal/pretty/pretty.go                              |   82 +++
 vendor/google.golang.org/protobuf/encoding/protojson/decode.go                       |  665 +++++++++++++++++++++
 vendor/google.golang.org/protobuf/encoding/protojson/doc.go                          |   11 +
 vendor/google.golang.org/protobuf/encoding/protojson/encode.go                       |  344 +++++++++++
 vendor/google.golang.org/protobuf/encoding/protojson/well_known_types.go             |  889 ++++++++++++++++++++++++++++
 vendor/google.golang.org/protobuf/internal/encoding/json/decode.go                   |  340 +++++++++++
 vendor/google.golang.org/protobuf/internal/encoding/json/decode_number.go            |  254 ++++++++
 vendor/google.golang.org/protobuf/internal/encoding/json/decode_string.go            |   91 +++
 vendor/google.golang.org/protobuf/internal/encoding/json/decode_token.go             |  192 ++++++
 vendor/google.golang.org/protobuf/internal/encoding/json/encode.go                   |  276 +++++++++
 vendor/google.golang.org/protobuf/types/known/emptypb/empty.pb.go                    |  168 ++++++

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
THIS MUST HAVE TOTAL CODE COVERAGE.

type: cosignSigned, with the usual keyData/keyPath.
Fulcio/Rekor is plausible _for the off-line rekor
log entry proofs_, but not currently implemented. Tests first.

NOTE: This only allows a single public key, not a keyring,
unlike simple signing. That seems problematic, there are
known users of that. But we can fix that later by adding
keyDirectory and the like.

FIXME: Update documentation of policy.json.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
@mtrmac
Copy link
Collaborator Author

mtrmac commented Jul 7, 2022

There is now just one outstanding PR - #1598 , so closing this.

Outstanding unfinished tasks and the like are tracked in #1601.

@mtrmac mtrmac closed this Jul 7, 2022
@mtrmac mtrmac deleted the cosign-integration branch July 7, 2022 16:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants