Skip to content

Commit

Permalink
Merge pull request #7718 from QiWang19/sign-multi-arch
Browse files Browse the repository at this point in the history
Sign multi-arch images
  • Loading branch information
openshift-merge-robot authored Dec 12, 2020
2 parents 1d50245 + 6730556 commit 36bec38
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 23 deletions.
1 change: 1 addition & 0 deletions cmd/podman/images/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ func init() {
certDirFlagName := "cert-dir"
flags.StringVar(&signOptions.CertDir, certDirFlagName, "", "`Pathname` of a directory containing TLS certificates and keys")
_ = signCommand.RegisterFlagCompletionFunc(certDirFlagName, completion.AutocompleteDefault)
flags.BoolVarP(&signOptions.All, "all", "a", false, "Sign all the manifests of the multi-architecture image")
}

func sign(cmd *cobra.Command, args []string) error {
Expand Down
4 changes: 4 additions & 0 deletions docs/source/markdown/podman-image-sign.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ By default, the signature will be written into `/var/lib/containers/sigstore` fo

Print usage statement.

#### **--all**, **-a**

Sign all the manifests of the multi-architecture image (default false).

#### **--cert-dir**=*path*

Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry.
Expand Down
1 change: 1 addition & 0 deletions pkg/domain/entities/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ type SignOptions struct {
Directory string
SignBy string
CertDir string
All bool
}

// SignReport describes the result of signing
Expand Down
71 changes: 48 additions & 23 deletions pkg/domain/infra/abi/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import (
"github.com/containers/podman/v2/pkg/rootless"
"github.com/containers/podman/v2/pkg/util"
"github.com/containers/storage"
dockerRef "github.com/docker/distribution/reference"
"github.com/opencontainers/go-digest"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -718,9 +720,9 @@ func (ir *ImageEngine) Sign(ctx context.Context, names []string, options entitie
logrus.Errorf("unable to close %s image source %q", srcRef.DockerReference().Name(), err)
}
}()
getManifest, _, err := rawSource.GetManifest(ctx, nil)
topManifestBlob, manifestType, err := rawSource.GetManifest(ctx, nil)
if err != nil {
return errors.Wrapf(err, "error getting getManifest")
return errors.Wrapf(err, "error getting manifest blob")
}
dockerReference := rawSource.Reference().DockerReference()
if dockerReference == nil {
Expand All @@ -743,34 +745,34 @@ func (ir *ImageEngine) Sign(ctx context.Context, names []string, options entitie
return err
}
}
manifestDigest, err := manifest.Digest(getManifest)
manifestDigest, err := manifest.Digest(topManifestBlob)
if err != nil {
return err
}

// create signature
newSig, err := signature.SignDockerManifest(getManifest, dockerReference.String(), mech, options.SignBy)
if err != nil {
return errors.Wrapf(err, "error creating new signature")
}
// create the signstore file
signatureDir := fmt.Sprintf("%s@%s=%s", sigStoreDir, manifestDigest.Algorithm(), manifestDigest.Hex())
if err := os.MkdirAll(signatureDir, 0751); err != nil {
// The directory is allowed to exist
if !os.IsExist(err) {
logrus.Error(err)
return nil
if options.All {
if !manifest.MIMETypeIsMultiImage(manifestType) {
return errors.Errorf("%s is not a multi-architecture image (manifest type %s)", signimage, manifestType)
}
list, err := manifest.ListFromBlob(topManifestBlob, manifestType)
if err != nil {
return errors.Wrapf(err, "Error parsing manifest list %q", string(topManifestBlob))
}
instanceDigests := list.Instances()
for _, instanceDigest := range instanceDigests {
digest := instanceDigest
man, _, err := rawSource.GetManifest(ctx, &digest)
if err != nil {
return err
}
if err = putSignature(man, mech, sigStoreDir, instanceDigest, dockerReference, options); err != nil {
return errors.Wrapf(err, "error storing signature for %s, %v", dockerReference.String(), instanceDigest)
}
}
}
sigFilename, err := getSigFilename(signatureDir)
if err != nil {
logrus.Errorf("error creating sigstore file: %v", err)
return nil
}
err = ioutil.WriteFile(filepath.Join(signatureDir, sigFilename), newSig, 0644)
if err != nil {
logrus.Errorf("error storing signature for %s", rawSource.Reference().DockerReference().String())
return nil
if err = putSignature(topManifestBlob, mech, sigStoreDir, manifestDigest, dockerReference, options); err != nil {
return errors.Wrapf(err, "error storing signature for %s, %v", dockerReference.String(), manifestDigest)
}
return nil
}()
Expand Down Expand Up @@ -806,3 +808,26 @@ func localPathFromURI(url *url.URL) (string, error) {
}
return url.Path, nil
}

// putSignature creates signature and saves it to the signstore file
func putSignature(manifestBlob []byte, mech signature.SigningMechanism, sigStoreDir string, instanceDigest digest.Digest, dockerReference dockerRef.Reference, options entities.SignOptions) error {
newSig, err := signature.SignDockerManifest(manifestBlob, dockerReference.String(), mech, options.SignBy)
if err != nil {
return err
}
signatureDir := fmt.Sprintf("%s@%s=%s", sigStoreDir, instanceDigest.Algorithm(), instanceDigest.Hex())
if err := os.MkdirAll(signatureDir, 0751); err != nil {
// The directory is allowed to exist
if !os.IsExist(err) {
return err
}
}
sigFilename, err := getSigFilename(signatureDir)
if err != nil {
return err
}
if err = ioutil.WriteFile(filepath.Join(signatureDir, sigFilename), newSig, 0644); err != nil {
return err
}
return nil
}
16 changes: 16 additions & 0 deletions test/e2e/image_sign_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package integration

import (
"io/ioutil"
"os"
"os/exec"
"path/filepath"
Expand Down Expand Up @@ -58,4 +59,19 @@ var _ = Describe("Podman image sign", func() {
_, err = os.Stat(filepath.Join(sigDir, "library"))
Expect(err).To(BeNil())
})

It("podman sign --all multi-arch image", func() {
cmd := exec.Command("gpg", "--import", "sign/secret-key.asc")
err := cmd.Run()
Expect(err).To(BeNil())
sigDir := filepath.Join(podmanTest.TempDir, "test-sign-multi")
err = os.MkdirAll(sigDir, os.ModePerm)
Expect(err).To(BeNil())
session := podmanTest.Podman([]string{"image", "sign", "--all", "--directory", sigDir, "--sign-by", "[email protected]", "docker://library/alpine"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
fInfos, err := ioutil.ReadDir(filepath.Join(sigDir, "library"))
Expect(err).To(BeNil())
Expect(len(fInfos) > 1).To(BeTrue())
})
})

0 comments on commit 36bec38

Please sign in to comment.