github.com/containerd/nerdctl@v1.7.7/cmd/nerdctl/image_encrypt_linux_test.go (about) 1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package main 18 19 import ( 20 "context" 21 "fmt" 22 "os" 23 "os/exec" 24 "path/filepath" 25 "testing" 26 27 "github.com/containerd/containerd" 28 "github.com/containerd/containerd/content" 29 "github.com/containerd/nerdctl/pkg/buildkitutil" 30 "github.com/containerd/nerdctl/pkg/testutil" 31 "github.com/containerd/nerdctl/pkg/testutil/testregistry" 32 "gotest.tools/v3/assert" 33 ) 34 35 type jweKeyPair struct { 36 prv string 37 pub string 38 cleanup func() 39 } 40 41 func newJWEKeyPair(t testing.TB) *jweKeyPair { 42 testutil.RequireExecutable(t, "openssl") 43 td, err := os.MkdirTemp(t.TempDir(), "jwe-key-pair") 44 assert.NilError(t, err) 45 prv := filepath.Join(td, "mykey.pem") 46 pub := filepath.Join(td, "mypubkey.pem") 47 cmds := [][]string{ 48 // Exec openssl commands to ensure that nerdctl is compatible with the output of openssl commands. 49 // Do NOT refactor this function to use "crypto/rsa" stdlib. 50 {"openssl", "genrsa", "-out", prv}, 51 {"openssl", "rsa", "-in", prv, "-pubout", "-out", pub}, 52 } 53 for _, f := range cmds { 54 cmd := exec.Command(f[0], f[1:]...) 55 if out, err := cmd.CombinedOutput(); err != nil { 56 t.Fatalf("failed to run %v: %v (%q)", cmd.Args, err, string(out)) 57 } 58 } 59 return &jweKeyPair{ 60 prv: prv, 61 pub: pub, 62 cleanup: func() { 63 _ = os.RemoveAll(td) 64 }, 65 } 66 } 67 68 func rmiAll(base *testutil.Base) { 69 base.T.Logf("Pruning images") 70 imageIDs := base.Cmd("images", "--no-trunc", "-a", "-q").OutLines() 71 // remove empty output line at the end 72 imageIDs = imageIDs[:len(imageIDs)-1] 73 // use `Run` on purpose (same below) because `rmi all` may fail on individual 74 // image id that has an expected running container (e.g. a registry) 75 base.Cmd(append([]string{"rmi", "-f"}, imageIDs...)...).Run() 76 77 base.T.Logf("Pruning build caches") 78 if _, err := buildkitutil.GetBuildkitHost(testutil.Namespace); err == nil { 79 base.Cmd("builder", "prune").AssertOK() 80 } 81 82 // For BuildKit >= 0.11, pruning cache isn't enough to remove manifest blobs that are referred by build history blobs 83 // https://github.com/containerd/nerdctl/pull/1833 84 if base.Target == testutil.Nerdctl { 85 base.T.Logf("Pruning all content blobs") 86 addr := base.ContainerdAddress() 87 client, err := containerd.New(addr, containerd.WithDefaultNamespace(testutil.Namespace)) 88 assert.NilError(base.T, err) 89 cs := client.ContentStore() 90 ctx := context.TODO() 91 wf := func(info content.Info) error { 92 base.T.Logf("Pruning blob %+v", info) 93 if err := cs.Delete(ctx, info.Digest); err != nil { 94 base.T.Log(err) 95 } 96 return nil 97 } 98 if err := cs.Walk(ctx, wf); err != nil { 99 base.T.Log(err) 100 } 101 102 base.T.Logf("Pruning all images (again?)") 103 imageIDs = base.Cmd("images", "--no-trunc", "-a", "-q").OutLines() 104 base.T.Logf("pruning following images: %+v", imageIDs) 105 base.Cmd(append([]string{"rmi", "-f"}, imageIDs...)...).Run() 106 } 107 } 108 109 func TestImageEncryptJWE(t *testing.T) { 110 testutil.RequiresBuild(t) 111 testutil.DockerIncompatible(t) 112 keyPair := newJWEKeyPair(t) 113 defer keyPair.cleanup() 114 base := testutil.NewBase(t) 115 tID := testutil.Identifier(t) 116 reg := testregistry.NewPlainHTTP(base, 5000) 117 defer reg.Cleanup() 118 base.Cmd("pull", testutil.CommonImage).AssertOK() 119 encryptImageRef := fmt.Sprintf("127.0.0.1:%d/%s:encrypted", reg.ListenPort, tID) 120 defer base.Cmd("rmi", encryptImageRef).Run() 121 base.Cmd("image", "encrypt", "--recipient=jwe:"+keyPair.pub, testutil.CommonImage, encryptImageRef).AssertOK() 122 base.Cmd("image", "inspect", "--mode=native", "--format={{len .Index.Manifests}}", encryptImageRef).AssertOutExactly("1\n") 123 base.Cmd("image", "inspect", "--mode=native", "--format={{json .Manifest.Layers}}", encryptImageRef).AssertOutContains("org.opencontainers.image.enc.keys.jwe") 124 base.Cmd("push", encryptImageRef).AssertOK() 125 // remove all local images (in the nerdctl-test namespace), to ensure that we do not have blobs of the original image. 126 rmiAll(base) 127 base.Cmd("pull", encryptImageRef).AssertFail() // defaults to --unpack=true, and fails due to missing prv key 128 base.Cmd("pull", "--unpack=false", encryptImageRef).AssertOK() 129 decryptImageRef := tID + ":decrypted" 130 defer base.Cmd("rmi", decryptImageRef).Run() 131 base.Cmd("image", "decrypt", "--key="+keyPair.pub, encryptImageRef, decryptImageRef).AssertFail() // decryption needs prv key, not pub key 132 base.Cmd("image", "decrypt", "--key="+keyPair.prv, encryptImageRef, decryptImageRef).AssertOK() 133 }