Add TLS auth registry support
Signed-off-by: Vlad Ungureanu <ungureanuvladvictor@gmail.com>
This commit is contained in:
parent
0ab79ff849
commit
60a58af376
@ -22,6 +22,22 @@ from a registry, containerd will try these endpoint URLs one by one, and use the
|
|||||||
|
|
||||||
After modify this config, you need restart the `containerd` service.
|
After modify this config, you need restart the `containerd` service.
|
||||||
|
|
||||||
|
## Configure Registry TLS Communication
|
||||||
|
`cri` plugin also supports configuring TLS settings when communicating with a registry.
|
||||||
|
|
||||||
|
To configure the TLS settings for a specific registry, create/modify the `/ec/containerd/config.toml` as follows:
|
||||||
|
```toml
|
||||||
|
[plugins.cri.registry.tls_configs]
|
||||||
|
[plugins.cri.registry.tls_configs."my.custom.registry"]
|
||||||
|
ca_file = "ca.pem"
|
||||||
|
cert_file = "cert.pem"
|
||||||
|
key_file = "key.pem"
|
||||||
|
```
|
||||||
|
|
||||||
|
In the config example shown above, TLS mutual authentication will be used for communications with the registry endpoint located at https://my.custom.registry.
|
||||||
|
`ca_file` is file name of the certificate authority (CA) certificate used to authenticate the x509 certificate/key pair specified by the files respectively pointed to by `cert_file` and `key_file`.
|
||||||
|
|
||||||
|
|
||||||
## Configure Registry Credentials
|
## Configure Registry Credentials
|
||||||
|
|
||||||
`cri` plugin also supports docker like registry credential config.
|
`cri` plugin also supports docker like registry credential config.
|
||||||
|
@ -106,6 +106,13 @@ type AuthConfig struct {
|
|||||||
IdentityToken string `toml:"identitytoken" json:"identitytoken"`
|
IdentityToken string `toml:"identitytoken" json:"identitytoken"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TLSConfig contains the CA/Cert/Key used for a registry
|
||||||
|
type TLSConfig struct {
|
||||||
|
CAFile string `toml:"ca_file" json:"caFile"`
|
||||||
|
CertFile string `toml:"cert_file" json:"certFile"`
|
||||||
|
KeyFile string `toml:"key_file" json:"keyFile"`
|
||||||
|
}
|
||||||
|
|
||||||
// Registry is registry settings configured
|
// Registry is registry settings configured
|
||||||
type Registry struct {
|
type Registry struct {
|
||||||
// Mirrors are namespace to mirror mapping for all namespaces.
|
// Mirrors are namespace to mirror mapping for all namespaces.
|
||||||
@ -113,6 +120,9 @@ type Registry struct {
|
|||||||
// Auths are registry endpoint to auth config mapping. The registry endpoint must
|
// Auths are registry endpoint to auth config mapping. The registry endpoint must
|
||||||
// be a valid url with host specified.
|
// be a valid url with host specified.
|
||||||
Auths map[string]AuthConfig `toml:"auths" json:"auths"`
|
Auths map[string]AuthConfig `toml:"auths" json:"auths"`
|
||||||
|
// TLSConfigs are pairs of CA/Cert/Key which then are used when creating the transport
|
||||||
|
// that communicates with the registry.
|
||||||
|
TLSConfigs map[string]TLSConfig `toml:"tls_configs" json:"tlsConfigs"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// PluginConfig contains toml config related to CRI plugin,
|
// PluginConfig contains toml config related to CRI plugin,
|
||||||
|
@ -17,7 +17,10 @@ limitations under the License.
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
@ -28,6 +31,7 @@ import (
|
|||||||
"github.com/containerd/containerd/reference"
|
"github.com/containerd/containerd/reference"
|
||||||
"github.com/containerd/containerd/remotes"
|
"github.com/containerd/containerd/remotes"
|
||||||
"github.com/containerd/containerd/remotes/docker"
|
"github.com/containerd/containerd/remotes/docker"
|
||||||
|
"github.com/containerd/cri/pkg/config"
|
||||||
distribution "github.com/docker/distribution/reference"
|
distribution "github.com/docker/distribution/reference"
|
||||||
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
|
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -246,6 +250,33 @@ func (c *criService) credentials(auth *runtime.AuthConfig) func(string) (string,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getRegistryTLSTransport returns a http.Transport configured with a CA/Cert/Key specified by registryTLSConfig
|
||||||
|
func (c *criService) getRegistryTLSTransport(ctx context.Context, registryTLSConfig config.TLSConfig) (*http.Transport, error) {
|
||||||
|
cert, err := tls.LoadX509KeyPair(registryTLSConfig.CertFile, registryTLSConfig.KeyFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to load cert file")
|
||||||
|
}
|
||||||
|
|
||||||
|
caCertPool, err := x509.SystemCertPool()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to get system cert pool")
|
||||||
|
}
|
||||||
|
caCert, err := ioutil.ReadFile(registryTLSConfig.CAFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to load CA file")
|
||||||
|
}
|
||||||
|
caCertPool.AppendCertsFromPEM(caCert)
|
||||||
|
|
||||||
|
tlsConfig := &tls.Config{
|
||||||
|
Certificates: []tls.Certificate{cert},
|
||||||
|
RootCAs: caCertPool,
|
||||||
|
}
|
||||||
|
tlsConfig.BuildNameToCertificate()
|
||||||
|
transport := &http.Transport{TLSClientConfig: tlsConfig}
|
||||||
|
|
||||||
|
return transport, nil
|
||||||
|
}
|
||||||
|
|
||||||
// getResolver tries registry mirrors and the default registry, and returns the resolver and descriptor
|
// getResolver tries registry mirrors and the default registry, and returns the resolver and descriptor
|
||||||
// from the first working registry.
|
// from the first working registry.
|
||||||
func (c *criService) getResolver(ctx context.Context, ref string, cred func(string) (string, string, error)) (remotes.Resolver, imagespec.Descriptor, error) {
|
func (c *criService) getResolver(ctx context.Context, ref string, cred func(string) (string, string, error)) (remotes.Resolver, imagespec.Descriptor, error) {
|
||||||
@ -253,15 +284,27 @@ func (c *criService) getResolver(ctx context.Context, ref string, cred func(stri
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, imagespec.Descriptor{}, errors.Wrap(err, "parse image reference")
|
return nil, imagespec.Descriptor{}, errors.Wrap(err, "parse image reference")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
httpClient := http.DefaultClient
|
||||||
|
|
||||||
// Try mirrors in order first, and then try default host name.
|
// Try mirrors in order first, and then try default host name.
|
||||||
for _, e := range c.config.Registry.Mirrors[refspec.Hostname()].Endpoints {
|
for _, e := range c.config.Registry.Mirrors[refspec.Hostname()].Endpoints {
|
||||||
u, err := url.Parse(e)
|
u, err := url.Parse(e)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, imagespec.Descriptor{}, errors.Wrapf(err, "parse registry endpoint %q", e)
|
return nil, imagespec.Descriptor{}, errors.Wrapf(err, "parse registry endpoint %q", e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if registryTLSConfig, ok := c.config.Registry.TLSConfigs[u.Host]; ok {
|
||||||
|
tlsTransport, err := c.getRegistryTLSTransport(ctx, registryTLSConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, imagespec.Descriptor{}, errors.Wrapf(err, "get tlsTransport for registry %q", refspec.Hostname())
|
||||||
|
}
|
||||||
|
httpClient = &http.Client{Transport: tlsTransport}
|
||||||
|
}
|
||||||
|
|
||||||
resolver := docker.NewResolver(docker.ResolverOptions{
|
resolver := docker.NewResolver(docker.ResolverOptions{
|
||||||
Authorizer: docker.NewAuthorizer(http.DefaultClient, cred),
|
Authorizer: docker.NewAuthorizer(http.DefaultClient, cred),
|
||||||
Client: http.DefaultClient,
|
Client: httpClient,
|
||||||
Host: func(string) (string, error) { return u.Host, nil },
|
Host: func(string) (string, error) { return u.Host, nil },
|
||||||
// By default use "https".
|
// By default use "https".
|
||||||
PlainHTTP: u.Scheme == "http",
|
PlainHTTP: u.Scheme == "http",
|
||||||
@ -273,9 +316,22 @@ func (c *criService) getResolver(ctx context.Context, ref string, cred func(stri
|
|||||||
logrus.WithError(err).Debugf("Tried registry mirror %q but failed", e)
|
logrus.WithError(err).Debugf("Tried registry mirror %q but failed", e)
|
||||||
// Continue to try next endpoint
|
// Continue to try next endpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hostname, err := docker.DefaultHost(refspec.Hostname())
|
||||||
|
if err != nil {
|
||||||
|
return nil, imagespec.Descriptor{}, errors.Wrapf(err, "get host for refspec %q", refspec.Hostname())
|
||||||
|
}
|
||||||
|
if registryTLSConfig, ok := c.config.Registry.TLSConfigs[hostname]; ok {
|
||||||
|
tlsTransport, err := c.getRegistryTLSTransport(ctx, registryTLSConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, imagespec.Descriptor{}, errors.Wrapf(err, "get tlsTransport for registry %q", refspec.Hostname())
|
||||||
|
}
|
||||||
|
httpClient = &http.Client{Transport: tlsTransport}
|
||||||
|
}
|
||||||
|
|
||||||
resolver := docker.NewResolver(docker.ResolverOptions{
|
resolver := docker.NewResolver(docker.ResolverOptions{
|
||||||
Credentials: cred,
|
Credentials: cred,
|
||||||
Client: http.DefaultClient,
|
Client: httpClient,
|
||||||
})
|
})
|
||||||
_, desc, err := resolver.Resolve(ctx, ref)
|
_, desc, err := resolver.Resolve(ctx, ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user