From 95c708572f2d65b85ebbb3648f34fd531c7b6f36 Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Thu, 1 Jul 2021 17:24:08 -0700 Subject: [PATCH 1/2] Update documenation for OCI distribution 1.0 Signed-off-by: Derek McGowan --- README.md | 8 ++++++++ docs/hosts.md | 14 ++++++++++++-- remotes/docker/config/hosts.go | 21 ++++++++++++++------- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 298436198..87e7c7c0d 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,14 @@ your system. See more details in [Checkpoint and Restore](#checkpoint-and-restor Build requirements for developers are listed in [BUILDING](BUILDING.md). + +## Supported Registries + +Any registry which is compliant with the [OCI Distribution Specification](https://github.com/opencontainers/distribution-spec) +is supported by containerd. + +For configuring registries, see [registry host configuration documentation](docs/hosts.md) + ## Features ### Client diff --git a/docs/hosts.md b/docs/hosts.md index 7f2217183..235a97749 100644 --- a/docs/hosts.md +++ b/docs/hosts.md @@ -5,6 +5,14 @@ Configuring registries will be done by specifying (optionally) a `hosts.toml` fi each desired registry host in a configuration directory. **Note**: Updates under this directory do not require restarting the containerd daemon. +## Registry API Support + +All configured registry hosts are expected to comply with the [OCI Distribution Specification](https://github.com/opencontainers/distribution-spec). +Registries which are non-compliant or implement non-standard behavior are not guaranteed +to be supported and may break unexpectedly between releases. + +Currently supported OCI Distribution version: **[v1.0.0](https://github.com/opencontainers/distribution-spec/tree/v1.0.0)** + ## Specifying the Configuration Directory ### Using Host Namespace Configs with CTR @@ -235,8 +243,10 @@ client = [["/etc/certs/client.cert", "/etc/certs/client.key"],["/etc/certs/clien ## skip_verify field -`skip_verify` set this flag to `true` to skip the registry certificate -verification for this registry host namespace. (Defaults to `false`) +`skip_verify` skips verifications of the registry's certificate chain and +host name when set to `true`. This should only be used for testing or in +combination with other method of verifying connections. (Defaults to `false`) + ``` skip_verify = false ``` diff --git a/remotes/docker/config/hosts.go b/remotes/docker/config/hosts.go index b24ba33f5..c31437af7 100644 --- a/remotes/docker/config/hosts.go +++ b/remotes/docker/config/hosts.go @@ -54,8 +54,6 @@ type hostConfig struct { header http.Header - // TODO: API ("docker" or "oci") - // TODO: API Version ("v1", "v2") // TODO: Add credential configuration (domain alias, username) } @@ -283,19 +281,28 @@ type hostFileConfig struct { // - push Capabilities []string `toml:"capabilities"` - // CACert can be a string or an array of strings + // CACert are the public key certificates for TLS + // Accepted types + // - string - Single file with certificate(s) + // - []string - Multiple files with certificates CACert interface{} `toml:"ca"` - // TODO: Make this an array (two key types, one for pairs (multiple files), one for single file?) + // Client keypair(s) for TLS with client authentication + // Accepted types + // - string - Single file with public and private keys + // - []string - Multiple files with public and private keys + // - [][2]string - Muliple keypairs with public and private keys in separate files Client interface{} `toml:"client"` + // SkipVerify skips verification of the server's certificate chain + // and host name. This should only be used for testing or in + // combination with other methods of verifying connections. SkipVerify *bool `toml:"skip_verify"` + // Header are additional header files to send to the server Header map[string]interface{} `toml:"header"` - // API (default: "docker") - // API Version (default: "v2") - // Credentials: helper? name? username? alternate domain? token? + // TODO: Credentials: helper? name? username? alternate domain? token? } func parseHostsFile(baseDir string, b []byte) ([]hostConfig, error) { From a7ad6b3be5bfad7ab77b2801e52663a2eb43e270 Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Thu, 1 Jul 2021 17:49:32 -0700 Subject: [PATCH 2/2] Add support for registry host path override Adds support for mirrors which are non-compliant with the OCI distribution specification but have previously mirrored content with a namespace prefix after the API root `/v2`. Signed-off-by: Derek McGowan --- docs/hosts.md | 15 +++++++++++++++ remotes/docker/config/hosts.go | 16 +++++++++------- remotes/docker/config/hosts_test.go | 18 ++++++++++++++++++ 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/docs/hosts.md b/docs/hosts.md index 235a97749..d713af9ca 100644 --- a/docs/hosts.md +++ b/docs/hosts.md @@ -274,6 +274,17 @@ or x-custom-1-2 = "another custom header" ``` +## override_path field + +`override_path` is used to indicate the host's API root endpoint is defined +in the URL path rather than by the API specification. This may be used with +non-compliant OCI registries which are missing the `/v2` prefix. +(Defaults to `false`) + +``` +override_path = true +``` + ## host field(s) (in the toml table format) `[host]."https://namespace"` and `[host].http://namespace` entries in the @@ -310,6 +321,10 @@ for this registry host namespace: [host."https://test-3.registry"] client = ["/etc/certs/client-1.pem", "/etc/certs/client-2.pem"] + +[host."https://non-compliant-mirror.registry/v2/upstream"] + capabilities = ["pull"] + override_path = true ``` **Note**: Recursion is not supported in the specification of host mirror diff --git a/remotes/docker/config/hosts.go b/remotes/docker/config/hosts.go index c31437af7..40330f17e 100644 --- a/remotes/docker/config/hosts.go +++ b/remotes/docker/config/hosts.go @@ -291,7 +291,7 @@ type hostFileConfig struct { // Accepted types // - string - Single file with public and private keys // - []string - Multiple files with public and private keys - // - [][2]string - Muliple keypairs with public and private keys in separate files + // - [][2]string - Multiple keypairs with public and private keys in separate files Client interface{} `toml:"client"` // SkipVerify skips verification of the server's certificate chain @@ -302,6 +302,12 @@ type hostFileConfig struct { // Header are additional header files to send to the server Header map[string]interface{} `toml:"header"` + // OverridePath indicates the API root endpoint is defined in the URL + // path rather than by the API specification. + // This may be used with non-compliant OCI registries to override the + // API root endpoint. + OverridePath bool `toml:"override_path"` + // TODO: Credentials: helper? name? username? alternate domain? token? } @@ -374,16 +380,12 @@ func parseHostConfig(server string, baseDir string, config hostFileConfig) (host } result.scheme = u.Scheme result.host = u.Host - // TODO: Handle path based on registry protocol - // Define a registry protocol type - // OCI v1 - Always use given path as is - // Docker v2 - Always ensure ends with /v2/ if len(u.Path) > 0 { u.Path = path.Clean(u.Path) - if !strings.HasSuffix(u.Path, "/v2") { + if !strings.HasSuffix(u.Path, "/v2") && !config.OverridePath { u.Path = u.Path + "/v2" } - } else { + } else if !config.OverridePath { u.Path = "/v2" } result.path = u.Path diff --git a/remotes/docker/config/hosts_test.go b/remotes/docker/config/hosts_test.go index 18dc1c659..44586fa5e 100644 --- a/remotes/docker/config/hosts_test.go +++ b/remotes/docker/config/hosts_test.go @@ -104,6 +104,13 @@ ca = "/etc/path/default" [host."https://test-3.registry"] client = ["/etc/certs/client-1.pem", "/etc/certs/client-2.pem"] + +[host."https://noncompliantmirror.registry/v2/namespaceprefix"] + capabilities = ["pull"] + override_path = true + +[host."https://noprefixnoncompliant.registry"] + override_path = true ` var tb, fb = true, false expected := []hostConfig{ @@ -159,6 +166,17 @@ ca = "/etc/path/default" {filepath.FromSlash("/etc/certs/client-2.pem")}, }, }, + { + scheme: "https", + host: "noncompliantmirror.registry", + path: "/v2/namespaceprefix", + capabilities: docker.HostCapabilityPull, + }, + { + scheme: "https", + host: "noprefixnoncompliant.registry", + capabilities: allCaps, + }, { scheme: "https", host: "test-default.registry",