summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libpod/image/image.go8
-rw-r--r--pkg/api/handlers/compat/images.go4
-rw-r--r--pkg/api/handlers/libpod/images.go3
-rw-r--r--pkg/domain/entities/images.go2
-rw-r--r--pkg/domain/infra/abi/images.go4
-rw-r--r--pkg/varlinkapi/images.go2
-rw-r--r--test/e2e/save_test.go69
-rw-r--r--test/e2e/sign/key.gpg30
-rw-r--r--test/e2e/sign/policy.json18
9 files changed, 130 insertions, 10 deletions
diff --git a/libpod/image/image.go b/libpod/image/image.go
index 0900944eb..62c6a2088 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -177,7 +177,7 @@ func (ir *Runtime) New(ctx context.Context, name, signaturePolicyPath, authfile
// SaveImages stores one more images in a multi-image archive.
// Note that only `docker-archive` supports storing multiple
// image.
-func (ir *Runtime) SaveImages(ctx context.Context, namesOrIDs []string, format string, outputFile string, quiet bool) (finalErr error) {
+func (ir *Runtime) SaveImages(ctx context.Context, namesOrIDs []string, format string, outputFile string, quiet, removeSignatures bool) (finalErr error) {
if format != DockerArchive {
return errors.Errorf("multi-image archives are only supported in in the %q format", DockerArchive)
}
@@ -264,7 +264,7 @@ func (ir *Runtime) SaveImages(ctx context.Context, namesOrIDs []string, format s
}
img := imageMap[id]
- copyOptions := getCopyOptions(sys, writer, nil, nil, SigningOptions{}, "", img.tags)
+ copyOptions := getCopyOptions(sys, writer, nil, nil, SigningOptions{RemoveSignatures: removeSignatures}, "", img.tags)
copyOptions.DestinationCtx.SystemRegistriesConfPath = registries.SystemRegistriesConfPath()
// For copying, we need a source reference that we can create
@@ -1584,7 +1584,7 @@ func (i *Image) Comment(ctx context.Context, manifestType string) (string, error
}
// Save writes a container image to the filesystem
-func (i *Image) Save(ctx context.Context, source, format, output string, moreTags []string, quiet, compress bool) error {
+func (i *Image) Save(ctx context.Context, source, format, output string, moreTags []string, quiet, compress, removeSignatures bool) error {
var (
writer io.Writer
destRef types.ImageReference
@@ -1636,7 +1636,7 @@ func (i *Image) Save(ctx context.Context, source, format, output string, moreTag
return err
}
}
- if err := i.PushImageToReference(ctx, destRef, manifestType, "", "", "", writer, compress, SigningOptions{}, &DockerRegistryOptions{}, additionaltags); err != nil {
+ if err := i.PushImageToReference(ctx, destRef, manifestType, "", "", "", writer, compress, SigningOptions{RemoveSignatures: removeSignatures}, &DockerRegistryOptions{}, additionaltags); err != nil {
return errors.Wrapf(err, "unable to save %q", source)
}
i.newImageEvent(events.Save)
diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go
index 3431823bd..d177b2335 100644
--- a/pkg/api/handlers/compat/images.go
+++ b/pkg/api/handlers/compat/images.go
@@ -60,7 +60,7 @@ func ExportImage(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to close tempfile"))
return
}
- if err := newImage.Save(r.Context(), name, "docker-archive", tmpfile.Name(), []string{}, false, false); err != nil {
+ if err := newImage.Save(r.Context(), name, "docker-archive", tmpfile.Name(), []string{}, false, false, true); err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to save image"))
return
}
@@ -429,7 +429,7 @@ func ExportImages(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to close tempfile"))
return
}
- if err := runtime.ImageRuntime().SaveImages(r.Context(), images, "docker-archive", tmpfile.Name(), false); err != nil {
+ if err := runtime.ImageRuntime().SaveImages(r.Context(), images, "docker-archive", tmpfile.Name(), false, true); err != nil {
utils.InternalServerError(w, err)
return
}
diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go
index 3fb5d23c8..598a46abe 100644
--- a/pkg/api/handlers/libpod/images.go
+++ b/pkg/api/handlers/libpod/images.go
@@ -206,7 +206,7 @@ func ExportImage(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "unknown format", http.StatusInternalServerError, errors.Errorf("unknown format %q", query.Format))
return
}
- if err := newImage.Save(r.Context(), name, query.Format, output, []string{}, false, query.Compress); err != nil {
+ if err := newImage.Save(r.Context(), name, query.Format, output, []string{}, false, query.Compress, true); err != nil {
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, err)
return
}
@@ -284,6 +284,7 @@ func ExportImages(w http.ResponseWriter, r *http.Request) {
Format: query.Format,
MultiImageArchive: true,
Output: output,
+ RemoveSignatures: true,
}
imageEngine := abi.ImageEngine{Libpod: runtime}
diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go
index 982fa0cc0..101542a98 100644
--- a/pkg/domain/entities/images.go
+++ b/pkg/domain/entities/images.go
@@ -300,6 +300,8 @@ type ImageSaveOptions struct {
MultiImageArchive bool
// Output - write image to the specified path.
Output string
+ // Do not save the signature from the source image
+ RemoveSignatures bool
// Quiet - suppress output when copying images
Quiet bool
}
diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go
index f9d733c63..25335cf11 100644
--- a/pkg/domain/infra/abi/images.go
+++ b/pkg/domain/infra/abi/images.go
@@ -482,13 +482,13 @@ func (ir *ImageEngine) Import(ctx context.Context, opts entities.ImageImportOpti
func (ir *ImageEngine) Save(ctx context.Context, nameOrID string, tags []string, options entities.ImageSaveOptions) error {
if options.MultiImageArchive {
nameOrIDs := append([]string{nameOrID}, tags...)
- return ir.Libpod.ImageRuntime().SaveImages(ctx, nameOrIDs, options.Format, options.Output, options.Quiet)
+ return ir.Libpod.ImageRuntime().SaveImages(ctx, nameOrIDs, options.Format, options.Output, options.Quiet, true)
}
newImage, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrID)
if err != nil {
return err
}
- return newImage.Save(ctx, nameOrID, options.Format, options.Output, tags, options.Quiet, options.Compress)
+ return newImage.Save(ctx, nameOrID, options.Format, options.Output, tags, options.Quiet, options.Compress, true)
}
func (ir *ImageEngine) Diff(_ context.Context, nameOrID string, _ entities.DiffOptions) (*entities.DiffReport, error) {
diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go
index ef310d590..af6c43fec 100644
--- a/pkg/varlinkapi/images.go
+++ b/pkg/varlinkapi/images.go
@@ -843,7 +843,7 @@ func (i *VarlinkAPI) ImageSave(call iopodman.VarlinkCall, options iopodman.Image
saveOutput := bytes.NewBuffer([]byte{})
c := make(chan error)
go func() {
- err := newImage.Save(getContext(), options.Name, options.Format, output, options.MoreTags, options.Quiet, options.Compress)
+ err := newImage.Save(getContext(), options.Name, options.Format, output, options.MoreTags, options.Quiet, options.Compress, true)
c <- err
close(c)
}()
diff --git a/test/e2e/save_test.go b/test/e2e/save_test.go
index 1f1258be3..79fc4d737 100644
--- a/test/e2e/save_test.go
+++ b/test/e2e/save_test.go
@@ -1,8 +1,12 @@
package integration
import (
+ "io/ioutil"
"os"
+ "os/exec"
"path/filepath"
+ "strconv"
+ "strings"
"github.com/containers/podman/v2/pkg/rootless"
. "github.com/containers/podman/v2/test/utils"
@@ -116,6 +120,71 @@ var _ = Describe("Podman save", func() {
Expect(save).To(ExitWithError())
})
+ It("podman save remove signature", func() {
+ SkipIfRootless("FIXME: Need get in rootless push sign")
+ if podmanTest.Host.Arch == "ppc64le" {
+ Skip("No registry image for ppc64le")
+ }
+ tempGNUPGHOME := filepath.Join(podmanTest.TempDir, "tmpGPG")
+ err := os.Mkdir(tempGNUPGHOME, os.ModePerm)
+ Expect(err).To(BeNil())
+ origGNUPGHOME := os.Getenv("GNUPGHOME")
+ err = os.Setenv("GNUPGHOME", tempGNUPGHOME)
+ Expect(err).To(BeNil())
+ defer os.Setenv("GNUPGHOME", origGNUPGHOME)
+
+ port := 5000
+ session := podmanTest.Podman([]string{"run", "-d", "--name", "registry", "-p", strings.Join([]string{strconv.Itoa(port), strconv.Itoa(port)}, ":"), "docker.io/registry:2.6"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ if !WaitContainerReady(podmanTest, "registry", "listening on", 20, 1) {
+ Skip("Cannot start docker registry.")
+ }
+
+ cmd := exec.Command("gpg", "--import", "sign/secret-key.asc")
+ err = cmd.Run()
+ Expect(err).To(BeNil())
+
+ cmd = exec.Command("cp", "/etc/containers/registries.d/default.yaml", "default.yaml")
+ if err = cmd.Run(); err != nil {
+ Skip("no signature store to verify")
+ }
+ defer func() {
+ cmd = exec.Command("cp", "default.yaml", "/etc/containers/registries.d/default.yaml")
+ cmd.Run()
+ }()
+
+ cmd = exec.Command("cp", "sign/key.gpg", "/tmp/key.gpg")
+ Expect(cmd.Run()).To(BeNil())
+ sigstore := `
+default-docker:
+ sigstore: file:///var/lib/containers/sigstore
+ sigstore-staging: file:///var/lib/containers/sigstore
+`
+ Expect(ioutil.WriteFile("/etc/containers/registries.d/default.yaml", []byte(sigstore), 0755)).To(BeNil())
+
+ session = podmanTest.Podman([]string{"tag", ALPINE, "localhost:5000/alpine"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"push", "--tls-verify=false", "--sign-by", "foo@bar.com", "localhost:5000/alpine"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"rmi", ALPINE, "localhost:5000/alpine"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"pull", "--tls-verify=false", "--signature-policy=sign/policy.json", "localhost:5000/alpine"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ outfile := filepath.Join(podmanTest.TempDir, "temp.tar")
+ save := podmanTest.Podman([]string{"save", "remove-signatures=true", "-o", outfile, "localhost:5000/alpine"})
+ save.WaitWithDefaultTimeout()
+ Expect(save).To(ExitWithError())
+ })
+
It("podman save image with digest reference", func() {
// pull a digest reference
session := podmanTest.PodmanNoCache([]string{"pull", ALPINELISTDIGEST})
diff --git a/test/e2e/sign/key.gpg b/test/e2e/sign/key.gpg
new file mode 100644
index 000000000..32968fc04
--- /dev/null
+++ b/test/e2e/sign/key.gpg
@@ -0,0 +1,30 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQENBF8kNqwBCAC0x3Kog+WlDNwcR6rWIP8Gj2T6LrQ2/3knSyAWzTgC/OBB6Oh0
+KAokXLjy8J3diG3EaSltE7erGG/bZCz8jYvMiwDJScON4zzidotqjoY80E+NeRDg
+CC0gqvqmh0ftJIjYNBHzSxqrGRQwzwZU+u6ezlE8+0dvsHcHY+MRnxXJQrdM07EP
+Prp85kKckChDlJ1tyGUB/YHieFQmOW5+TERA7ZqQOAQ12Vviv6V4kNfEJJq3MS2c
+csZpO323tcHt3oebqsZCIElhX7uVw6GAeCw1tm4NZXs4g1yIC21Of/hzPeC18F72
+splCgKaAOiE9w/nMGLNEYy2NzgEclZLs2Y7jABEBAAG0FGZvb2JhciA8Zm9vQGJh
+ci5jb20+iQFUBBMBCAA+FiEERyT4ac7LLibByeabqaoHAy6P2bIFAl8kNqwCGwMF
+CQPCZwAFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQqaoHAy6P2bKtuggAgv54
+/F8wgi+uMrtFr8rqNtZMDyXRxfXaXUy5uGNfqHD83yqxweEqxiA8lmFkRHixPWtg
+Z2MniFXMVc9kVmg8GNIIuzewXrPqtXztvuURQo9phK68v8fXEqqT6K25wtq8TiQZ
+0J3mQIJPPTMe3pCCOyR6+W3iMtQp2AmitxKbzLP3J3GG2i0rG5S147A2rPnzTeMY
+hds819+JE7jNMD7FkV+TcQlOVl4wyOQhNEJcjb6rA6EUe5+s85pIFTBSyPMJpJ03
+Y0dLdcSGpKdncGTK2X9+hS96G1+FP/t8hRIDblqUHtBRXe3Ozz6zSqpqu1DbAQSM
+bIrLYxXfnZEN+ro0dLkBDQRfJDasAQgAncvLLZUHZkJWDPka3ocysJ7+/lmrXyAj
+T3D4r7UM4oaLBOMKjvaKSDw1uW5qYmTxnnsqFDI0O5+XJxD1/0qEf6l2oUpnILdx
+Vruf28FuvymbsyhDgs+MBoHz0jLWWPHUW2oWLIqcvaF0BePQ1GS6UoZlmZejsLww
+cSpbaAHJng7An/iLuqOBr5EdUA5XMXqmdMFDrjh0uZezImJ2Eacu/hshBdu3IY49
+J5XP18GWrSdUnP27cv3tOii9j5Lfl8QAvCN89vkALIU3eZtnMlWZqLgl5o6COVFm
+zpyx+iHOoCznQBt0aGoSNmE/dAqWIQS/xCSFqMHI6kNd9N0oR0rEHwARAQABiQE8
+BBgBCAAmFiEERyT4ac7LLibByeabqaoHAy6P2bIFAl8kNqwCGwwFCQPCZwAACgkQ
+qaoHAy6P2bJfjQgAje6YR+p1QaNlTN9l4t2kGzy9RhkfYMrTgI2fEqbS9bFJUy3Y
+3mH+vj/r2gN/kaN8LHH4K1d7fAohBsFqSI0flzHHIx2rfti9zAlbXcAErbnG+f0f
+k0AaqU7KelU35vjPfNe6Vn7ky6G9CC6jW04NkLZDNFA2GusdYf1aM0LWew5t4WZa
+quLVFhL36q9eHaogO/fcPR/quvQefHokk+b541ytwMN9l/g43rTbCvAjrUDHwipb
+Gbw91Wg2XjbecRiCXDKWds2M149BpxUzY5xHFtD5t5WSEE/SkkryGTMmTxS3tuQZ
+9PdtCPGrNDO6Ts/amORF04Tf+YMJgfv3IWxMeQ==
+=y0uZ
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/test/e2e/sign/policy.json b/test/e2e/sign/policy.json
new file mode 100644
index 000000000..ab01137bf
--- /dev/null
+++ b/test/e2e/sign/policy.json
@@ -0,0 +1,18 @@
+{
+ "default": [
+ {
+ "type": "insecureAcceptAnything"
+ }
+ ],
+ "transports": {
+ "docker": {
+ "localhost:5000": [
+ {
+ "type": "signedBy",
+ "keyType": "GPGKeys",
+ "keyPath": "/tmp/key.gpg"
+ }
+ ]
+ }
+ }
+}