image sign using per user registries.d

Support per user ~/.config/containers/registries.d to allow rootless image sign configurations.

Signed-off-by: Qi Wang <qiwan@redhat.com>
This commit is contained in:
Qi Wang
2020-10-27 17:25:20 -04:00
parent dc5da90523
commit cf8f2342a1
3 changed files with 42 additions and 54 deletions

View File

@@ -9,7 +9,9 @@ podman-image-sign - Create a signature for an image
## DESCRIPTION
**podman image sign** will create a local signature for one or more local images that have
been pulled from a registry. The signature will be written to a directory
derived from the registry configuration files in /etc/containers/registries.d. By default, the signature will be written into /var/lib/containers/sigstore directory.
derived from the registry configuration files in `$HOME/.config/containers/registries.d` if it exists,
otherwise `/etc/containers/registries.d` (unless overridden at compile-time), see **containers-registries.d(5)** for more information.
By default, the signature will be written into `/var/lib/containers/sigstore` for root and `$HOME/.local/share/containers/sigstore` for non-root users
## OPTIONS
@@ -38,7 +40,8 @@ Sign the busybox image with the identify of foo@bar.com with a user's keyring an
## RELATED CONFIGURATION
The write (and read) location for signatures is defined in YAML-based
configuration files in /etc/containers/registries.d/. When you sign
configuration files in /etc/containers/registries.d/ for root,
or $HOME/.config/containers/registries.d for non-root users. When you sign
an image, Podman will use those configuration files to determine
where to write the signature based on the the name of the originating
registry or a default storage value unless overridden with the --directory
@@ -53,5 +56,8 @@ the signature will be written into sub-directories of
/var/lib/containers/sigstore/privateregistry.example.com. The use of 'sigstore' also means
the signature will be 'read' from that same location on a pull-related function.
## SEE ALSO
containers-registries.d(5)
## HISTORY
November 2018, Originally compiled by Qi Wang (qiwan at redhat dot com)

View File

@@ -26,7 +26,6 @@ import (
"github.com/containers/podman/v2/pkg/domain/entities"
domainUtils "github.com/containers/podman/v2/pkg/domain/utils"
"github.com/containers/podman/v2/pkg/rootless"
"github.com/containers/podman/v2/pkg/trust"
"github.com/containers/podman/v2/pkg/util"
"github.com/containers/storage"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
@@ -34,9 +33,6 @@ import (
"github.com/sirupsen/logrus"
)
// SignatureStoreDir defines default directory to store signatures
const SignatureStoreDir = "/var/lib/containers/sigstore"
func (ir *ImageEngine) Exists(_ context.Context, nameOrID string) (*entities.BoolReport, error) {
_, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrID)
if err != nil {
@@ -707,12 +703,6 @@ func (ir *ImageEngine) Sign(ctx context.Context, names []string, options entitie
sc := ir.Libpod.SystemContext()
sc.DockerCertPath = options.CertDir
systemRegistriesDirPath := trust.RegistriesDirPath(sc)
registryConfigs, err := trust.LoadAndMergeConfig(systemRegistriesDirPath)
if err != nil {
return nil, errors.Wrapf(err, "error reading registry configuration")
}
for _, signimage := range names {
err = func() error {
srcRef, err := alltransports.ParseImageName(signimage)
@@ -738,37 +728,25 @@ func (ir *ImageEngine) Sign(ctx context.Context, names []string, options entitie
}
var sigStoreDir string
if options.Directory != "" {
sigStoreDir = options.Directory
}
if sigStoreDir == "" {
if rootless.IsRootless() {
sigStoreDir = filepath.Join(filepath.Dir(ir.Libpod.StorageConfig().GraphRoot), "sigstore")
} else {
var sigStoreURI string
registryInfo := trust.HaveMatchRegistry(rawSource.Reference().DockerReference().String(), registryConfigs)
if registryInfo != nil {
if sigStoreURI = registryInfo.SigStoreStaging; sigStoreURI == "" {
sigStoreURI = registryInfo.SigStore
}
}
if sigStoreURI == "" {
return errors.Errorf("no signature storage configuration found for %s", rawSource.Reference().DockerReference().String())
}
sigStoreDir, err = localPathFromURI(sigStoreURI)
if err != nil {
return errors.Wrapf(err, "invalid signature storage %s", sigStoreURI)
}
repo := reference.Path(dockerReference)
if path.Clean(repo) != repo { // Coverage: This should not be reachable because /./ and /../ components are not valid in docker references
return errors.Errorf("Unexpected path elements in Docker reference %s for signature storage", dockerReference.String())
}
sigStoreDir = filepath.Join(options.Directory, repo)
} else {
signatureURL, err := docker.SignatureStorageBaseURL(sc, rawSource.Reference(), true)
if err != nil {
return err
}
sigStoreDir, err = localPathFromURI(signatureURL)
if err != nil {
return err
}
}
manifestDigest, err := manifest.Digest(getManifest)
if err != nil {
return err
}
repo := reference.Path(dockerReference)
if path.Clean(repo) != repo { // Coverage: This should not be reachable because /./ and /../ components are not valid in docker references
return errors.Errorf("Unexpected path elements in Docker reference %s for signature storage", dockerReference.String())
}
// create signature
newSig, err := signature.SignDockerManifest(getManifest, dockerReference.String(), mech, options.SignBy)
@@ -776,7 +754,7 @@ func (ir *ImageEngine) Sign(ctx context.Context, names []string, options entitie
return errors.Wrapf(err, "error creating new signature")
}
// create the signstore file
signatureDir := fmt.Sprintf("%s@%s=%s", filepath.Join(sigStoreDir, repo), manifestDigest.Algorithm(), manifestDigest.Hex())
signatureDir := fmt.Sprintf("%s@%s=%s", sigStoreDir, manifestDigest.Algorithm(), manifestDigest.Hex())
if err := os.MkdirAll(signatureDir, 0751); err != nil {
// The directory is allowed to exist
if !os.IsExist(err) {
@@ -822,14 +800,9 @@ func getSigFilename(sigStoreDirPath string) (string, error) {
}
}
func localPathFromURI(sigStoreDir string) (string, error) {
url, err := url.Parse(sigStoreDir)
if err != nil {
return sigStoreDir, errors.Wrapf(err, "invalid directory %s", sigStoreDir)
}
func localPathFromURI(url *url.URL) (string, error) {
if url.Scheme != "file" {
return sigStoreDir, errors.Errorf("writing to %s is not supported. Use a supported scheme", sigStoreDir)
return "", errors.Errorf("writing to %s is not supported. Use a supported scheme", url.String())
}
sigStoreDir = url.Path
return sigStoreDir, nil
return url.Path, nil
}

View File

@@ -12,6 +12,7 @@ import (
"strings"
"github.com/containers/image/v5/types"
"github.com/docker/docker/pkg/homedir"
"github.com/ghodss/yaml"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -60,6 +61,12 @@ type ShowOutput struct {
Sigstore string
}
// 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"
@@ -76,15 +83,17 @@ func DefaultPolicyPath(sys *types.SystemContext) string {
// RegistriesDirPath returns a path to registries.d
func RegistriesDirPath(sys *types.SystemContext) string {
systemRegistriesDirPath := "/etc/containers/registries.d"
if sys != nil {
if sys.RegistriesDirPath != "" {
return sys.RegistriesDirPath
}
if sys.RootForImplicitAbsolutePaths != "" {
return filepath.Join(sys.RootForImplicitAbsolutePaths, systemRegistriesDirPath)
}
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
}