mirror of
https://github.com/containers/podman.git
synced 2025-08-06 19:44:14 +08:00
Merge pull request #7718 from QiWang19/sign-multi-arch
Sign multi-arch images
This commit is contained in:
@ -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 {
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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())
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user