From b01b2a78f4f8ffbd8d76ef7234ccc1ba8d7b42ce Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Tue, 8 Jan 2019 22:01:54 -0500 Subject: Fix 'image trust' from PR1899 Signed-off-by: Qi Wang --- cmd/podman/trust.go | 58 ++++++++--------------- pkg/trust/trust.go | 129 ++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 108 insertions(+), 79 deletions(-) diff --git a/cmd/podman/trust.go b/cmd/podman/trust.go index 7c404cd3f..863f36d09 100644 --- a/cmd/podman/trust.go +++ b/cmd/podman/trust.go @@ -13,7 +13,6 @@ import ( "github.com/containers/libpod/libpod/image" "github.com/containers/libpod/pkg/trust" "github.com/pkg/errors" - "github.com/sirupsen/logrus" "github.com/urfave/cli" ) @@ -132,7 +131,7 @@ func showTrustCmd(c *cli.Context) error { if err := json.Unmarshal(policyContent, &policyContentStruct); err != nil { return errors.Errorf("could not read trust policies") } - policyJSON, err := trust.GetPolicyJSON(policyContentStruct, systemRegistriesDirPath) + policyJSON, showOutputMap, err := trust.GetPolicy(policyContentStruct, systemRegistriesDirPath) if err != nil { return errors.Wrapf(err, "error reading registry config file") } @@ -144,31 +143,12 @@ func showTrustCmd(c *cli.Context) error { } sortedRepos := sortPolicyJSONKey(policyJSON) - type policydefault struct { - Repo string - Trusttype string - GPGid string - Sigstore string - } - var policyoutput []policydefault - for _, repo := range sortedRepos { - repoval := policyJSON[repo] - var defaultstruct policydefault - defaultstruct.Repo = repo - if repoval["type"] != nil { - defaultstruct.Trusttype = trustTypeDescription(repoval["type"].(string)) - } - if repoval["keys"] != nil && len(repoval["keys"].([]string)) > 0 { - defaultstruct.GPGid = trust.GetGPGId(repoval["keys"].([]string)) - } - if repoval["sigstore"] != nil { - defaultstruct.Sigstore = repoval["sigstore"].(string) - } - policyoutput = append(policyoutput, defaultstruct) - } var output []interface{} - for _, ele := range policyoutput { - output = append(output, interface{}(ele)) + for _, reponame := range sortedRepos { + showOutput, exists := showOutputMap[reponame] + if exists { + output = append(output, interface{}(showOutput)) + } } out := formats.StdoutTemplateArray{Output: output, Template: "{{.Repo}}\t{{.Trusttype}}\t{{.GPGid}}\t{{.Sigstore}}"} return formats.Writer(out).Out() @@ -209,8 +189,10 @@ func setTrustCmd(c *cli.Context) error { policyPath = trust.DefaultPolicyPath(runtime.SystemContext()) } var policyContentStruct trust.PolicyContent + policyFileExists := false _, err = os.Stat(policyPath) if !os.IsNotExist(err) { + policyFileExists = true policyContent, err := ioutil.ReadFile(policyPath) if err != nil { return errors.Wrapf(err, "unable to read %s", policyPath) @@ -218,6 +200,9 @@ func setTrustCmd(c *cli.Context) error { if err := json.Unmarshal(policyContent, &policyContentStruct); err != nil { return errors.Errorf("could not read trust policies") } + if args[0] != "default" && len(policyContentStruct.Default) == 0 { + return errors.Errorf("Default trust policy must be set.") + } } var newReposContent []trust.RepoContent if len(pubkeysfile) != 0 { @@ -230,15 +215,18 @@ func setTrustCmd(c *cli.Context) error { if args[0] == "default" { policyContentStruct.Default = newReposContent } else { - exists := false + if policyFileExists == false && len(policyContentStruct.Default) == 0 { + return errors.Errorf("Default trust policy must be set to create the policy file.") + } + registryExists := false for transport, transportval := range policyContentStruct.Transports { - _, exists = transportval[args[0]] - if exists { + _, registryExists = transportval[args[0]] + if registryExists { policyContentStruct.Transports[transport][args[0]] = newReposContent break } } - if !exists { + if !registryExists { if policyContentStruct.Transports == nil { policyContentStruct.Transports = make(map[string]trust.RepoMap) } @@ -260,16 +248,6 @@ func setTrustCmd(c *cli.Context) error { return 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 -} - func sortPolicyJSONKey(m map[string]map[string]interface{}) []string { keys := make([]string, len(m)) i := 0 diff --git a/pkg/trust/trust.go b/pkg/trust/trust.go index efc760364..31e41903e 100644 --- a/pkg/trust/trust.go +++ b/pkg/trust/trust.go @@ -2,6 +2,7 @@ package trust import ( "bufio" + "bytes" "encoding/base64" "encoding/json" "io/ioutil" @@ -9,7 +10,6 @@ import ( "os/exec" "path/filepath" "strings" - "unsafe" "github.com/containers/image/types" "github.com/pkg/errors" @@ -52,6 +52,14 @@ type RegistryNamespace struct { SigStoreStaging string `json:"sigstore-staging"` // For writing only. } +// ShowOutput keep the fields for image trust show command +type ShowOutput struct { + Repo string + Trusttype string + GPGid string + Sigstore string +} + // DefaultPolicyPath returns a path to the default policy of the system. func DefaultPolicyPath(sys *types.SystemContext) string { systemDefaultPolicyPath := "/etc/containers/policy.json" @@ -167,84 +175,127 @@ func CreateTmpFile(dir, pattern string, content []byte) (string, error) { return tmpfile.Name(), nil } -// GetGPGId return GPG identity, either bracketed or ID string -// comma separated if more than one key -func GetGPGId(keys []string) string { +func getGPGIdFromKeyPath(path []string) []string { + var uids []string + for _, k := range path { + cmd := exec.Command("gpg2", "--with-colons", k) + results, err := cmd.Output() + if err != nil { + logrus.Warnf("error get key identity: %s", err) + continue + } + uids = append(uids, parseUids(results)...) + } + return uids +} + +func getGPGIdFromKeyData(keys []string) []string { + var uids []string for _, k := range keys { - if _, err := os.Stat(k); err != nil { - decodeKey, err := base64.StdEncoding.DecodeString(k) - if err != nil { - logrus.Warnf("error decoding key data") - continue - } - tmpfileName, err := CreateTmpFile("/run/", "", decodeKey) - if err != nil { - logrus.Warnf("error creating key date temp file %s", err) - } - defer os.Remove(tmpfileName) - k = tmpfileName + decodeKey, err := base64.StdEncoding.DecodeString(k) + if err != nil { + logrus.Warnf("error decoding key data") + continue } + tmpfileName, err := CreateTmpFile("", "", decodeKey) + if err != nil { + logrus.Warnf("error creating key date temp file %s", err) + } + defer os.Remove(tmpfileName) + k = tmpfileName cmd := exec.Command("gpg2", "--with-colons", k) results, err := cmd.Output() if err != nil { logrus.Warnf("error get key identity: %s", err) continue } - resultsStr := *(*string)(unsafe.Pointer(&results)) - scanner := bufio.NewScanner(strings.NewReader(resultsStr)) - var parseduids []string - for scanner.Scan() { - line := scanner.Text() - if strings.HasPrefix(line, "uid:") || strings.HasPrefix(line, "pub:") { - uid := strings.Split(line, ":")[9] - if uid == "" { - continue - } - parseduid := uid - if strings.Contains(uid, "<") && strings.Contains(uid, ">") { - parseduid = strings.SplitN(strings.SplitAfterN(uid, "<", 2)[1], ">", 2)[0] - } - parseduids = append(parseduids, parseduid) + uids = append(uids, parseUids(results)...) + } + return uids +} + +func parseUids(colonDelimitKeys []byte) []string { + var parseduids []string + scanner := bufio.NewScanner(bytes.NewReader(colonDelimitKeys)) + for scanner.Scan() { + line := scanner.Text() + if strings.HasPrefix(line, "uid:") || strings.HasPrefix(line, "pub:") { + uid := strings.Split(line, ":")[9] + if uid == "" { + continue + } + parseduid := uid + if strings.Contains(uid, "<") && strings.Contains(uid, ">") { + parseduid = strings.SplitN(strings.SplitAfterN(uid, "<", 2)[1], ">", 2)[0] } + parseduids = append(parseduids, parseduid) } - return strings.Join(parseduids, ",") } - return "" + return parseduids } -// GetPolicyJSON return the struct to show policy.json in json format -func GetPolicyJSON(policyContentStruct PolicyContent, systemRegistriesDirPath string) (map[string]map[string]interface{}, error) { +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 +} + +// GetPolicy return the struct to show policy.json in json format and a map (reponame, ShowOutput) pair for image trust show command +func GetPolicy(policyContentStruct PolicyContent, systemRegistriesDirPath string) (map[string]map[string]interface{}, map[string]ShowOutput, error) { registryConfigs, err := LoadAndMergeConfig(systemRegistriesDirPath) if err != nil { - return nil, err + return nil, nil, err } + trustShowOutputMap := make(map[string]ShowOutput) policyJSON := make(map[string]map[string]interface{}) if len(policyContentStruct.Default) > 0 { policyJSON["* (default)"] = make(map[string]interface{}) policyJSON["* (default)"]["type"] = policyContentStruct.Default[0].Type + + var defaultPolicyStruct ShowOutput + defaultPolicyStruct.Repo = "default" + defaultPolicyStruct.Trusttype = trustTypeDescription(policyContentStruct.Default[0].Type) + trustShowOutputMap["* (default)"] = defaultPolicyStruct } for transname, transval := range policyContentStruct.Transports { for repo, repoval := range transval { + tempTrustShowOutput := ShowOutput{ + Repo: repo, + Trusttype: repoval[0].Type, + } policyJSON[repo] = make(map[string]interface{}) policyJSON[repo]["type"] = repoval[0].Type policyJSON[repo]["transport"] = transname + keyDataArr := []string{} + keyPathArr := []string{} + keyarr := []string{} for _, repoele := range repoval { - keyarr := []string{} if len(repoele.KeyPath) > 0 { keyarr = append(keyarr, repoele.KeyPath) + keyPathArr = append(keyPathArr, repoele.KeyPath) } if len(repoele.KeyData) > 0 { keyarr = append(keyarr, string(repoele.KeyData)) + keyDataArr = append(keyDataArr, string(repoele.KeyData)) } - policyJSON[repo]["keys"] = keyarr } + policyJSON[repo]["keys"] = keyarr + uids := append(getGPGIdFromKeyPath(keyPathArr), getGPGIdFromKeyData(keyDataArr)...) + tempTrustShowOutput.GPGid = strings.Join(uids, ",") + policyJSON[repo]["sigstore"] = "" registryNamespace := HaveMatchRegistry(repo, registryConfigs) if registryNamespace != nil { policyJSON[repo]["sigstore"] = registryNamespace.SigStore + tempTrustShowOutput.Sigstore = registryNamespace.SigStore } + trustShowOutputMap[repo] = tempTrustShowOutput } } - return policyJSON, nil + return policyJSON, trustShowOutputMap, nil } -- cgit v1.2.3-54-g00ecf