mirror of
https://github.com/containers/skopeo.git
synced 2025-09-21 09:57:19 +00:00
enforce blocking of registries
Vendor in the latest c/image to enforce blocking of registries when creating a c/image/docker.dockerClient. Add integration tests to avoid regressions. Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
This commit is contained in:
3
vendor/github.com/containers/image/docker/docker_client.go
generated
vendored
3
vendor/github.com/containers/image/docker/docker_client.go
generated
vendored
@@ -254,6 +254,9 @@ func newDockerClient(sys *types.SystemContext, registry, reference string) (*doc
|
||||
return nil, errors.Wrapf(err, "error loading registries")
|
||||
}
|
||||
if reg != nil {
|
||||
if reg.Blocked {
|
||||
return nil, fmt.Errorf("registry %s is blocked in %s", reg.Prefix, sysregistriesv2.ConfigPath(sys))
|
||||
}
|
||||
skipVerify = reg.Insecure
|
||||
}
|
||||
tlsClientConfig.InsecureSkipVerify = skipVerify
|
||||
|
23
vendor/github.com/containers/image/pkg/docker/config/config.go
generated
vendored
23
vendor/github.com/containers/image/pkg/docker/config/config.go
generated
vendored
@@ -35,6 +35,8 @@ var (
|
||||
// ErrNotLoggedIn is returned for users not logged into a registry
|
||||
// that they are trying to logout of
|
||||
ErrNotLoggedIn = errors.New("not logged in")
|
||||
// ErrNotSupported is returned for unsupported methods
|
||||
ErrNotSupported = errors.New("not supported")
|
||||
)
|
||||
|
||||
// SetAuthentication stores the username and password in the auth.json file
|
||||
@@ -44,6 +46,13 @@ func SetAuthentication(sys *types.SystemContext, registry, username, password st
|
||||
return false, setAuthToCredHelper(ch, registry, username, password)
|
||||
}
|
||||
|
||||
err := setAuthToKernelKeyring(registry, username, password)
|
||||
if err == nil {
|
||||
logrus.Debugf("credentials for (%s, %s) were stored in the kernel keyring\n", registry, username)
|
||||
return false, nil
|
||||
}
|
||||
logrus.Debugf("failed to authenticate with the kernel keyring, falling back to authfiles.")
|
||||
|
||||
creds := base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
|
||||
newCreds := dockerAuthConfig{Auth: creds}
|
||||
auths.AuthConfigs[registry] = newCreds
|
||||
@@ -60,6 +69,12 @@ func GetAuthentication(sys *types.SystemContext, registry string) (string, strin
|
||||
return sys.DockerAuthConfig.Username, sys.DockerAuthConfig.Password, nil
|
||||
}
|
||||
|
||||
username, password, err := getAuthFromKernelKeyring(registry)
|
||||
if err == nil {
|
||||
logrus.Debug("returning credentials from kernel keyring")
|
||||
return username, password, nil
|
||||
}
|
||||
|
||||
dockerLegacyPath := filepath.Join(homedir.Get(), dockerLegacyHomePath)
|
||||
var paths []string
|
||||
pathToAuth, err := getPathToAuth(sys)
|
||||
@@ -97,6 +112,14 @@ func RemoveAuthentication(sys *types.SystemContext, registry string) error {
|
||||
return false, deleteAuthFromCredHelper(ch, registry)
|
||||
}
|
||||
|
||||
// Next try kernel keyring
|
||||
err := deleteAuthFromKernelKeyring(registry)
|
||||
if err == nil {
|
||||
logrus.Debugf("credentials for %s were deleted from the kernel keyring", registry)
|
||||
return false, nil
|
||||
}
|
||||
logrus.Debugf("failed to delete credentials from the kernel keyring, falling back to authfiles")
|
||||
|
||||
if _, ok := auths.AuthConfigs[registry]; ok {
|
||||
delete(auths.AuthConfigs, registry)
|
||||
} else if _, ok := auths.AuthConfigs[normalizeRegistry(registry)]; ok {
|
||||
|
79
vendor/github.com/containers/image/pkg/docker/config/config_linux.go
generated
vendored
Normal file
79
vendor/github.com/containers/image/pkg/docker/config/config_linux.go
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/image/pkg/keyctl"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func getAuthFromKernelKeyring(registry string) (string, string, error) {
|
||||
userkeyring, err := keyctl.UserKeyring()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
key, err := userkeyring.Search(genDescription(registry))
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
authData, err := key.Get()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
parts := strings.SplitN(string(authData), "\x00", 2)
|
||||
if len(parts) != 2 {
|
||||
return "", "", nil
|
||||
}
|
||||
return parts[0], parts[1], nil
|
||||
}
|
||||
|
||||
func deleteAuthFromKernelKeyring(registry string) error {
|
||||
userkeyring, err := keyctl.UserKeyring()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key, err := userkeyring.Search(genDescription(registry))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return key.Unlink()
|
||||
}
|
||||
|
||||
func setAuthToKernelKeyring(registry, username, password string) error {
|
||||
keyring, err := keyctl.SessionKeyring()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
id, err := keyring.Add(genDescription(registry), []byte(fmt.Sprintf("%s\x00%s", username, password)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// sets all permission(view,read,write,search,link,set attribute) for current user
|
||||
// it enables the user to search the key after it linked to user keyring and unlinked from session keyring
|
||||
err = keyctl.SetPerm(id, keyctl.PermUserAll)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// link the key to userKeyring
|
||||
userKeyring, err := keyctl.UserKeyring()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error getting user keyring")
|
||||
}
|
||||
err = keyctl.Link(userKeyring, id)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error linking the key to user keyring")
|
||||
}
|
||||
// unlink the key from session keyring
|
||||
err = keyctl.Unlink(keyring, id)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error unlinking the key from session keyring")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func genDescription(registry string) string {
|
||||
return fmt.Sprintf("container-registry-login:%s", registry)
|
||||
}
|
16
vendor/github.com/containers/image/pkg/docker/config/config_unsupported.go
generated
vendored
Normal file
16
vendor/github.com/containers/image/pkg/docker/config/config_unsupported.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
// +build !linux
|
||||
// +build !386 !amd64
|
||||
|
||||
package config
|
||||
|
||||
func getAuthFromKernelKeyring(registry string) (string, string, error) {
|
||||
return "", "", ErrNotSupported
|
||||
}
|
||||
|
||||
func deleteAuthFromKernelKeyring(registry string) error {
|
||||
return ErrNotSupported
|
||||
}
|
||||
|
||||
func setAuthToKernelKeyring(registry, username, password string) error {
|
||||
return ErrNotSupported
|
||||
}
|
65
vendor/github.com/containers/image/pkg/keyctl/key.go
generated
vendored
Normal file
65
vendor/github.com/containers/image/pkg/keyctl/key.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
// Copyright 2015 Jesse Sipprell. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux
|
||||
// +build 386 amd64
|
||||
|
||||
package keyctl
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Key represents a single key linked to one or more kernel keyrings.
|
||||
type Key struct {
|
||||
Name string
|
||||
|
||||
id, ring keyID
|
||||
size int
|
||||
}
|
||||
|
||||
// ID returns the 32-bit kernel identifier for a specific key
|
||||
func (k *Key) ID() int32 {
|
||||
return int32(k.id)
|
||||
}
|
||||
|
||||
// Get the key's value as a byte slice
|
||||
func (k *Key) Get() ([]byte, error) {
|
||||
var (
|
||||
b []byte
|
||||
err error
|
||||
sizeRead int
|
||||
)
|
||||
|
||||
if k.size == 0 {
|
||||
k.size = 512
|
||||
}
|
||||
|
||||
size := k.size
|
||||
|
||||
b = make([]byte, int(size))
|
||||
sizeRead = size + 1
|
||||
for sizeRead > size {
|
||||
r1, _, err := keyctl(keyctlRead, uintptr(k.id), uintptr(unsafe.Pointer(&b[0])), uintptr(size))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if sizeRead = int(r1); sizeRead > size {
|
||||
b = make([]byte, sizeRead)
|
||||
size = sizeRead
|
||||
sizeRead = size + 1
|
||||
} else {
|
||||
k.size = sizeRead
|
||||
}
|
||||
}
|
||||
return b[:k.size], err
|
||||
}
|
||||
|
||||
// Unlink a key from the keyring it was loaded from (or added to). If the key
|
||||
// is not linked to any other keyrings, it is destroyed.
|
||||
func (k *Key) Unlink() error {
|
||||
_, _, err := keyctl(keyctlUnlink, uintptr(k.id), uintptr(k.ring))
|
||||
return err
|
||||
}
|
73
vendor/github.com/containers/image/pkg/keyctl/keyring.go
generated
vendored
Normal file
73
vendor/github.com/containers/image/pkg/keyctl/keyring.go
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright 2015 Jesse Sipprell. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux
|
||||
// +build 386 amd64
|
||||
|
||||
// Package keyctl is a Go interface to linux kernel keyrings (keyctl interface)
|
||||
package keyctl
|
||||
|
||||
// Keyring is the basic interface to a linux keyctl keyring.
|
||||
type Keyring interface {
|
||||
ID
|
||||
Add(string, []byte) (*Key, error)
|
||||
Search(string) (*Key, error)
|
||||
}
|
||||
|
||||
type keyring struct {
|
||||
id keyID
|
||||
}
|
||||
|
||||
// ID is unique 32-bit serial number identifiers for all Keys and Keyrings have.
|
||||
type ID interface {
|
||||
ID() int32
|
||||
}
|
||||
|
||||
// Add a new key to a keyring. The key can be searched for later by name.
|
||||
func (kr *keyring) Add(name string, key []byte) (*Key, error) {
|
||||
r, err := addkey("user", name, key, int32(kr.id))
|
||||
if err == nil {
|
||||
key := &Key{Name: name, id: keyID(r), ring: kr.id}
|
||||
return key, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Search for a key by name, this also searches child keyrings linked to this
|
||||
// one. The key, if found, is linked to the top keyring that Search() was called
|
||||
// from.
|
||||
func (kr *keyring) Search(name string) (*Key, error) {
|
||||
id, err := searchKeyring(kr.id, name, "user")
|
||||
if err == nil {
|
||||
return &Key{Name: name, id: id, ring: kr.id}, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// ID returns the 32-bit kernel identifier of a keyring
|
||||
func (kr *keyring) ID() int32 {
|
||||
return int32(kr.id)
|
||||
}
|
||||
|
||||
// SessionKeyring returns the current login session keyring
|
||||
func SessionKeyring() (Keyring, error) {
|
||||
return newKeyring(keySpecSessionKeyring)
|
||||
}
|
||||
|
||||
// UserKeyring returns the keyring specific to the current user.
|
||||
func UserKeyring() (Keyring, error) {
|
||||
return newKeyring(keySpecUserKeyring)
|
||||
}
|
||||
|
||||
// Unlink an object from a keyring
|
||||
func Unlink(parent Keyring, child ID) error {
|
||||
_, _, err := keyctl(keyctlUnlink, uintptr(child.ID()), uintptr(parent.ID()))
|
||||
return err
|
||||
}
|
||||
|
||||
// Link a key into a keyring
|
||||
func Link(parent Keyring, child ID) error {
|
||||
_, _, err := keyctl(keyctlLink, uintptr(child.ID()), uintptr(parent.ID()))
|
||||
return err
|
||||
}
|
29
vendor/github.com/containers/image/pkg/keyctl/perm.go
generated
vendored
Normal file
29
vendor/github.com/containers/image/pkg/keyctl/perm.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright 2015 Jesse Sipprell. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux
|
||||
|
||||
package keyctl
|
||||
|
||||
// KeyPerm represents in-kernel access control permission to keys and keyrings
|
||||
// as a 32-bit integer broken up into four permission sets, one per byte.
|
||||
// In MSB order, the perms are: Processor, User, Group, Other.
|
||||
type KeyPerm uint32
|
||||
|
||||
const (
|
||||
// PermOtherAll sets all permission for Other
|
||||
PermOtherAll KeyPerm = 0x3f << (8 * iota)
|
||||
// PermGroupAll sets all permission for Group
|
||||
PermGroupAll
|
||||
// PermUserAll sets all permission for User
|
||||
PermUserAll
|
||||
// PermProcessAll sets all permission for Processor
|
||||
PermProcessAll
|
||||
)
|
||||
|
||||
// SetPerm sets the permissions on a key or keyring.
|
||||
func SetPerm(k ID, p KeyPerm) error {
|
||||
_, _, err := keyctl(keyctlSetPerm, uintptr(k.ID()), uintptr(p))
|
||||
return err
|
||||
}
|
121
vendor/github.com/containers/image/pkg/keyctl/sys_linux.go
generated
vendored
Normal file
121
vendor/github.com/containers/image/pkg/keyctl/sys_linux.go
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
// Copyright 2015 Jesse Sipprell. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux
|
||||
// +build 386 amd64
|
||||
|
||||
package keyctl
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type keyctlCommand int
|
||||
|
||||
type keyID int32
|
||||
|
||||
const (
|
||||
keySpecSessionKeyring keyID = -3
|
||||
keySpecUserKeyring keyID = -4
|
||||
)
|
||||
|
||||
const (
|
||||
keyctlGetKeyringID keyctlCommand = 0
|
||||
keyctlSetPerm keyctlCommand = 5
|
||||
keyctlLink keyctlCommand = 8
|
||||
keyctlUnlink keyctlCommand = 9
|
||||
keyctlSearch keyctlCommand = 10
|
||||
keyctlRead keyctlCommand = 11
|
||||
)
|
||||
|
||||
func (id keyID) ID() int32 {
|
||||
return int32(id)
|
||||
}
|
||||
|
||||
func keyctl(cmd keyctlCommand, args ...uintptr) (r1 int32, r2 int32, err error) {
|
||||
a := make([]uintptr, 6)
|
||||
l := len(args)
|
||||
if l > 5 {
|
||||
l = 5
|
||||
}
|
||||
a[0] = uintptr(cmd)
|
||||
for idx, v := range args[:l] {
|
||||
a[idx+1] = v
|
||||
}
|
||||
v1, v2, errno := syscall.Syscall6(syscallKeyctl, a[0], a[1], a[2], a[3], a[4], a[5])
|
||||
if errno != 0 {
|
||||
err = errno
|
||||
return
|
||||
}
|
||||
|
||||
r1 = int32(v1)
|
||||
r2 = int32(v2)
|
||||
return
|
||||
}
|
||||
|
||||
func addkey(keyType, keyDesc string, payload []byte, id int32) (int32, error) {
|
||||
var (
|
||||
err error
|
||||
errno syscall.Errno
|
||||
b1, b2 *byte
|
||||
r1 uintptr
|
||||
pptr unsafe.Pointer
|
||||
)
|
||||
|
||||
if b1, err = syscall.BytePtrFromString(keyType); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if b2, err = syscall.BytePtrFromString(keyDesc); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if len(payload) > 0 {
|
||||
pptr = unsafe.Pointer(&payload[0])
|
||||
}
|
||||
r1, _, errno = syscall.Syscall6(syscallAddKey,
|
||||
uintptr(unsafe.Pointer(b1)),
|
||||
uintptr(unsafe.Pointer(b2)),
|
||||
uintptr(pptr),
|
||||
uintptr(len(payload)),
|
||||
uintptr(id),
|
||||
0)
|
||||
|
||||
if errno != 0 {
|
||||
err = errno
|
||||
return 0, err
|
||||
}
|
||||
return int32(r1), nil
|
||||
}
|
||||
|
||||
func newKeyring(id keyID) (*keyring, error) {
|
||||
r1, _, err := keyctl(keyctlGetKeyringID, uintptr(id), uintptr(1))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if id < 0 {
|
||||
r1 = int32(id)
|
||||
}
|
||||
return &keyring{id: keyID(r1)}, nil
|
||||
}
|
||||
|
||||
func searchKeyring(id keyID, name, keyType string) (keyID, error) {
|
||||
var (
|
||||
r1 int32
|
||||
b1, b2 *byte
|
||||
err error
|
||||
)
|
||||
|
||||
if b1, err = syscall.BytePtrFromString(keyType); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if b2, err = syscall.BytePtrFromString(name); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
r1, _, err = keyctl(keyctlSearch, uintptr(id), uintptr(unsafe.Pointer(b1)), uintptr(unsafe.Pointer(b2)))
|
||||
return keyID(r1), err
|
||||
}
|
12
vendor/github.com/containers/image/pkg/keyctl/sys_linux_386.go
generated
vendored
Normal file
12
vendor/github.com/containers/image/pkg/keyctl/sys_linux_386.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright 2015 Jesse Sipprell. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux
|
||||
|
||||
package keyctl
|
||||
|
||||
const (
|
||||
syscallKeyctl uintptr = 288
|
||||
syscallAddKey uintptr = 286
|
||||
)
|
12
vendor/github.com/containers/image/pkg/keyctl/sys_linux_amd64.go
generated
vendored
Normal file
12
vendor/github.com/containers/image/pkg/keyctl/sys_linux_amd64.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright 2015 Jesse Sipprell. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux
|
||||
|
||||
package keyctl
|
||||
|
||||
const (
|
||||
syscallKeyctl uintptr = 250
|
||||
syscallAddKey uintptr = 248
|
||||
)
|
7
vendor/github.com/containers/image/pkg/sysregistriesv2/system_registries_v2.go
generated
vendored
7
vendor/github.com/containers/image/pkg/sysregistriesv2/system_registries_v2.go
generated
vendored
@@ -303,9 +303,8 @@ func (config *V2RegistriesConf) postProcess() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// getConfigPath returns the system-registries config path if specified.
|
||||
// Otherwise, systemRegistriesConfPath is returned.
|
||||
func getConfigPath(ctx *types.SystemContext) string {
|
||||
// ConfigPath returns the path to the system-wide registry configuration file.
|
||||
func ConfigPath(ctx *types.SystemContext) string {
|
||||
confPath := systemRegistriesConfPath
|
||||
if ctx != nil {
|
||||
if ctx.SystemRegistriesConfPath != "" {
|
||||
@@ -336,7 +335,7 @@ func InvalidateCache() {
|
||||
|
||||
// getConfig returns the config object corresponding to ctx, loading it if it is not yet cached.
|
||||
func getConfig(ctx *types.SystemContext) (*V2RegistriesConf, error) {
|
||||
configPath := getConfigPath(ctx)
|
||||
configPath := ConfigPath(ctx)
|
||||
|
||||
configMutex.Lock()
|
||||
defer configMutex.Unlock()
|
||||
|
2
vendor/github.com/containers/image/signature/policy_types.go
generated
vendored
2
vendor/github.com/containers/image/signature/policy_types.go
generated
vendored
@@ -6,7 +6,7 @@
|
||||
|
||||
package signature
|
||||
|
||||
// NOTE: Keep this in sync with docs/policy.json.md!
|
||||
// NOTE: Keep this in sync with docs/containers-policy.json.5.md!
|
||||
|
||||
// Policy defines requirements for considering a signature, or an image, valid.
|
||||
type Policy struct {
|
||||
|
2
vendor/github.com/containers/image/transports/alltransports/alltransports.go
generated
vendored
2
vendor/github.com/containers/image/transports/alltransports/alltransports.go
generated
vendored
@@ -4,7 +4,7 @@ import (
|
||||
"strings"
|
||||
|
||||
// register all known transports
|
||||
// NOTE: Make sure docs/policy.json.md is updated when adding or updating
|
||||
// NOTE: Make sure docs/containers-policy.json.5.md is updated when adding or updating
|
||||
// a transport.
|
||||
_ "github.com/containers/image/directory"
|
||||
_ "github.com/containers/image/docker"
|
||||
|
2
vendor/github.com/containers/image/version/version.go
generated
vendored
2
vendor/github.com/containers/image/version/version.go
generated
vendored
@@ -8,7 +8,7 @@ const (
|
||||
// VersionMinor is for functionality in a backwards-compatible manner
|
||||
VersionMinor = 0
|
||||
// VersionPatch is for backwards-compatible bug fixes
|
||||
VersionPatch = 1
|
||||
VersionPatch = 2
|
||||
|
||||
// VersionDev indicates development branch. Releases will be empty string.
|
||||
VersionDev = "-dev"
|
||||
|
Reference in New Issue
Block a user