Merge pull request #7718 from QiWang19/sign-multi-arch

Sign multi-arch images
This commit is contained in:
OpenShift Merge Robot
2020-12-12 03:46:31 -05:00
committed by GitHub
5 changed files with 70 additions and 23 deletions

View File

@ -47,6 +47,7 @@ func init() {
certDirFlagName := "cert-dir" certDirFlagName := "cert-dir"
flags.StringVar(&signOptions.CertDir, certDirFlagName, "", "`Pathname` of a directory containing TLS certificates and keys") flags.StringVar(&signOptions.CertDir, certDirFlagName, "", "`Pathname` of a directory containing TLS certificates and keys")
_ = signCommand.RegisterFlagCompletionFunc(certDirFlagName, completion.AutocompleteDefault) _ = 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 { func sign(cmd *cobra.Command, args []string) error {

View File

@ -19,6 +19,10 @@ By default, the signature will be written into `/var/lib/containers/sigstore` fo
Print usage statement. Print usage statement.
#### **--all**, **-a**
Sign all the manifests of the multi-architecture image (default false).
#### **--cert-dir**=*path* #### **--cert-dir**=*path*
Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry. Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry.

View File

@ -344,6 +344,7 @@ type SignOptions struct {
Directory string Directory string
SignBy string SignBy string
CertDir string CertDir string
All bool
} }
// SignReport describes the result of signing // SignReport describes the result of signing

View File

@ -28,6 +28,8 @@ import (
"github.com/containers/podman/v2/pkg/rootless" "github.com/containers/podman/v2/pkg/rootless"
"github.com/containers/podman/v2/pkg/util" "github.com/containers/podman/v2/pkg/util"
"github.com/containers/storage" "github.com/containers/storage"
dockerRef "github.com/docker/distribution/reference"
"github.com/opencontainers/go-digest"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1" imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -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) 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 { if err != nil {
return errors.Wrapf(err, "error getting getManifest") return errors.Wrapf(err, "error getting manifest blob")
} }
dockerReference := rawSource.Reference().DockerReference() dockerReference := rawSource.Reference().DockerReference()
if dockerReference == nil { if dockerReference == nil {
@ -743,34 +745,34 @@ func (ir *ImageEngine) Sign(ctx context.Context, names []string, options entitie
return err return err
} }
} }
manifestDigest, err := manifest.Digest(getManifest) manifestDigest, err := manifest.Digest(topManifestBlob)
if err != nil { if err != nil {
return err return err
} }
// create signature if options.All {
newSig, err := signature.SignDockerManifest(getManifest, dockerReference.String(), mech, options.SignBy) if !manifest.MIMETypeIsMultiImage(manifestType) {
if err != nil { return errors.Errorf("%s is not a multi-architecture image (manifest type %s)", signimage, manifestType)
return errors.Wrapf(err, "error creating new signature") }
} list, err := manifest.ListFromBlob(topManifestBlob, manifestType)
// create the signstore file if err != nil {
signatureDir := fmt.Sprintf("%s@%s=%s", sigStoreDir, manifestDigest.Algorithm(), manifestDigest.Hex()) return errors.Wrapf(err, "Error parsing manifest list %q", string(topManifestBlob))
if err := os.MkdirAll(signatureDir, 0751); err != nil { }
// The directory is allowed to exist instanceDigests := list.Instances()
if !os.IsExist(err) { for _, instanceDigest := range instanceDigests {
logrus.Error(err) digest := instanceDigest
return nil 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 return nil
} }
err = ioutil.WriteFile(filepath.Join(signatureDir, sigFilename), newSig, 0644) if err = putSignature(topManifestBlob, mech, sigStoreDir, manifestDigest, dockerReference, options); err != nil {
if err != nil { return errors.Wrapf(err, "error storing signature for %s, %v", dockerReference.String(), manifestDigest)
logrus.Errorf("error storing signature for %s", rawSource.Reference().DockerReference().String())
return nil
} }
return nil return nil
}() }()
@ -806,3 +808,26 @@ func localPathFromURI(url *url.URL) (string, error) {
} }
return url.Path, nil 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
}

View File

@ -1,6 +1,7 @@
package integration package integration
import ( import (
"io/ioutil"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
@ -58,4 +59,19 @@ var _ = Describe("Podman image sign", func() {
_, err = os.Stat(filepath.Join(sigDir, "library")) _, err = os.Stat(filepath.Join(sigDir, "library"))
Expect(err).To(BeNil()) 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", "foo@bar.com", "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())
})
}) })