Skip to content

Commit

Permalink
Merge branch 'cosign-sign' into cosign-integration
Browse files Browse the repository at this point in the history
  • Loading branch information
mtrmac committed Jul 6, 2022
2 parents 0989d8f + abc8aac commit fc4612a
Show file tree
Hide file tree
Showing 20 changed files with 1,682 additions and 137 deletions.
38 changes: 27 additions & 11 deletions copy/copy.go
Expand Up @@ -123,15 +123,17 @@ type ImageListSelection int

// Options allows supplying non-default configuration modifying the behavior of CopyImage.
type Options struct {
RemoveSignatures bool // Remove any pre-existing signatures. SignBy will still add a new signature.
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`.
SignIdentity reference.Named // Identify to use when signing, defaults to the docker reference of the destination
ReportWriter io.Writer
SourceCtx *types.SystemContext
DestinationCtx *types.SystemContext
ProgressInterval time.Duration // time to wait between reports to signal the progress channel
Progress chan types.ProgressProperties // Reported to when ProgressInterval has arrived for a single artifact+offset.
RemoveSignatures bool // Remove any pre-existing signatures. SignBy will still add a new signature.
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`.
SignIdentity reference.Named // Identify to use when signing, defaults to the docker reference of the destination
ReportWriter io.Writer
SourceCtx *types.SystemContext
DestinationCtx *types.SystemContext
ProgressInterval time.Duration // time to wait between reports to signal the progress channel
Progress chan types.ProgressProperties // Reported to when ProgressInterval has arrived for a single artifact+offset.

// Preserve digests, and fail if we cannot.
PreserveDigests bool
Expand Down Expand Up @@ -575,6 +577,13 @@ func (c *copier) copyMultipleImages(ctx context.Context, policyContext *signatur
}
sigs = append(sigs, newSig)
}
if options.SignByCosignPrivateKeyFile != "" {
newSig, err := c.createCosignSignature(manifestList, options.SignByCosignPrivateKeyFile, options.SignByCosignPrivateKeyPassphrase, options.SignIdentity)
if err != nil {
return nil, err
}
sigs = append(sigs, newSig)
}

c.Printf("Storing list signatures\n")
if err := c.dest.PutSignaturesWithFormat(ctx, sigs, nil); err != nil {
Expand Down Expand Up @@ -688,7 +697,7 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
// We do intend the RecordDigestUncompressedPair calls to only work with reliable data, but at least there’s a risk
// that the compressed version coming from a third party may be designed to attack some other decompressor implementation,
// and we would reuse and sign it.
ic.canSubstituteBlobs = ic.cannotModifyManifestReason == "" && options.SignBy == ""
ic.canSubstituteBlobs = ic.cannotModifyManifestReason == "" && options.SignBy == "" && options.SignByCosignPrivateKeyFile == ""

if err := ic.updateEmbeddedDockerReference(); err != nil {
return nil, "", "", err
Expand Down Expand Up @@ -719,7 +728,7 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli

// If enabled, fetch and compare the destination's manifest. And as an optimization skip updating the destination iff equal
if options.OptimizeDestinationImageAlreadyExists {
shouldUpdateSigs := len(sigs) > 0 || options.SignBy != "" // TODO: Consider allowing signatures updates only and skipping the image's layers/manifest copy if possible
shouldUpdateSigs := len(sigs) > 0 || options.SignBy != "" || options.SignByCosignPrivateKeyFile != "" // TODO: Consider allowing signatures updates only and skipping the image's layers/manifest copy if possible
noPendingManifestUpdates := ic.noPendingManifestUpdates()

logrus.Debugf("Checking if we can skip copying: has signatures=%t, OCI encryption=%t, no manifest updates=%t", shouldUpdateSigs, destRequiresOciEncryption, noPendingManifestUpdates)
Expand Down Expand Up @@ -806,6 +815,13 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
}
sigs = append(sigs, newSig)
}
if options.SignByCosignPrivateKeyFile != "" {
newSig, err := c.createCosignSignature(manifestBytes, options.SignByCosignPrivateKeyFile, options.SignByCosignPrivateKeyPassphrase, options.SignIdentity)
if err != nil {
return nil, "", "", err
}
sigs = append(sigs, newSig)
}

c.Printf("Storing signatures\n")
if err := c.dest.PutSignaturesWithFormat(ctx, sigs, targetInstance); err != nil {
Expand Down
22 changes: 22 additions & 0 deletions copy/sign.go
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/containers/image/v5/docker/reference"
internalsig "github.com/containers/image/v5/internal/signature"
"github.com/containers/image/v5/signature"
"github.com/containers/image/v5/signature/cosign"
"github.com/containers/image/v5/transports"
perrors "github.com/pkg/errors"
)
Expand Down Expand Up @@ -39,3 +40,24 @@ func (c *copier) createSignature(manifest []byte, keyIdentity string, passphrase
}
return internalsig.SimpleSigningFromBlob(newSig), nil
}

// createCosignSignature creates a new Cosign signature of manifest using privateKeyFile and identity.
func (c *copier) createCosignSignature(manifest []byte, privateKeyFile string, passphrase []byte, identity reference.Named) (internalsig.Signature, error) {
if identity != nil {
if reference.IsNameOnly(identity) {
return nil, fmt.Errorf("Sign identity must be a fully specified reference %s", identity.String())
}
} else {
identity = c.dest.Reference().DockerReference()
if identity == nil {
return nil, fmt.Errorf("Cannot determine canonical Docker reference for destination %s", transports.ImageName(c.dest.Reference()))
}
}

c.Printf("Signing manifest\n")
newSig, err := cosign.SignDockerManifestWithPrivateKeyFileUnstable(manifest, identity, privateKeyFile, passphrase)
if err != nil {
return nil, fmt.Errorf("creating signature: %w", err)
}
return newSig, nil
}
34 changes: 18 additions & 16 deletions go.mod
Expand Up @@ -18,28 +18,30 @@ require (
github.com/klauspost/pgzip v1.2.5
github.com/manifoldco/promptui v0.9.0
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.0.3-0.20211202193544-a5463b7f9c84
github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198
github.com/opencontainers/selinux v1.10.1
github.com/ostreedev/ostree-go v0.0.0-20210805093236-719684c64e4f
github.com/pkg/errors v0.9.1
github.com/proglottis/gpgme v0.1.3
github.com/sigstore/sigstore v1.3.1-0.20220629021053-b95fc0d626c1
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.8.0
github.com/sylabs/sif/v2 v2.7.1
github.com/theupdateframework/go-tuf v0.3.0
github.com/ulikunitz/xz v0.5.10
github.com/vbatts/tar-split v0.11.2
github.com/vbauerster/mpb/v7 v7.4.2
github.com/xeipuuv/gojsonschema v1.2.0
go.etcd.io/bbolt v1.3.6
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211

)

require (
github.com/14rcole/gopopulate v0.0.0-20180821133914-b175b219e774 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/Microsoft/hcsshim v0.9.2 // indirect
github.com/VividCortex/ewma v1.2.0 // indirect
Expand All @@ -57,43 +59,43 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-containerregistry v0.10.0 // indirect
github.com/google/go-intervals v0.0.2 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/mux v1.7.4 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/letsencrypt/boulder v0.0.0-20220331220046-b23ab962616e // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/mattn/go-shellwords v1.0.12 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/miekg/pkcs11 v1.1.1 // indirect
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible // indirect
github.com/moby/sys/mountinfo v0.6.1 // indirect
github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/opencontainers/runc v1.1.2 // indirect
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.11.0 // indirect
github.com/prometheus/client_golang v1.12.1 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.30.0 // indirect
github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980 // indirect
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect
github.com/tchap/go-patricia v2.3.0+incompatible // indirect
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1 // indirect
go.opencensus.io v0.23.0 // indirect
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
golang.org/x/sys v0.0.0-20220624220833-87e55d714810 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8 // indirect
google.golang.org/grpc v1.44.0 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/square/go-jose.v2 v2.5.1 // indirect
google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f // indirect
google.golang.org/grpc v1.47.0 // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

0 comments on commit fc4612a

Please sign in to comment.