mirror of
https://github.com/podman-container-tools/podman.git
synced 2026-08-10 10:55:46 +00:00
Reorganize pkg/trust
Split the existing code into policy.go and registries.go, depending on which files it concerns. Only moves unchanged code, should not change behavior. Signed-off-by: Miloslav Trmač <mitr@redhat.com>
This commit is contained in:
parent
5f03e2f804
commit
d591e00100
4 changed files with 255 additions and 244 deletions
|
|
@ -1,12 +0,0 @@
|
|||
package trust
|
||||
|
||||
// Policy describes a basic trust policy configuration
|
||||
type Policy struct {
|
||||
Transport string `json:"transport"`
|
||||
Name string `json:"name,omitempty"`
|
||||
RepoName string `json:"repo_name,omitempty"`
|
||||
Keys []string `json:"keys,omitempty"`
|
||||
SignatureStore string `json:"sigstore,omitempty"`
|
||||
Type string `json:"type"`
|
||||
GPGId string `json:"gpg_id,omitempty"`
|
||||
}
|
||||
125
pkg/trust/policy.go
Normal file
125
pkg/trust/policy.go
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
package trust
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// PolicyContent struct for policy.json file
|
||||
type PolicyContent struct {
|
||||
Default []RepoContent `json:"default"`
|
||||
Transports TransportsContent `json:"transports,omitempty"`
|
||||
}
|
||||
|
||||
// RepoContent struct used under each repo
|
||||
type RepoContent struct {
|
||||
Type string `json:"type"`
|
||||
KeyType string `json:"keyType,omitempty"`
|
||||
KeyPath string `json:"keyPath,omitempty"`
|
||||
KeyData string `json:"keyData,omitempty"`
|
||||
SignedIdentity json.RawMessage `json:"signedIdentity,omitempty"`
|
||||
}
|
||||
|
||||
// RepoMap map repo name to policycontent for each repo
|
||||
type RepoMap map[string][]RepoContent
|
||||
|
||||
// TransportsContent struct for content under "transports"
|
||||
type TransportsContent map[string]RepoMap
|
||||
|
||||
// DefaultPolicyPath returns a path to the default policy of the system.
|
||||
func DefaultPolicyPath(sys *types.SystemContext) string {
|
||||
systemDefaultPolicyPath := "/etc/containers/policy.json"
|
||||
if sys != nil {
|
||||
if sys.SignaturePolicyPath != "" {
|
||||
return sys.SignaturePolicyPath
|
||||
}
|
||||
if sys.RootForImplicitAbsolutePaths != "" {
|
||||
return filepath.Join(sys.RootForImplicitAbsolutePaths, systemDefaultPolicyPath)
|
||||
}
|
||||
}
|
||||
return systemDefaultPolicyPath
|
||||
}
|
||||
|
||||
// CreateTmpFile creates a temp file under dir and writes the content into it
|
||||
func CreateTmpFile(dir, pattern string, content []byte) (string, error) {
|
||||
tmpfile, err := ioutil.TempFile(dir, pattern)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer tmpfile.Close()
|
||||
|
||||
if _, err := tmpfile.Write(content); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return tmpfile.Name(), nil
|
||||
}
|
||||
|
||||
// GetGPGIdFromKeyPath return user keyring from key path
|
||||
func GetGPGIdFromKeyPath(path string) []string {
|
||||
cmd := exec.Command("gpg2", "--with-colons", path)
|
||||
results, err := cmd.Output()
|
||||
if err != nil {
|
||||
logrus.Errorf("Getting key identity: %s", err)
|
||||
return nil
|
||||
}
|
||||
return parseUids(results)
|
||||
}
|
||||
|
||||
// GetGPGIdFromKeyData return user keyring from keydata
|
||||
func GetGPGIdFromKeyData(key string) []string {
|
||||
decodeKey, err := base64.StdEncoding.DecodeString(key)
|
||||
if err != nil {
|
||||
logrus.Errorf("%s, error decoding key data", err)
|
||||
return nil
|
||||
}
|
||||
tmpfileName, err := CreateTmpFile("", "", decodeKey)
|
||||
if err != nil {
|
||||
logrus.Errorf("Creating key date temp file %s", err)
|
||||
}
|
||||
defer os.Remove(tmpfileName)
|
||||
return GetGPGIdFromKeyPath(tmpfileName)
|
||||
}
|
||||
|
||||
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 parseduids
|
||||
}
|
||||
|
||||
// GetPolicy parse policy.json into PolicyContent struct
|
||||
func GetPolicy(policyPath string) (PolicyContent, error) {
|
||||
var policyContentStruct PolicyContent
|
||||
policyContent, err := ioutil.ReadFile(policyPath)
|
||||
if err != nil {
|
||||
return policyContentStruct, fmt.Errorf("unable to read policy file: %w", err)
|
||||
}
|
||||
if err := json.Unmarshal(policyContent, &policyContentStruct); err != nil {
|
||||
return policyContentStruct, fmt.Errorf("could not parse trust policies from %s: %w", policyPath, err)
|
||||
}
|
||||
return policyContentStruct, nil
|
||||
}
|
||||
121
pkg/trust/registries.go
Normal file
121
pkg/trust/registries.go
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
package trust
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/docker/docker/pkg/homedir"
|
||||
"github.com/ghodss/yaml"
|
||||
)
|
||||
|
||||
// RegistryConfiguration is one of the files in registriesDirPath configuring lookaside locations, or the result of merging them all.
|
||||
// NOTE: Keep this in sync with docs/registries.d.md!
|
||||
type RegistryConfiguration struct {
|
||||
DefaultDocker *RegistryNamespace `json:"default-docker"`
|
||||
// The key is a namespace, using fully-expanded Docker reference format or parent namespaces (per dockerReference.PolicyConfiguration*),
|
||||
Docker map[string]RegistryNamespace `json:"docker"`
|
||||
}
|
||||
|
||||
// RegistryNamespace defines lookaside locations for a single namespace.
|
||||
type RegistryNamespace struct {
|
||||
SigStore string `json:"sigstore"` // For reading, and if SigStoreStaging is not present, for writing.
|
||||
SigStoreStaging string `json:"sigstore-staging"` // For writing only.
|
||||
}
|
||||
|
||||
// systemRegistriesDirPath is the path to registries.d.
|
||||
const systemRegistriesDirPath = "/etc/containers/registries.d"
|
||||
|
||||
// userRegistriesDir is the path to the per user registries.d.
|
||||
var userRegistriesDir = filepath.FromSlash(".config/containers/registries.d")
|
||||
|
||||
// RegistriesDirPath returns a path to registries.d
|
||||
func RegistriesDirPath(sys *types.SystemContext) string {
|
||||
if sys != nil && sys.RegistriesDirPath != "" {
|
||||
return sys.RegistriesDirPath
|
||||
}
|
||||
userRegistriesDirPath := filepath.Join(homedir.Get(), userRegistriesDir)
|
||||
if _, err := os.Stat(userRegistriesDirPath); err == nil {
|
||||
return userRegistriesDirPath
|
||||
}
|
||||
if sys != nil && sys.RootForImplicitAbsolutePaths != "" {
|
||||
return filepath.Join(sys.RootForImplicitAbsolutePaths, systemRegistriesDirPath)
|
||||
}
|
||||
|
||||
return systemRegistriesDirPath
|
||||
}
|
||||
|
||||
// LoadAndMergeConfig loads configuration files in dirPath
|
||||
func LoadAndMergeConfig(dirPath string) (*RegistryConfiguration, error) {
|
||||
mergedConfig := RegistryConfiguration{Docker: map[string]RegistryNamespace{}}
|
||||
dockerDefaultMergedFrom := ""
|
||||
nsMergedFrom := map[string]string{}
|
||||
|
||||
dir, err := os.Open(dirPath)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return &mergedConfig, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
configNames, err := dir.Readdirnames(0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, configName := range configNames {
|
||||
if !strings.HasSuffix(configName, ".yaml") {
|
||||
continue
|
||||
}
|
||||
configPath := filepath.Join(dirPath, configName)
|
||||
configBytes, err := ioutil.ReadFile(configPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var config RegistryConfiguration
|
||||
err = yaml.Unmarshal(configBytes, &config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing %s: %w", configPath, err)
|
||||
}
|
||||
if config.DefaultDocker != nil {
|
||||
if mergedConfig.DefaultDocker != nil {
|
||||
return nil, fmt.Errorf(`error parsing signature storage configuration: "default-docker" defined both in "%s" and "%s"`,
|
||||
dockerDefaultMergedFrom, configPath)
|
||||
}
|
||||
mergedConfig.DefaultDocker = config.DefaultDocker
|
||||
dockerDefaultMergedFrom = configPath
|
||||
}
|
||||
for nsName, nsConfig := range config.Docker { // includes config.Docker == nil
|
||||
if _, ok := mergedConfig.Docker[nsName]; ok {
|
||||
return nil, fmt.Errorf(`error parsing signature storage configuration: "docker" namespace "%s" defined both in "%s" and "%s"`,
|
||||
nsName, nsMergedFrom[nsName], configPath)
|
||||
}
|
||||
mergedConfig.Docker[nsName] = nsConfig
|
||||
nsMergedFrom[nsName] = configPath
|
||||
}
|
||||
}
|
||||
return &mergedConfig, nil
|
||||
}
|
||||
|
||||
// HaveMatchRegistry checks if trust settings for the registry have been configured in yaml file
|
||||
func HaveMatchRegistry(key string, registryConfigs *RegistryConfiguration) *RegistryNamespace {
|
||||
searchKey := key
|
||||
if !strings.Contains(searchKey, "/") {
|
||||
val, exists := registryConfigs.Docker[searchKey]
|
||||
if exists {
|
||||
return &val
|
||||
}
|
||||
}
|
||||
for range strings.Split(key, "/") {
|
||||
val, exists := registryConfigs.Docker[searchKey]
|
||||
if exists {
|
||||
return &val
|
||||
}
|
||||
if strings.Contains(searchKey, "/") {
|
||||
searchKey = searchKey[:strings.LastIndex(searchKey, "/")]
|
||||
}
|
||||
}
|
||||
return registryConfigs.DefaultDocker
|
||||
}
|
||||
|
|
@ -1,235 +1,12 @@
|
|||
package trust
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/image/v5/types"
|
||||
"github.com/docker/docker/pkg/homedir"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// PolicyContent struct for policy.json file
|
||||
type PolicyContent struct {
|
||||
Default []RepoContent `json:"default"`
|
||||
Transports TransportsContent `json:"transports,omitempty"`
|
||||
}
|
||||
|
||||
// RepoContent struct used under each repo
|
||||
type RepoContent struct {
|
||||
Type string `json:"type"`
|
||||
KeyType string `json:"keyType,omitempty"`
|
||||
KeyPath string `json:"keyPath,omitempty"`
|
||||
KeyData string `json:"keyData,omitempty"`
|
||||
SignedIdentity json.RawMessage `json:"signedIdentity,omitempty"`
|
||||
}
|
||||
|
||||
// RepoMap map repo name to policycontent for each repo
|
||||
type RepoMap map[string][]RepoContent
|
||||
|
||||
// TransportsContent struct for content under "transports"
|
||||
type TransportsContent map[string]RepoMap
|
||||
|
||||
// RegistryConfiguration is one of the files in registriesDirPath configuring lookaside locations, or the result of merging them all.
|
||||
// NOTE: Keep this in sync with docs/registries.d.md!
|
||||
type RegistryConfiguration struct {
|
||||
DefaultDocker *RegistryNamespace `json:"default-docker"`
|
||||
// The key is a namespace, using fully-expanded Docker reference format or parent namespaces (per dockerReference.PolicyConfiguration*),
|
||||
Docker map[string]RegistryNamespace `json:"docker"`
|
||||
}
|
||||
|
||||
// RegistryNamespace defines lookaside locations for a single namespace.
|
||||
type RegistryNamespace struct {
|
||||
SigStore string `json:"sigstore"` // For reading, and if SigStoreStaging is not present, for writing.
|
||||
SigStoreStaging string `json:"sigstore-staging"` // For writing only.
|
||||
}
|
||||
|
||||
// systemRegistriesDirPath is the path to registries.d.
|
||||
const systemRegistriesDirPath = "/etc/containers/registries.d"
|
||||
|
||||
// userRegistriesDir is the path to the per user registries.d.
|
||||
var userRegistriesDir = filepath.FromSlash(".config/containers/registries.d")
|
||||
|
||||
// DefaultPolicyPath returns a path to the default policy of the system.
|
||||
func DefaultPolicyPath(sys *types.SystemContext) string {
|
||||
systemDefaultPolicyPath := "/etc/containers/policy.json"
|
||||
if sys != nil {
|
||||
if sys.SignaturePolicyPath != "" {
|
||||
return sys.SignaturePolicyPath
|
||||
}
|
||||
if sys.RootForImplicitAbsolutePaths != "" {
|
||||
return filepath.Join(sys.RootForImplicitAbsolutePaths, systemDefaultPolicyPath)
|
||||
}
|
||||
}
|
||||
return systemDefaultPolicyPath
|
||||
}
|
||||
|
||||
// RegistriesDirPath returns a path to registries.d
|
||||
func RegistriesDirPath(sys *types.SystemContext) string {
|
||||
if sys != nil && sys.RegistriesDirPath != "" {
|
||||
return sys.RegistriesDirPath
|
||||
}
|
||||
userRegistriesDirPath := filepath.Join(homedir.Get(), userRegistriesDir)
|
||||
if _, err := os.Stat(userRegistriesDirPath); err == nil {
|
||||
return userRegistriesDirPath
|
||||
}
|
||||
if sys != nil && sys.RootForImplicitAbsolutePaths != "" {
|
||||
return filepath.Join(sys.RootForImplicitAbsolutePaths, systemRegistriesDirPath)
|
||||
}
|
||||
|
||||
return systemRegistriesDirPath
|
||||
}
|
||||
|
||||
// LoadAndMergeConfig loads configuration files in dirPath
|
||||
func LoadAndMergeConfig(dirPath string) (*RegistryConfiguration, error) {
|
||||
mergedConfig := RegistryConfiguration{Docker: map[string]RegistryNamespace{}}
|
||||
dockerDefaultMergedFrom := ""
|
||||
nsMergedFrom := map[string]string{}
|
||||
|
||||
dir, err := os.Open(dirPath)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return &mergedConfig, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
configNames, err := dir.Readdirnames(0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, configName := range configNames {
|
||||
if !strings.HasSuffix(configName, ".yaml") {
|
||||
continue
|
||||
}
|
||||
configPath := filepath.Join(dirPath, configName)
|
||||
configBytes, err := ioutil.ReadFile(configPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var config RegistryConfiguration
|
||||
err = yaml.Unmarshal(configBytes, &config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing %s: %w", configPath, err)
|
||||
}
|
||||
if config.DefaultDocker != nil {
|
||||
if mergedConfig.DefaultDocker != nil {
|
||||
return nil, fmt.Errorf(`error parsing signature storage configuration: "default-docker" defined both in "%s" and "%s"`,
|
||||
dockerDefaultMergedFrom, configPath)
|
||||
}
|
||||
mergedConfig.DefaultDocker = config.DefaultDocker
|
||||
dockerDefaultMergedFrom = configPath
|
||||
}
|
||||
for nsName, nsConfig := range config.Docker { // includes config.Docker == nil
|
||||
if _, ok := mergedConfig.Docker[nsName]; ok {
|
||||
return nil, fmt.Errorf(`error parsing signature storage configuration: "docker" namespace "%s" defined both in "%s" and "%s"`,
|
||||
nsName, nsMergedFrom[nsName], configPath)
|
||||
}
|
||||
mergedConfig.Docker[nsName] = nsConfig
|
||||
nsMergedFrom[nsName] = configPath
|
||||
}
|
||||
}
|
||||
return &mergedConfig, nil
|
||||
}
|
||||
|
||||
// HaveMatchRegistry checks if trust settings for the registry have been configured in yaml file
|
||||
func HaveMatchRegistry(key string, registryConfigs *RegistryConfiguration) *RegistryNamespace {
|
||||
searchKey := key
|
||||
if !strings.Contains(searchKey, "/") {
|
||||
val, exists := registryConfigs.Docker[searchKey]
|
||||
if exists {
|
||||
return &val
|
||||
}
|
||||
}
|
||||
for range strings.Split(key, "/") {
|
||||
val, exists := registryConfigs.Docker[searchKey]
|
||||
if exists {
|
||||
return &val
|
||||
}
|
||||
if strings.Contains(searchKey, "/") {
|
||||
searchKey = searchKey[:strings.LastIndex(searchKey, "/")]
|
||||
}
|
||||
}
|
||||
return registryConfigs.DefaultDocker
|
||||
}
|
||||
|
||||
// CreateTmpFile creates a temp file under dir and writes the content into it
|
||||
func CreateTmpFile(dir, pattern string, content []byte) (string, error) {
|
||||
tmpfile, err := ioutil.TempFile(dir, pattern)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer tmpfile.Close()
|
||||
|
||||
if _, err := tmpfile.Write(content); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return tmpfile.Name(), nil
|
||||
}
|
||||
|
||||
// GetGPGIdFromKeyPath return user keyring from key path
|
||||
func GetGPGIdFromKeyPath(path string) []string {
|
||||
cmd := exec.Command("gpg2", "--with-colons", path)
|
||||
results, err := cmd.Output()
|
||||
if err != nil {
|
||||
logrus.Errorf("Getting key identity: %s", err)
|
||||
return nil
|
||||
}
|
||||
return parseUids(results)
|
||||
}
|
||||
|
||||
// GetGPGIdFromKeyData return user keyring from keydata
|
||||
func GetGPGIdFromKeyData(key string) []string {
|
||||
decodeKey, err := base64.StdEncoding.DecodeString(key)
|
||||
if err != nil {
|
||||
logrus.Errorf("%s, error decoding key data", err)
|
||||
return nil
|
||||
}
|
||||
tmpfileName, err := CreateTmpFile("", "", decodeKey)
|
||||
if err != nil {
|
||||
logrus.Errorf("Creating key date temp file %s", err)
|
||||
}
|
||||
defer os.Remove(tmpfileName)
|
||||
return GetGPGIdFromKeyPath(tmpfileName)
|
||||
}
|
||||
|
||||
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 parseduids
|
||||
}
|
||||
|
||||
// GetPolicy parse policy.json into PolicyContent struct
|
||||
func GetPolicy(policyPath string) (PolicyContent, error) {
|
||||
var policyContentStruct PolicyContent
|
||||
policyContent, err := ioutil.ReadFile(policyPath)
|
||||
if err != nil {
|
||||
return policyContentStruct, fmt.Errorf("unable to read policy file: %w", err)
|
||||
}
|
||||
if err := json.Unmarshal(policyContent, &policyContentStruct); err != nil {
|
||||
return policyContentStruct, fmt.Errorf("could not parse trust policies from %s: %w", policyPath, err)
|
||||
}
|
||||
return policyContentStruct, nil
|
||||
// Policy describes a basic trust policy configuration
|
||||
type Policy struct {
|
||||
Transport string `json:"transport"`
|
||||
Name string `json:"name,omitempty"`
|
||||
RepoName string `json:"repo_name,omitempty"`
|
||||
Keys []string `json:"keys,omitempty"`
|
||||
SignatureStore string `json:"sigstore,omitempty"`
|
||||
Type string `json:"type"`
|
||||
GPGId string `json:"gpg_id,omitempty"`
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue