*: support insecure registries
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
This commit is contained in:
parent
8441dca284
commit
8b53fabcbd
6 changed files with 129 additions and 38 deletions
|
@ -95,6 +95,10 @@ pause_command = "{{ .PauseCommand }}"
|
||||||
# unspecified so that the default system-wide policy will be used.
|
# unspecified so that the default system-wide policy will be used.
|
||||||
signature_policy = "{{ .SignaturePolicyPath }}"
|
signature_policy = "{{ .SignaturePolicyPath }}"
|
||||||
|
|
||||||
|
# insecure_registries is used to skip TLS verification when pulling images.
|
||||||
|
insecure_registries = [
|
||||||
|
{{ range $opt := .InsecureRegistries }}{{ printf "\t%q,\n" $opt }}{{ end }}]
|
||||||
|
|
||||||
# The "crio.network" table contains settings pertaining to the
|
# The "crio.network" table contains settings pertaining to the
|
||||||
# management of CNI plugins.
|
# management of CNI plugins.
|
||||||
[crio.network]
|
[crio.network]
|
||||||
|
|
|
@ -62,6 +62,9 @@ func mergeConfig(config *server.Config, ctx *cli.Context) error {
|
||||||
if ctx.GlobalIsSet("storage-opt") {
|
if ctx.GlobalIsSet("storage-opt") {
|
||||||
config.StorageOptions = ctx.GlobalStringSlice("storage-opt")
|
config.StorageOptions = ctx.GlobalStringSlice("storage-opt")
|
||||||
}
|
}
|
||||||
|
if ctx.GlobalIsSet("insecure-registry") {
|
||||||
|
config.InsecureRegistries = ctx.GlobalStringSlice("insecure-registries")
|
||||||
|
}
|
||||||
if ctx.GlobalIsSet("default-transport") {
|
if ctx.GlobalIsSet("default-transport") {
|
||||||
config.DefaultTransport = ctx.GlobalString("default-transport")
|
config.DefaultTransport = ctx.GlobalString("default-transport")
|
||||||
}
|
}
|
||||||
|
@ -180,6 +183,10 @@ func main() {
|
||||||
Name: "storage-opt",
|
Name: "storage-opt",
|
||||||
Usage: "storage driver option",
|
Usage: "storage driver option",
|
||||||
},
|
},
|
||||||
|
cli.StringSliceFlag{
|
||||||
|
Name: "insecure-registry",
|
||||||
|
Usage: "whether to disable TLS verification for the given registry",
|
||||||
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "default-transport",
|
Name: "default-transport",
|
||||||
Usage: "default transport",
|
Usage: "default transport",
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package storage
|
package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
"github.com/containers/image/copy"
|
"github.com/containers/image/copy"
|
||||||
"github.com/containers/image/docker/reference"
|
"github.com/containers/image/docker/reference"
|
||||||
"github.com/containers/image/image"
|
"github.com/containers/image/image"
|
||||||
|
@ -19,9 +21,16 @@ type ImageResult struct {
|
||||||
Size *uint64
|
Size *uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type indexInfo struct {
|
||||||
|
name string
|
||||||
|
secure bool
|
||||||
|
}
|
||||||
|
|
||||||
type imageService struct {
|
type imageService struct {
|
||||||
store storage.Store
|
store storage.Store
|
||||||
defaultTransport string
|
defaultTransport string
|
||||||
|
insecureRegistryCIDRs []*net.IPNet
|
||||||
|
indexConfigs map[string]*indexInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImageServer wraps up various CRI-related activities into a reusable
|
// ImageServer wraps up various CRI-related activities into a reusable
|
||||||
|
@ -40,7 +49,7 @@ type ImageServer interface {
|
||||||
// when it's asked to pull an image.
|
// when it's asked to pull an image.
|
||||||
GetStore() storage.Store
|
GetStore() storage.Store
|
||||||
// CanPull preliminary checks whether we're allowed to pull an image
|
// CanPull preliminary checks whether we're allowed to pull an image
|
||||||
CanPull(imageName string, sourceCtx *types.SystemContext) (bool, error)
|
CanPull(imageName string, options *copy.Options) (bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc *imageService) ListImages(filter string) ([]ImageResult, error) {
|
func (svc *imageService) ListImages(filter string) ([]ImageResult, error) {
|
||||||
|
@ -119,22 +128,12 @@ func imageSize(img types.Image) *uint64 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc *imageService) CanPull(imageName string, sourceCtx *types.SystemContext) (bool, error) {
|
func (svc *imageService) CanPull(imageName string, options *copy.Options) (bool, error) {
|
||||||
if imageName == "" {
|
srcRef, err := svc.prepareImage(imageName, options)
|
||||||
return false, storage.ErrNotAnImage
|
|
||||||
}
|
|
||||||
srcRef, err := alltransports.ParseImageName(imageName)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if svc.defaultTransport == "" {
|
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
srcRef2, err2 := alltransports.ParseImageName(svc.defaultTransport + imageName)
|
rawSource, err := srcRef.NewImageSource(options.SourceCtx, nil)
|
||||||
if err2 != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
srcRef = srcRef2
|
|
||||||
}
|
|
||||||
rawSource, err := srcRef.NewImageSource(sourceCtx, nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
@ -148,21 +147,13 @@ func (svc *imageService) CanPull(imageName string, sourceCtx *types.SystemContex
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc *imageService) PullImage(systemContext *types.SystemContext, imageName string, options *copy.Options) (types.ImageReference, error) {
|
// prepareImage creates an image reference from an image string and set options
|
||||||
policy, err := signature.DefaultPolicy(systemContext)
|
// for the source context
|
||||||
if err != nil {
|
func (svc *imageService) prepareImage(imageName string, options *copy.Options) (types.ImageReference, error) {
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
policyContext, err := signature.NewPolicyContext(policy)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if imageName == "" {
|
if imageName == "" {
|
||||||
return nil, storage.ErrNotAnImage
|
return nil, storage.ErrNotAnImage
|
||||||
}
|
}
|
||||||
if options == nil {
|
|
||||||
options = ©.Options{}
|
|
||||||
}
|
|
||||||
srcRef, err := alltransports.ParseImageName(imageName)
|
srcRef, err := alltransports.ParseImageName(imageName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if svc.defaultTransport == "" {
|
if svc.defaultTransport == "" {
|
||||||
|
@ -174,6 +165,36 @@ func (svc *imageService) PullImage(systemContext *types.SystemContext, imageName
|
||||||
}
|
}
|
||||||
srcRef = srcRef2
|
srcRef = srcRef2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if options.SourceCtx == nil {
|
||||||
|
options.SourceCtx = &types.SystemContext{}
|
||||||
|
}
|
||||||
|
|
||||||
|
hostname := reference.Domain(srcRef.DockerReference())
|
||||||
|
if secure := svc.isSecureIndex(hostname); !secure {
|
||||||
|
options.SourceCtx.DockerInsecureSkipTLSVerify = !secure
|
||||||
|
}
|
||||||
|
return srcRef, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (svc *imageService) PullImage(systemContext *types.SystemContext, imageName string, options *copy.Options) (types.ImageReference, error) {
|
||||||
|
policy, err := signature.DefaultPolicy(systemContext)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
policyContext, err := signature.NewPolicyContext(policy)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if options == nil {
|
||||||
|
options = ©.Options{}
|
||||||
|
}
|
||||||
|
|
||||||
|
srcRef, err := svc.prepareImage(imageName, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
dest := imageName
|
dest := imageName
|
||||||
if srcRef.DockerReference() != nil {
|
if srcRef.DockerReference() != nil {
|
||||||
dest = srcRef.DockerReference().Name()
|
dest = srcRef.DockerReference().Name()
|
||||||
|
@ -215,11 +236,47 @@ func (svc *imageService) GetStore() storage.Store {
|
||||||
return svc.store
|
return svc.store
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (svc *imageService) isSecureIndex(indexName string) bool {
|
||||||
|
if index, ok := svc.indexConfigs[indexName]; ok {
|
||||||
|
return index.secure
|
||||||
|
}
|
||||||
|
|
||||||
|
host, _, err := net.SplitHostPort(indexName)
|
||||||
|
if err != nil {
|
||||||
|
// assume indexName is of the form `host` without the port and go on.
|
||||||
|
host = indexName
|
||||||
|
}
|
||||||
|
|
||||||
|
addrs, err := net.LookupIP(host)
|
||||||
|
if err != nil {
|
||||||
|
ip := net.ParseIP(host)
|
||||||
|
if ip != nil {
|
||||||
|
addrs = []net.IP{ip}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if ip == nil, then `host` is neither an IP nor it could be looked up,
|
||||||
|
// either because the index is unreachable, or because the index is behind an HTTP proxy.
|
||||||
|
// So, len(addrs) == 0 and we're not aborting.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try CIDR notation only if addrs has any elements, i.e. if `host`'s IP could be determined.
|
||||||
|
for _, addr := range addrs {
|
||||||
|
for _, ipnet := range svc.insecureRegistryCIDRs {
|
||||||
|
// check if the addr falls in the subnet
|
||||||
|
if (*net.IPNet)(ipnet).Contains(addr) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// GetImageService returns an ImageServer that uses the passed-in store, and
|
// GetImageService returns an ImageServer that uses the passed-in store, and
|
||||||
// which will prepend the passed-in defaultTransport value to an image name if
|
// which will prepend the passed-in defaultTransport value to an image name if
|
||||||
// a name that's passed to its PullImage() method can't be resolved to an image
|
// a name that's passed to its PullImage() method can't be resolved to an image
|
||||||
// in the store and can't be resolved to a source on its own.
|
// in the store and can't be resolved to a source on its own.
|
||||||
func GetImageService(store storage.Store, defaultTransport string) (ImageServer, error) {
|
func GetImageService(store storage.Store, defaultTransport string, insecureRegistries []string) (ImageServer, error) {
|
||||||
if store == nil {
|
if store == nil {
|
||||||
var err error
|
var err error
|
||||||
store, err = storage.GetStore(storage.DefaultStoreOptions)
|
store, err = storage.GetStore(storage.DefaultStoreOptions)
|
||||||
|
@ -227,8 +284,30 @@ func GetImageService(store storage.Store, defaultTransport string) (ImageServer,
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &imageService{
|
|
||||||
|
is := &imageService{
|
||||||
store: store,
|
store: store,
|
||||||
defaultTransport: defaultTransport,
|
defaultTransport: defaultTransport,
|
||||||
}, nil
|
indexConfigs: make(map[string]*indexInfo, 0),
|
||||||
|
insecureRegistryCIDRs: make([]*net.IPNet, 0),
|
||||||
|
}
|
||||||
|
|
||||||
|
insecureRegistries = append(insecureRegistries, "127.0.0.0/8")
|
||||||
|
// Split --insecure-registry into CIDR and registry-specific settings.
|
||||||
|
for _, r := range insecureRegistries {
|
||||||
|
// Check if CIDR was passed to --insecure-registry
|
||||||
|
_, ipnet, err := net.ParseCIDR(r)
|
||||||
|
if err == nil {
|
||||||
|
// Valid CIDR.
|
||||||
|
is.insecureRegistryCIDRs = append(is.insecureRegistryCIDRs, ipnet)
|
||||||
|
} else {
|
||||||
|
// Assume `host:port` if not CIDR.
|
||||||
|
is.indexConfigs[r] = &indexInfo{
|
||||||
|
name: r,
|
||||||
|
secure: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return is, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,6 +117,9 @@ type ImageConfig struct {
|
||||||
// that this be left unspecified so that the default system-wide policy
|
// that this be left unspecified so that the default system-wide policy
|
||||||
// will be used.
|
// will be used.
|
||||||
SignaturePolicyPath string `toml:"signature_policy"`
|
SignaturePolicyPath string `toml:"signature_policy"`
|
||||||
|
// InsecureRegistries is a list of registries that must be contacted w/o
|
||||||
|
// TLS verification.
|
||||||
|
InsecureRegistries []string `toml:"insecure_registries"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetworkConfig represents the "crio.network" TOML config table
|
// NetworkConfig represents the "crio.network" TOML config table
|
||||||
|
|
|
@ -38,8 +38,6 @@ func (s *Server) PullImage(ctx context.Context, req *pb.PullImageRequest) (*pb.P
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
options := ©.Options{
|
options := ©.Options{
|
||||||
// TODO: we need a way to specify insecure registries like docker
|
|
||||||
//DockerInsecureSkipTLSVerify: true,
|
|
||||||
SourceCtx: &types.SystemContext{},
|
SourceCtx: &types.SystemContext{},
|
||||||
}
|
}
|
||||||
// a not empty username should be sufficient to decide whether to send auth
|
// a not empty username should be sufficient to decide whether to send auth
|
||||||
|
@ -53,7 +51,7 @@ func (s *Server) PullImage(ctx context.Context, req *pb.PullImageRequest) (*pb.P
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
canPull, err := s.storageImageServer.CanPull(image, options.SourceCtx)
|
canPull, err := s.storageImageServer.CanPull(image, options)
|
||||||
if err != nil && !canPull {
|
if err != nil && !canPull {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -545,7 +545,7 @@ func New(config *Config) (*Server, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
imageService, err := storage.GetImageService(store, config.DefaultTransport)
|
imageService, err := storage.GetImageService(store, config.DefaultTransport, config.InsecureRegistries)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue