mirror of
https://github.com/containers/podman.git
synced 2026-03-13 08:01:19 +08:00
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:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user