github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/pkg/trust/trust.go (about) 1 package trust 2 3 import ( 4 "bufio" 5 "bytes" 6 "encoding/base64" 7 "encoding/json" 8 "io/ioutil" 9 "os" 10 "os/exec" 11 "path/filepath" 12 "strings" 13 14 "github.com/containers/image/v5/types" 15 "github.com/docker/docker/pkg/homedir" 16 "github.com/ghodss/yaml" 17 "github.com/pkg/errors" 18 "github.com/sirupsen/logrus" 19 ) 20 21 // PolicyContent struct for policy.json file 22 type PolicyContent struct { 23 Default []RepoContent `json:"default"` 24 Transports TransportsContent `json:"transports,omitempty"` 25 } 26 27 // RepoContent struct used under each repo 28 type RepoContent struct { 29 Type string `json:"type"` 30 KeyType string `json:"keyType,omitempty"` 31 KeyPath string `json:"keyPath,omitempty"` 32 KeyData string `json:"keyData,omitempty"` 33 SignedIdentity json.RawMessage `json:"signedIdentity,omitempty"` 34 } 35 36 // RepoMap map repo name to policycontent for each repo 37 type RepoMap map[string][]RepoContent 38 39 // TransportsContent struct for content under "transports" 40 type TransportsContent map[string]RepoMap 41 42 // RegistryConfiguration is one of the files in registriesDirPath configuring lookaside locations, or the result of merging them all. 43 // NOTE: Keep this in sync with docs/registries.d.md! 44 type RegistryConfiguration struct { 45 DefaultDocker *RegistryNamespace `json:"default-docker"` 46 // The key is a namespace, using fully-expanded Docker reference format or parent namespaces (per dockerReference.PolicyConfiguration*), 47 Docker map[string]RegistryNamespace `json:"docker"` 48 } 49 50 // RegistryNamespace defines lookaside locations for a single namespace. 51 type RegistryNamespace struct { 52 SigStore string `json:"sigstore"` // For reading, and if SigStoreStaging is not present, for writing. 53 SigStoreStaging string `json:"sigstore-staging"` // For writing only. 54 } 55 56 // ShowOutput keep the fields for image trust show command 57 type ShowOutput struct { 58 Repo string 59 Trusttype string 60 GPGid string 61 Sigstore string 62 } 63 64 // systemRegistriesDirPath is the path to registries.d. 65 const systemRegistriesDirPath = "/etc/containers/registries.d" 66 67 // userRegistriesDir is the path to the per user registries.d. 68 var userRegistriesDir = filepath.FromSlash(".config/containers/registries.d") 69 70 // DefaultPolicyPath returns a path to the default policy of the system. 71 func DefaultPolicyPath(sys *types.SystemContext) string { 72 systemDefaultPolicyPath := "/etc/containers/policy.json" 73 if sys != nil { 74 if sys.SignaturePolicyPath != "" { 75 return sys.SignaturePolicyPath 76 } 77 if sys.RootForImplicitAbsolutePaths != "" { 78 return filepath.Join(sys.RootForImplicitAbsolutePaths, systemDefaultPolicyPath) 79 } 80 } 81 return systemDefaultPolicyPath 82 } 83 84 // RegistriesDirPath returns a path to registries.d 85 func RegistriesDirPath(sys *types.SystemContext) string { 86 if sys != nil && sys.RegistriesDirPath != "" { 87 return sys.RegistriesDirPath 88 } 89 userRegistriesDirPath := filepath.Join(homedir.Get(), userRegistriesDir) 90 if _, err := os.Stat(userRegistriesDirPath); err == nil { 91 return userRegistriesDirPath 92 } 93 if sys != nil && sys.RootForImplicitAbsolutePaths != "" { 94 return filepath.Join(sys.RootForImplicitAbsolutePaths, systemRegistriesDirPath) 95 } 96 97 return systemRegistriesDirPath 98 } 99 100 // LoadAndMergeConfig loads configuration files in dirPath 101 func LoadAndMergeConfig(dirPath string) (*RegistryConfiguration, error) { 102 mergedConfig := RegistryConfiguration{Docker: map[string]RegistryNamespace{}} 103 dockerDefaultMergedFrom := "" 104 nsMergedFrom := map[string]string{} 105 106 dir, err := os.Open(dirPath) 107 if err != nil { 108 if os.IsNotExist(err) { 109 return &mergedConfig, nil 110 } 111 return nil, err 112 } 113 configNames, err := dir.Readdirnames(0) 114 if err != nil { 115 return nil, err 116 } 117 for _, configName := range configNames { 118 if !strings.HasSuffix(configName, ".yaml") { 119 continue 120 } 121 configPath := filepath.Join(dirPath, configName) 122 configBytes, err := ioutil.ReadFile(configPath) 123 if err != nil { 124 return nil, err 125 } 126 var config RegistryConfiguration 127 err = yaml.Unmarshal(configBytes, &config) 128 if err != nil { 129 return nil, errors.Wrapf(err, "error parsing %s", configPath) 130 } 131 if config.DefaultDocker != nil { 132 if mergedConfig.DefaultDocker != nil { 133 return nil, errors.Errorf(`Error parsing signature storage configuration: "default-docker" defined both in "%s" and "%s"`, 134 dockerDefaultMergedFrom, configPath) 135 } 136 mergedConfig.DefaultDocker = config.DefaultDocker 137 dockerDefaultMergedFrom = configPath 138 } 139 for nsName, nsConfig := range config.Docker { // includes config.Docker == nil 140 if _, ok := mergedConfig.Docker[nsName]; ok { 141 return nil, errors.Errorf(`Error parsing signature storage configuration: "docker" namespace "%s" defined both in "%s" and "%s"`, 142 nsName, nsMergedFrom[nsName], configPath) 143 } 144 mergedConfig.Docker[nsName] = nsConfig 145 nsMergedFrom[nsName] = configPath 146 } 147 } 148 return &mergedConfig, nil 149 } 150 151 // HaveMatchRegistry checks if trust settings for the registry have been configured in yaml file 152 func HaveMatchRegistry(key string, registryConfigs *RegistryConfiguration) *RegistryNamespace { 153 searchKey := key 154 if !strings.Contains(searchKey, "/") { 155 val, exists := registryConfigs.Docker[searchKey] 156 if exists { 157 return &val 158 } 159 } 160 for range strings.Split(key, "/") { 161 val, exists := registryConfigs.Docker[searchKey] 162 if exists { 163 return &val 164 } 165 if strings.Contains(searchKey, "/") { 166 searchKey = searchKey[:strings.LastIndex(searchKey, "/")] 167 } 168 } 169 return registryConfigs.DefaultDocker 170 } 171 172 // CreateTmpFile creates a temp file under dir and writes the content into it 173 func CreateTmpFile(dir, pattern string, content []byte) (string, error) { 174 tmpfile, err := ioutil.TempFile(dir, pattern) 175 if err != nil { 176 return "", err 177 } 178 defer tmpfile.Close() 179 180 if _, err := tmpfile.Write(content); err != nil { 181 return "", err 182 } 183 return tmpfile.Name(), nil 184 } 185 186 // GetGPGIdFromKeyPath return user keyring from key path 187 func GetGPGIdFromKeyPath(path string) []string { 188 cmd := exec.Command("gpg2", "--with-colons", path) 189 results, err := cmd.Output() 190 if err != nil { 191 logrus.Errorf("Getting key identity: %s", err) 192 return nil 193 } 194 return parseUids(results) 195 } 196 197 // GetGPGIdFromKeyData return user keyring from keydata 198 func GetGPGIdFromKeyData(key string) []string { 199 decodeKey, err := base64.StdEncoding.DecodeString(key) 200 if err != nil { 201 logrus.Errorf("%s, error decoding key data", err) 202 return nil 203 } 204 tmpfileName, err := CreateTmpFile("", "", decodeKey) 205 if err != nil { 206 logrus.Errorf("Creating key date temp file %s", err) 207 } 208 defer os.Remove(tmpfileName) 209 return GetGPGIdFromKeyPath(tmpfileName) 210 } 211 212 func parseUids(colonDelimitKeys []byte) []string { 213 var parseduids []string 214 scanner := bufio.NewScanner(bytes.NewReader(colonDelimitKeys)) 215 for scanner.Scan() { 216 line := scanner.Text() 217 if strings.HasPrefix(line, "uid:") || strings.HasPrefix(line, "pub:") { 218 uid := strings.Split(line, ":")[9] 219 if uid == "" { 220 continue 221 } 222 parseduid := uid 223 if strings.Contains(uid, "<") && strings.Contains(uid, ">") { 224 parseduid = strings.SplitN(strings.SplitAfterN(uid, "<", 2)[1], ">", 2)[0] 225 } 226 parseduids = append(parseduids, parseduid) 227 } 228 } 229 return parseduids 230 } 231 232 // GetPolicy parse policy.json into PolicyContent struct 233 func GetPolicy(policyPath string) (PolicyContent, error) { 234 var policyContentStruct PolicyContent 235 policyContent, err := ioutil.ReadFile(policyPath) 236 if err != nil { 237 return policyContentStruct, errors.Wrap(err, "unable to read policy file") 238 } 239 if err := json.Unmarshal(policyContent, &policyContentStruct); err != nil { 240 return policyContentStruct, errors.Wrapf(err, "could not parse trust policies from %s", policyPath) 241 } 242 return policyContentStruct, nil 243 }