github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/cmd/podman/trust_set_show.go (about)

     1  package main
     2  
     3  import (
     4  	"io/ioutil"
     5  	"os"
     6  	"sort"
     7  	"strings"
     8  
     9  	"github.com/containers/buildah/pkg/formats"
    10  	"github.com/containers/libpod/cmd/podman/cliconfig"
    11  	"github.com/containers/libpod/cmd/podman/libpodruntime"
    12  	"github.com/containers/libpod/libpod/image"
    13  	"github.com/containers/libpod/pkg/trust"
    14  	"github.com/pkg/errors"
    15  	"github.com/sirupsen/logrus"
    16  	"github.com/spf13/cobra"
    17  )
    18  
    19  var (
    20  	setTrustCommand     cliconfig.SetTrustValues
    21  	showTrustCommand    cliconfig.ShowTrustValues
    22  	setTrustDescription = "Set default trust policy or add a new trust policy for a registry"
    23  	_setTrustCommand    = &cobra.Command{
    24  		Use:     "set [flags] REGISTRY",
    25  		Short:   "Set default trust policy or a new trust policy for a registry",
    26  		Long:    setTrustDescription,
    27  		Example: "",
    28  		RunE: func(cmd *cobra.Command, args []string) error {
    29  			setTrustCommand.InputArgs = args
    30  			setTrustCommand.GlobalFlags = MainGlobalOpts
    31  			setTrustCommand.Remote = remoteclient
    32  			return setTrustCmd(&setTrustCommand)
    33  		},
    34  	}
    35  
    36  	showTrustDescription = "Display trust policy for the system"
    37  	_showTrustCommand    = &cobra.Command{
    38  		Use:   "show [flags] [REGISTRY]",
    39  		Short: "Display trust policy for the system",
    40  		Long:  showTrustDescription,
    41  		RunE: func(cmd *cobra.Command, args []string) error {
    42  			showTrustCommand.InputArgs = args
    43  			showTrustCommand.GlobalFlags = MainGlobalOpts
    44  			return showTrustCmd(&showTrustCommand)
    45  		},
    46  		Example: "",
    47  	}
    48  )
    49  
    50  func init() {
    51  	setTrustCommand.Command = _setTrustCommand
    52  	setTrustCommand.SetHelpTemplate(HelpTemplate())
    53  	setTrustCommand.SetUsageTemplate(UsageTemplate())
    54  	showTrustCommand.Command = _showTrustCommand
    55  	showTrustCommand.SetHelpTemplate(HelpTemplate())
    56  	showTrustCommand.SetUsageTemplate(UsageTemplate())
    57  	setFlags := setTrustCommand.Flags()
    58  	setFlags.StringVar(&setTrustCommand.PolicyPath, "policypath", "", "")
    59  	markFlagHidden(setFlags, "policypath")
    60  	setFlags.StringSliceVarP(&setTrustCommand.PubKeysFile, "pubkeysfile", "f", []string{}, `Path of installed public key(s) to trust for TARGET.
    61  Absolute path to keys is added to policy.json. May
    62  used multiple times to define multiple public keys.
    63  File(s) must exist before using this command`)
    64  	setFlags.StringVarP(&setTrustCommand.TrustType, "type", "t", "signedBy", "Trust type, accept values: signedBy(default), accept, reject")
    65  
    66  	showFlags := showTrustCommand.Flags()
    67  	showFlags.BoolVarP(&showTrustCommand.Json, "json", "j", false, "Output as json")
    68  	showFlags.StringVar(&showTrustCommand.PolicyPath, "policypath", "", "")
    69  	showFlags.BoolVar(&showTrustCommand.Raw, "raw", false, "Output raw policy file")
    70  	markFlagHidden(showFlags, "policypath")
    71  	showFlags.StringVar(&showTrustCommand.RegistryPath, "registrypath", "", "")
    72  	markFlagHidden(showFlags, "registrypath")
    73  }
    74  
    75  func showTrustCmd(c *cliconfig.ShowTrustValues) error {
    76  	runtime, err := libpodruntime.GetRuntime(getContext(), &c.PodmanCommand)
    77  	if err != nil {
    78  		return errors.Wrapf(err, "could not create runtime")
    79  	}
    80  
    81  	var (
    82  		policyPath              string
    83  		systemRegistriesDirPath string
    84  		outjson                 interface{}
    85  	)
    86  	if c.Flag("policypath").Changed {
    87  		policyPath = c.PolicyPath
    88  	} else {
    89  		policyPath = trust.DefaultPolicyPath(runtime.SystemContext())
    90  	}
    91  	policyContent, err := ioutil.ReadFile(policyPath)
    92  	if err != nil {
    93  		return errors.Wrapf(err, "unable to read %s", policyPath)
    94  	}
    95  	if c.Flag("registrypath").Changed {
    96  		systemRegistriesDirPath = c.RegistryPath
    97  	} else {
    98  		systemRegistriesDirPath = trust.RegistriesDirPath(runtime.SystemContext())
    99  	}
   100  
   101  	if c.Raw {
   102  		_, err := os.Stdout.Write(policyContent)
   103  		if err != nil {
   104  			return errors.Wrap(err, "could not read raw trust policies")
   105  		}
   106  		return nil
   107  	}
   108  
   109  	policyContentStruct, err := trust.GetPolicy(policyPath)
   110  	if err != nil {
   111  		return errors.Wrapf(err, "could not read trust policies")
   112  	}
   113  
   114  	if c.Json {
   115  		policyJSON, err := getPolicyJSON(policyContentStruct, systemRegistriesDirPath)
   116  		if err != nil {
   117  			return errors.Wrapf(err, "could not show trust policies in JSON format")
   118  		}
   119  		outjson = policyJSON
   120  		out := formats.JSONStruct{Output: outjson}
   121  		return out.Out()
   122  	}
   123  
   124  	showOutputMap, err := getPolicyShowOutput(policyContentStruct, systemRegistriesDirPath)
   125  	if err != nil {
   126  		return errors.Wrapf(err, "could not show trust policies")
   127  	}
   128  	out := formats.StdoutTemplateArray{Output: showOutputMap, Template: "{{.Repo}}\t{{.Trusttype}}\t{{.GPGid}}\t{{.Sigstore}}"}
   129  	return out.Out()
   130  }
   131  
   132  func setTrustCmd(c *cliconfig.SetTrustValues) error {
   133  	runtime, err := libpodruntime.GetRuntime(getContext(), &c.PodmanCommand)
   134  	if err != nil {
   135  		return errors.Wrapf(err, "could not create runtime")
   136  	}
   137  	var (
   138  		policyPath          string
   139  		policyContentStruct trust.PolicyContent
   140  		newReposContent     []trust.RepoContent
   141  	)
   142  	args := c.InputArgs
   143  	if len(args) != 1 {
   144  		return errors.Errorf("default or a registry name must be specified")
   145  	}
   146  	valid, err := image.IsValidImageURI(args[0])
   147  	if err != nil || !valid {
   148  		return errors.Wrapf(err, "invalid image uri %s", args[0])
   149  	}
   150  
   151  	trusttype := c.TrustType
   152  	if !isValidTrustType(trusttype) {
   153  		return errors.Errorf("invalid choice: %s (choose from 'accept', 'reject', 'signedBy')", trusttype)
   154  	}
   155  	if trusttype == "accept" {
   156  		trusttype = "insecureAcceptAnything"
   157  	}
   158  
   159  	pubkeysfile := c.PubKeysFile
   160  	if len(pubkeysfile) == 0 && trusttype == "signedBy" {
   161  		return errors.Errorf("At least one public key must be defined for type 'signedBy'")
   162  	}
   163  
   164  	if c.Flag("policypath").Changed {
   165  		policyPath = c.PolicyPath
   166  	} else {
   167  		policyPath = trust.DefaultPolicyPath(runtime.SystemContext())
   168  	}
   169  	_, err = os.Stat(policyPath)
   170  	if !os.IsNotExist(err) {
   171  		policyContent, err := ioutil.ReadFile(policyPath)
   172  		if err != nil {
   173  			return errors.Wrapf(err, "unable to read %s", policyPath)
   174  		}
   175  		if err := json.Unmarshal(policyContent, &policyContentStruct); err != nil {
   176  			return errors.Errorf("could not read trust policies")
   177  		}
   178  	}
   179  	if len(pubkeysfile) != 0 {
   180  		for _, filepath := range pubkeysfile {
   181  			newReposContent = append(newReposContent, trust.RepoContent{Type: trusttype, KeyType: "GPGKeys", KeyPath: filepath})
   182  		}
   183  	} else {
   184  		newReposContent = append(newReposContent, trust.RepoContent{Type: trusttype})
   185  	}
   186  	if args[0] == "default" {
   187  		policyContentStruct.Default = newReposContent
   188  	} else {
   189  		if len(policyContentStruct.Default) == 0 {
   190  			return errors.Errorf("Default trust policy must be set.")
   191  		}
   192  		registryExists := false
   193  		for transport, transportval := range policyContentStruct.Transports {
   194  			_, registryExists = transportval[args[0]]
   195  			if registryExists {
   196  				policyContentStruct.Transports[transport][args[0]] = newReposContent
   197  				break
   198  			}
   199  		}
   200  		if !registryExists {
   201  			if policyContentStruct.Transports == nil {
   202  				policyContentStruct.Transports = make(map[string]trust.RepoMap)
   203  			}
   204  			if policyContentStruct.Transports["docker"] == nil {
   205  				policyContentStruct.Transports["docker"] = make(map[string][]trust.RepoContent)
   206  			}
   207  			policyContentStruct.Transports["docker"][args[0]] = append(policyContentStruct.Transports["docker"][args[0]], newReposContent...)
   208  		}
   209  	}
   210  
   211  	data, err := json.MarshalIndent(policyContentStruct, "", "    ")
   212  	if err != nil {
   213  		return errors.Wrapf(err, "error setting trust policy")
   214  	}
   215  	err = ioutil.WriteFile(policyPath, data, 0644)
   216  	if err != nil {
   217  		return errors.Wrapf(err, "error setting trust policy")
   218  	}
   219  	return nil
   220  }
   221  
   222  func sortShowOutputMapKey(m map[string]trust.ShowOutput) []string {
   223  	keys := make([]string, len(m))
   224  	i := 0
   225  	for k := range m {
   226  		keys[i] = k
   227  		i++
   228  	}
   229  	sort.Strings(keys)
   230  	return keys
   231  }
   232  
   233  func isValidTrustType(t string) bool {
   234  	if t == "accept" || t == "insecureAcceptAnything" || t == "reject" || t == "signedBy" {
   235  		return true
   236  	}
   237  	return false
   238  }
   239  
   240  func getPolicyJSON(policyContentStruct trust.PolicyContent, systemRegistriesDirPath string) (map[string]map[string]interface{}, error) {
   241  	registryConfigs, err := trust.LoadAndMergeConfig(systemRegistriesDirPath)
   242  	if err != nil {
   243  		return nil, err
   244  	}
   245  
   246  	policyJSON := make(map[string]map[string]interface{})
   247  	if len(policyContentStruct.Default) > 0 {
   248  		policyJSON["* (default)"] = make(map[string]interface{})
   249  		policyJSON["* (default)"]["type"] = policyContentStruct.Default[0].Type
   250  	}
   251  	for transname, transval := range policyContentStruct.Transports {
   252  		for repo, repoval := range transval {
   253  			policyJSON[repo] = make(map[string]interface{})
   254  			policyJSON[repo]["type"] = repoval[0].Type
   255  			policyJSON[repo]["transport"] = transname
   256  			keyarr := []string{}
   257  			for _, repoele := range repoval {
   258  				if len(repoele.KeyPath) > 0 {
   259  					keyarr = append(keyarr, repoele.KeyPath)
   260  				}
   261  				if len(repoele.KeyData) > 0 {
   262  					keyarr = append(keyarr, repoele.KeyData)
   263  				}
   264  			}
   265  			policyJSON[repo]["keys"] = keyarr
   266  			policyJSON[repo]["sigstore"] = ""
   267  			registryNamespace := trust.HaveMatchRegistry(repo, registryConfigs)
   268  			if registryNamespace != nil {
   269  				policyJSON[repo]["sigstore"] = registryNamespace.SigStore
   270  			}
   271  		}
   272  	}
   273  	return policyJSON, nil
   274  }
   275  
   276  var typeDescription = map[string]string{"insecureAcceptAnything": "accept", "signedBy": "signed", "reject": "reject"}
   277  
   278  func trustTypeDescription(trustType string) string {
   279  	trustDescription, exist := typeDescription[trustType]
   280  	if !exist {
   281  		logrus.Warnf("invalid trust type %s", trustType)
   282  	}
   283  	return trustDescription
   284  }
   285  
   286  func getPolicyShowOutput(policyContentStruct trust.PolicyContent, systemRegistriesDirPath string) ([]interface{}, error) {
   287  	var output []interface{}
   288  
   289  	registryConfigs, err := trust.LoadAndMergeConfig(systemRegistriesDirPath)
   290  	if err != nil {
   291  		return nil, err
   292  	}
   293  
   294  	trustShowOutputMap := make(map[string]trust.ShowOutput)
   295  	if len(policyContentStruct.Default) > 0 {
   296  		defaultPolicyStruct := trust.ShowOutput{
   297  			Repo:      "default",
   298  			Trusttype: trustTypeDescription(policyContentStruct.Default[0].Type),
   299  		}
   300  		trustShowOutputMap["* (default)"] = defaultPolicyStruct
   301  	}
   302  	for _, transval := range policyContentStruct.Transports {
   303  		for repo, repoval := range transval {
   304  			tempTrustShowOutput := trust.ShowOutput{
   305  				Repo:      repo,
   306  				Trusttype: repoval[0].Type,
   307  			}
   308  			// TODO - keyarr is not used and I don't know its intent; commenting out for now for someone to fix later
   309  			//keyarr := []string{}
   310  			uids := []string{}
   311  			for _, repoele := range repoval {
   312  				if len(repoele.KeyPath) > 0 {
   313  					//keyarr = append(keyarr, repoele.KeyPath)
   314  					uids = append(uids, trust.GetGPGIdFromKeyPath(repoele.KeyPath)...)
   315  				}
   316  				if len(repoele.KeyData) > 0 {
   317  					//keyarr = append(keyarr, string(repoele.KeyData))
   318  					uids = append(uids, trust.GetGPGIdFromKeyData(repoele.KeyData)...)
   319  				}
   320  			}
   321  			tempTrustShowOutput.GPGid = strings.Join(uids, ", ")
   322  
   323  			registryNamespace := trust.HaveMatchRegistry(repo, registryConfigs)
   324  			if registryNamespace != nil {
   325  				tempTrustShowOutput.Sigstore = registryNamespace.SigStore
   326  			}
   327  			trustShowOutputMap[repo] = tempTrustShowOutput
   328  		}
   329  	}
   330  
   331  	sortedRepos := sortShowOutputMapKey(trustShowOutputMap)
   332  	for _, reponame := range sortedRepos {
   333  		showOutput, exists := trustShowOutputMap[reponame]
   334  		if exists {
   335  			output = append(output, interface{}(showOutput))
   336  		}
   337  	}
   338  	return output, nil
   339  }