summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbaude <bbaude@redhat.com>2020-05-06 15:24:54 -0500
committerBrent Baude <bbaude@redhat.com>2020-05-07 09:55:52 -0500
commite9a17da1c5f3e20a5f4394db9f5d7e744d8fdbc6 (patch)
tree2f1a257cbf8bbfa03c619068692c2fd059fc7a3f
parent7cd2e35203cd059a75792c1ff03486ba32a23ddb (diff)
downloadpodman-e9a17da1c5f3e20a5f4394db9f5d7e744d8fdbc6.tar.gz
podman-e9a17da1c5f3e20a5f4394db9f5d7e744d8fdbc6.tar.bz2
podman-e9a17da1c5f3e20a5f4394db9f5d7e744d8fdbc6.zip
v2trust set and show
add podman image trust set and show Signed-off-by: baude <bbaude@redhat.com> Signed-off-by: bbaude <bbaude@DESKTOP-SH5EG3J.localdomain> Signed-off-by: Brent Baude <bbaude@redhat.com>
-rw-r--r--cmd/podman/images/trust.go27
-rw-r--r--cmd/podman/images/trust_set.go56
-rw-r--r--cmd/podman/images/trust_show.go77
-rw-r--r--pkg/domain/entities/engine_image.go2
-rw-r--r--pkg/domain/entities/images.go24
-rw-r--r--pkg/domain/infra/abi/trust.go171
-rw-r--r--pkg/domain/infra/tunnel/trust.go16
-rw-r--r--pkg/trust/config.go12
-rw-r--r--test/e2e/trust_test.go1
9 files changed, 385 insertions, 1 deletions
diff --git a/cmd/podman/images/trust.go b/cmd/podman/images/trust.go
new file mode 100644
index 000000000..88a567871
--- /dev/null
+++ b/cmd/podman/images/trust.go
@@ -0,0 +1,27 @@
+package images
+
+import (
+ "github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/spf13/cobra"
+)
+
+var (
+ trustDescription = `Manages which registries you trust as a source of container images based on their location.
+ The location is determined by the transport and the registry host of the image. Using this container image docker://quay.io/podman/stable as an example, docker is the transport and quay.io is the registry host.`
+ trustCmd = &cobra.Command{
+ Use: "trust",
+ Short: "Manage container image trust policy",
+ Long: trustDescription,
+ RunE: validate.SubCommandExists,
+ }
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode},
+ Command: trustCmd,
+ Parent: imageCmd,
+ })
+}
diff --git a/cmd/podman/images/trust_set.go b/cmd/podman/images/trust_set.go
new file mode 100644
index 000000000..5868f5546
--- /dev/null
+++ b/cmd/podman/images/trust_set.go
@@ -0,0 +1,56 @@
+package images
+
+import (
+ "github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/libpod/image"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/util"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ setTrustDescription = "Set default trust policy or add a new trust policy for a registry"
+ setTrustCommand = &cobra.Command{
+ Use: "set [flags] REGISTRY",
+ Short: "Set default trust policy or a new trust policy for a registry",
+ Long: setTrustDescription,
+ Example: "",
+ RunE: setTrust,
+ Args: cobra.ExactArgs(1),
+ }
+)
+
+var (
+ setOptions entities.SetTrustOptions
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode},
+ Command: setTrustCommand,
+ Parent: trustCmd,
+ })
+ setFlags := setTrustCommand.Flags()
+ setFlags.StringVar(&setOptions.PolicyPath, "policypath", "", "")
+ _ = setFlags.MarkHidden("policypath")
+ setFlags.StringSliceVarP(&setOptions.PubKeysFile, "pubkeysfile", "f", []string{}, `Path of installed public key(s) to trust for TARGET.
+Absolute path to keys is added to policy.json. May
+used multiple times to define multiple public keys.
+File(s) must exist before using this command`)
+ setFlags.StringVarP(&setOptions.Type, "type", "t", "signedBy", "Trust type, accept values: signedBy(default), accept, reject")
+}
+
+func setTrust(cmd *cobra.Command, args []string) error {
+ validTrustTypes := []string{"accept", "insecureAcceptAnything", "reject", "signedBy"}
+
+ valid, err := image.IsValidImageURI(args[0])
+ if err != nil || !valid {
+ return errors.Wrapf(err, "invalid image uri %s", args[0])
+ }
+
+ if !util.StringInSlice(setOptions.Type, validTrustTypes) {
+ return errors.Errorf("invalid choice: %s (choose from 'accept', 'reject', 'signedBy')", setOptions.Type)
+ }
+ return registry.ImageEngine().SetTrust(registry.Context(), args, setOptions)
+}
diff --git a/cmd/podman/images/trust_show.go b/cmd/podman/images/trust_show.go
new file mode 100644
index 000000000..23ee6c709
--- /dev/null
+++ b/cmd/podman/images/trust_show.go
@@ -0,0 +1,77 @@
+package images
+
+import (
+ "fmt"
+ "os"
+ "text/tabwriter"
+ "text/template"
+
+ "github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/spf13/cobra"
+)
+
+var (
+ showTrustDescription = "Display trust policy for the system"
+ showTrustCommand = &cobra.Command{
+ Use: "show [flags] [REGISTRY]",
+ Short: "Display trust policy for the system",
+ Long: showTrustDescription,
+ RunE: showTrust,
+ Example: "",
+ }
+)
+
+var (
+ showTrustOptions entities.ShowTrustOptions
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode},
+ Command: showTrustCommand,
+ Parent: trustCmd,
+ })
+ showFlags := showTrustCommand.Flags()
+ showFlags.BoolVarP(&showTrustOptions.JSON, "json", "j", false, "Output as json")
+ showFlags.StringVar(&showTrustOptions.PolicyPath, "policypath", "", "")
+ showFlags.BoolVar(&showTrustOptions.Raw, "raw", false, "Output raw policy file")
+ _ = showFlags.MarkHidden("policypath")
+ showFlags.StringVar(&showTrustOptions.RegistryPath, "registrypath", "", "")
+ _ = showFlags.MarkHidden("registrypath")
+
+}
+
+func showTrust(cmd *cobra.Command, args []string) error {
+ report, err := registry.ImageEngine().ShowTrust(registry.Context(), args, showTrustOptions)
+ if err != nil {
+ return err
+ }
+ if showTrustOptions.Raw {
+ fmt.Println(report.Raw)
+ return nil
+ }
+ if showTrustOptions.JSON {
+ b, err := json.MarshalIndent(report.Policies, "", " ")
+ if err != nil {
+ return err
+ }
+ fmt.Println(string(b))
+ return nil
+ }
+
+ row := "{{.RepoName}}\t{{.Type}}\t{{.GPGId}}\t{{.SignatureStore}}\n"
+ format := "{{range . }}" + row + "{{end}}"
+ tmpl, err := template.New("listContainers").Parse(format)
+ if err != nil {
+ return err
+ }
+ w := tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0)
+ if err := tmpl.Execute(w, report.Policies); err != nil {
+ return err
+ }
+ if err := w.Flush(); err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/pkg/domain/entities/engine_image.go b/pkg/domain/entities/engine_image.go
index c46ba815a..d979e6006 100644
--- a/pkg/domain/entities/engine_image.go
+++ b/pkg/domain/entities/engine_image.go
@@ -22,6 +22,8 @@ type ImageEngine interface {
Remove(ctx context.Context, images []string, opts ImageRemoveOptions) (*ImageRemoveReport, []error)
Save(ctx context.Context, nameOrId string, tags []string, options ImageSaveOptions) error
Search(ctx context.Context, term string, opts ImageSearchOptions) ([]ImageSearchReport, error)
+ SetTrust(ctx context.Context, args []string, options SetTrustOptions) error
+ ShowTrust(ctx context.Context, args []string, options ShowTrustOptions) (*ShowTrustReport, error)
Shutdown(ctx context.Context)
Tag(ctx context.Context, nameOrId string, tags []string, options ImageTagOptions) error
Tree(ctx context.Context, nameOrId string, options ImageTreeOptions) (*ImageTreeReport, error)
diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go
index 74f27e25f..e116a90b9 100644
--- a/pkg/domain/entities/images.go
+++ b/pkg/domain/entities/images.go
@@ -7,6 +7,7 @@ import (
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/types"
"github.com/containers/libpod/pkg/inspect"
+ "github.com/containers/libpod/pkg/trust"
docker "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/opencontainers/go-digest"
@@ -285,3 +286,26 @@ type ImageTreeOptions struct {
type ImageTreeReport struct {
Tree string // TODO: Refactor move presentation work out of server
}
+
+// ShowTrustOptions are the cli options for showing trust
+type ShowTrustOptions struct {
+ JSON bool
+ PolicyPath string
+ Raw bool
+ RegistryPath string
+}
+
+// ShowTrustReport describes the results of show trust
+type ShowTrustReport struct {
+ Raw []byte
+ SystemRegistriesDirPath string
+ JSONOutput []byte
+ Policies []*trust.TrustPolicy
+}
+
+// SetTrustOptions describes the CLI options for setting trust
+type SetTrustOptions struct {
+ PolicyPath string
+ PubKeysFile []string
+ Type string
+}
diff --git a/pkg/domain/infra/abi/trust.go b/pkg/domain/infra/abi/trust.go
new file mode 100644
index 000000000..5b89c91d9
--- /dev/null
+++ b/pkg/domain/infra/abi/trust.go
@@ -0,0 +1,171 @@
+package abi
+
+import (
+ "context"
+ "encoding/json"
+ "io/ioutil"
+ "os"
+ "strings"
+
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/trust"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+func (ir *ImageEngine) ShowTrust(ctx context.Context, args []string, options entities.ShowTrustOptions) (*entities.ShowTrustReport, error) {
+ var (
+ err error
+ report entities.ShowTrustReport
+ )
+ policyPath := trust.DefaultPolicyPath(ir.Libpod.SystemContext())
+ if len(options.PolicyPath) > 0 {
+ policyPath = options.PolicyPath
+ }
+ report.Raw, err = ioutil.ReadFile(policyPath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "unable to read %s", policyPath)
+ }
+ if options.Raw {
+ return &report, nil
+ }
+ report.SystemRegistriesDirPath = trust.RegistriesDirPath(ir.Libpod.SystemContext())
+ if len(options.RegistryPath) > 0 {
+ report.SystemRegistriesDirPath = options.RegistryPath
+ }
+ policyContentStruct, err := trust.GetPolicy(policyPath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "could not read trust policies")
+ }
+ report.Policies, err = getPolicyShowOutput(policyContentStruct, report.SystemRegistriesDirPath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "could not show trust policies")
+ }
+ return &report, nil
+}
+
+func (ir *ImageEngine) SetTrust(ctx context.Context, args []string, options entities.SetTrustOptions) error {
+ var (
+ policyContentStruct trust.PolicyContent
+ newReposContent []trust.RepoContent
+ )
+ trustType := options.Type
+ if trustType == "accept" {
+ trustType = "insecureAcceptAnything"
+ }
+
+ pubkeysfile := options.PubKeysFile
+ if len(pubkeysfile) == 0 && trustType == "signedBy" {
+ return errors.Errorf("At least one public key must be defined for type 'signedBy'")
+ }
+
+ policyPath := trust.DefaultPolicyPath(ir.Libpod.SystemContext())
+ if len(options.PolicyPath) > 0 {
+ policyPath = options.PolicyPath
+ }
+ _, err := os.Stat(policyPath)
+ if !os.IsNotExist(err) {
+ policyContent, err := ioutil.ReadFile(policyPath)
+ if err != nil {
+ return errors.Wrapf(err, "unable to read %s", policyPath)
+ }
+ if err := json.Unmarshal(policyContent, &policyContentStruct); err != nil {
+ return errors.Errorf("could not read trust policies")
+ }
+ }
+ if len(pubkeysfile) != 0 {
+ for _, filepath := range pubkeysfile {
+ newReposContent = append(newReposContent, trust.RepoContent{Type: trustType, KeyType: "GPGKeys", KeyPath: filepath})
+ }
+ } else {
+ newReposContent = append(newReposContent, trust.RepoContent{Type: trustType})
+ }
+ if args[0] == "default" {
+ policyContentStruct.Default = newReposContent
+ } else {
+ if len(policyContentStruct.Default) == 0 {
+ return errors.Errorf("Default trust policy must be set.")
+ }
+ registryExists := false
+ for transport, transportval := range policyContentStruct.Transports {
+ _, registryExists = transportval[args[0]]
+ if registryExists {
+ policyContentStruct.Transports[transport][args[0]] = newReposContent
+ break
+ }
+ }
+ if !registryExists {
+ if policyContentStruct.Transports == nil {
+ policyContentStruct.Transports = make(map[string]trust.RepoMap)
+ }
+ if policyContentStruct.Transports["docker"] == nil {
+ policyContentStruct.Transports["docker"] = make(map[string][]trust.RepoContent)
+ }
+ policyContentStruct.Transports["docker"][args[0]] = append(policyContentStruct.Transports["docker"][args[0]], newReposContent...)
+ }
+ }
+
+ data, err := json.MarshalIndent(policyContentStruct, "", " ")
+ if err != nil {
+ return errors.Wrapf(err, "error setting trust policy")
+ }
+ return ioutil.WriteFile(policyPath, data, 0644)
+}
+
+func getPolicyShowOutput(policyContentStruct trust.PolicyContent, systemRegistriesDirPath string) ([]*trust.TrustPolicy, error) {
+ var output []*trust.TrustPolicy
+
+ registryConfigs, err := trust.LoadAndMergeConfig(systemRegistriesDirPath)
+ if err != nil {
+ return nil, err
+ }
+
+ if len(policyContentStruct.Default) > 0 {
+ defaultPolicyStruct := trust.TrustPolicy{
+ Name: "* (default)",
+ RepoName: "default",
+ Type: trustTypeDescription(policyContentStruct.Default[0].Type),
+ }
+ output = append(output, &defaultPolicyStruct)
+ }
+ for _, transval := range policyContentStruct.Transports {
+ for repo, repoval := range transval {
+ tempTrustShowOutput := trust.TrustPolicy{
+ Name: repo,
+ RepoName: repo,
+ Type: repoval[0].Type,
+ }
+ // TODO - keyarr is not used and I don't know its intent; commenting out for now for someone to fix later
+ //keyarr := []string{}
+ uids := []string{}
+ for _, repoele := range repoval {
+ if len(repoele.KeyPath) > 0 {
+ //keyarr = append(keyarr, repoele.KeyPath)
+ uids = append(uids, trust.GetGPGIdFromKeyPath(repoele.KeyPath)...)
+ }
+ if len(repoele.KeyData) > 0 {
+ //keyarr = append(keyarr, string(repoele.KeyData))
+ uids = append(uids, trust.GetGPGIdFromKeyData(repoele.KeyData)...)
+ }
+ }
+ tempTrustShowOutput.GPGId = strings.Join(uids, ", ")
+
+ registryNamespace := trust.HaveMatchRegistry(repo, registryConfigs)
+ if registryNamespace != nil {
+ tempTrustShowOutput.SignatureStore = registryNamespace.SigStore
+ }
+ output = append(output, &tempTrustShowOutput)
+ }
+ }
+ return output, nil
+}
+
+var typeDescription = map[string]string{"insecureAcceptAnything": "accept", "signedBy": "signed", "reject": "reject"}
+
+func trustTypeDescription(trustType string) string {
+ trustDescription, exist := typeDescription[trustType]
+ if !exist {
+ logrus.Warnf("invalid trust type %s", trustType)
+ }
+ return trustDescription
+}
diff --git a/pkg/domain/infra/tunnel/trust.go b/pkg/domain/infra/tunnel/trust.go
new file mode 100644
index 000000000..a976bfdc2
--- /dev/null
+++ b/pkg/domain/infra/tunnel/trust.go
@@ -0,0 +1,16 @@
+package tunnel
+
+import (
+ "context"
+ "errors"
+
+ "github.com/containers/libpod/pkg/domain/entities"
+)
+
+func (ir *ImageEngine) ShowTrust(ctx context.Context, args []string, options entities.ShowTrustOptions) (*entities.ShowTrustReport, error) {
+ return nil, errors.New("not implemented")
+}
+
+func (ir *ImageEngine) SetTrust(ctx context.Context, args []string, options entities.SetTrustOptions) error {
+ return errors.New("not implemented")
+}
diff --git a/pkg/trust/config.go b/pkg/trust/config.go
new file mode 100644
index 000000000..0bafc722b
--- /dev/null
+++ b/pkg/trust/config.go
@@ -0,0 +1,12 @@
+package trust
+
+// Trust Policy describes a basic trust policy configuration
+type TrustPolicy struct {
+ Name string `json:"name"`
+ RepoName string `json:"repo_name,omitempty"`
+ Keys []string `json:"keys,omitempty"`
+ SignatureStore string `json:"sigstore"`
+ Transport string `json:"transport"`
+ Type string `json:"type"`
+ GPGId string `json:"gpg_id,omitempty"`
+}
diff --git a/test/e2e/trust_test.go b/test/e2e/trust_test.go
index 2da370194..8c97e6b28 100644
--- a/test/e2e/trust_test.go
+++ b/test/e2e/trust_test.go
@@ -21,7 +21,6 @@ var _ = Describe("Podman trust", func() {
)
BeforeEach(func() {
- Skip(v2fail)
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)