Skip to content

Commit

Permalink
save image remove signatures
Browse files Browse the repository at this point in the history
remove signatures to podman save since the image formats do not support signatures
Close: containers#7659

Signed-off-by: Qi Wang <[email protected]>
  • Loading branch information
QiWang19 committed Oct 21, 2020
1 parent 94873a2 commit b898f91
Show file tree
Hide file tree
Showing 9 changed files with 130 additions and 10 deletions.
8 changes: 4 additions & 4 deletions libpod/image/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions pkg/api/handlers/compat/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/api/handlers/libpod/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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}
Expand Down
2 changes: 2 additions & 0 deletions pkg/domain/entities/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/domain/infra/abi/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/varlinkapi/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}()
Expand Down
69 changes: 69 additions & 0 deletions test/e2e/save_test.go
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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", "[email protected]", "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})
Expand Down
30 changes: 30 additions & 0 deletions test/e2e/sign/key.gpg
Original file line number Diff line number Diff line change
@@ -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-----
18 changes: 18 additions & 0 deletions test/e2e/sign/policy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"default": [
{
"type": "insecureAcceptAnything"
}
],
"transports": {
"docker": {
"localhost:5000": [
{
"type": "signedBy",
"keyType": "GPGKeys",
"keyPath": "/tmp/key.gpg"
}
]
}
}
}

0 comments on commit b898f91

Please sign in to comment.