1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
|
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package images
import (
"errors"
"fmt"
"os"
"sort"
"strings"
"text/tabwriter"
"github.com/containerd/containerd/cmd/ctr/commands"
"github.com/containerd/containerd/platforms"
"github.com/containerd/imgcrypt/cmd/ctr/commands/img"
"github.com/containerd/imgcrypt/images/encryption/parsehelpers"
"github.com/containers/ocicrypt"
"github.com/urfave/cli"
)
var layerinfoCommand = cli.Command{
Name: "layerinfo",
Usage: "get information about an image's layers",
ArgsUsage: "[flags] <local>",
Description: `Get encryption information about the layers of an image.
Get information about the layers of an image and display with which
encryption technology the individual layers are encrypted with.
The user has control over the individual layers and the platforms they are
associated with and can retrieve information for them separately. If no
layers or platforms are specified, infomration for all layers and all
platforms will be retrieved.
`,
Flags: append(commands.RegistryFlags, cli.IntSliceFlag{
Name: "layer",
Usage: "The layer to get info for; this must be either the layer number or a negative number starting with -1 for topmost layer",
}, cli.StringSliceFlag{
Name: "platform",
Usage: "For which platform to get the layer info; by default info for all platforms is retrieved",
}, cli.StringFlag{
Name: "gpg-homedir",
Usage: "The GPG homedir to use; by default gpg uses ~/.gnupg",
}, cli.StringFlag{
Name: "gpg-version",
Usage: "The GPG version (\"v1\" or \"v2\"), default will make an educated guess",
}, cli.BoolFlag{
Name: "n",
Usage: "Do not resolve PGP key IDs to email addresses",
}),
Action: func(context *cli.Context) error {
local := context.Args().First()
if local == "" {
return errors.New("please provide the name of an image")
}
client, ctx, cancel, err := commands.NewClient(context)
if err != nil {
return err
}
defer cancel()
layers32 := img.IntToInt32Array(context.IntSlice("layer"))
LayerInfos, _, err := getImageLayerInfos(client, ctx, local, layers32, context.StringSlice("platform"))
if err != nil {
return err
}
if len(LayerInfos) == 0 {
return nil
}
var gpgClient ocicrypt.GPGClient
if !context.Bool("n") {
// create a GPG client to resolve keyIds to names
gpgClient, _ = parsehelpers.CreateGPGClient(ParseEncArgs(context))
}
w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', tabwriter.AlignRight)
fmt.Fprintf(w, "#\tDIGEST\tPLATFORM\tSIZE\tENCRYPTION\tRECIPIENTS\t\n")
for _, layer := range LayerInfos {
var recipients []string
var schemes []string
for scheme, wrappedKeys := range ocicrypt.GetWrappedKeysMap(layer.Descriptor) {
schemes = append(schemes, scheme)
keywrapper := ocicrypt.GetKeyWrapper(scheme)
if keywrapper != nil {
addRecipients, err := keywrapper.GetRecipients(wrappedKeys)
if err != nil {
return err
}
if scheme == "pgp" && gpgClient != nil {
addRecipients = gpgClient.ResolveRecipients(addRecipients)
}
recipients = append(recipients, addRecipients...)
} else {
recipients = append(recipients, fmt.Sprintf("No %s KeyWrapper", scheme))
}
}
sort.Strings(schemes)
sort.Strings(recipients)
fmt.Fprintf(w, "%d\t%s\t%s\t%d\t%s\t%s\t\n", layer.Index, layer.Descriptor.Digest.String(), platforms.Format(*layer.Descriptor.Platform), layer.Descriptor.Size, strings.Join(schemes, ","), strings.Join(recipients, ", "))
}
w.Flush()
return nil
},
}
|