mirror of
https://github.com/containers/podman.git
synced 2025-06-20 17:13:43 +08:00
27
cmd/podman/images/trust.go
Normal file
27
cmd/podman/images/trust.go
Normal file
@ -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,
|
||||||
|
})
|
||||||
|
}
|
56
cmd/podman/images/trust_set.go
Normal file
56
cmd/podman/images/trust_set.go
Normal file
@ -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)
|
||||||
|
}
|
77
cmd/podman/images/trust_show.go
Normal file
77
cmd/podman/images/trust_show.go
Normal file
@ -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
|
||||||
|
}
|
@ -22,6 +22,8 @@ type ImageEngine interface {
|
|||||||
Remove(ctx context.Context, images []string, opts ImageRemoveOptions) (*ImageRemoveReport, []error)
|
Remove(ctx context.Context, images []string, opts ImageRemoveOptions) (*ImageRemoveReport, []error)
|
||||||
Save(ctx context.Context, nameOrId string, tags []string, options ImageSaveOptions) error
|
Save(ctx context.Context, nameOrId string, tags []string, options ImageSaveOptions) error
|
||||||
Search(ctx context.Context, term string, opts ImageSearchOptions) ([]ImageSearchReport, 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)
|
Shutdown(ctx context.Context)
|
||||||
Tag(ctx context.Context, nameOrId string, tags []string, options ImageTagOptions) error
|
Tag(ctx context.Context, nameOrId string, tags []string, options ImageTagOptions) error
|
||||||
Tree(ctx context.Context, nameOrId string, options ImageTreeOptions) (*ImageTreeReport, error)
|
Tree(ctx context.Context, nameOrId string, options ImageTreeOptions) (*ImageTreeReport, error)
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/containers/image/v5/manifest"
|
"github.com/containers/image/v5/manifest"
|
||||||
"github.com/containers/image/v5/types"
|
"github.com/containers/image/v5/types"
|
||||||
"github.com/containers/libpod/pkg/inspect"
|
"github.com/containers/libpod/pkg/inspect"
|
||||||
|
"github.com/containers/libpod/pkg/trust"
|
||||||
docker "github.com/docker/docker/api/types"
|
docker "github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/opencontainers/go-digest"
|
"github.com/opencontainers/go-digest"
|
||||||
@ -285,3 +286,26 @@ type ImageTreeOptions struct {
|
|||||||
type ImageTreeReport struct {
|
type ImageTreeReport struct {
|
||||||
Tree string // TODO: Refactor move presentation work out of server
|
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
|
||||||
|
}
|
||||||
|
171
pkg/domain/infra/abi/trust.go
Normal file
171
pkg/domain/infra/abi/trust.go
Normal file
@ -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
|
||||||
|
}
|
16
pkg/domain/infra/tunnel/trust.go
Normal file
16
pkg/domain/infra/tunnel/trust.go
Normal file
@ -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")
|
||||||
|
}
|
12
pkg/trust/config.go
Normal file
12
pkg/trust/config.go
Normal file
@ -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"`
|
||||||
|
}
|
@ -21,7 +21,6 @@ var _ = Describe("Podman trust", func() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
Skip(v2fail)
|
|
||||||
tempdir, err = CreateTempDirInTempDir()
|
tempdir, err = CreateTempDirInTempDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
Reference in New Issue
Block a user