From 9a7ca39cbd7c6b7598c067835693375a4ccb4a5b Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Mon, 8 Mar 2021 17:37:58 +0900 Subject: [PATCH 1/3] defaults: add DefaultConfigDir Signed-off-by: Akihiro Suda --- cmd/containerd/command/main.go | 3 ++- cmd/containerd/command/main_unix.go | 2 -- cmd/containerd/command/main_windows.go | 4 +--- defaults/defaults_unix.go | 2 ++ defaults/defaults_windows.go | 3 +++ 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/cmd/containerd/command/main.go b/cmd/containerd/command/main.go index 297f89403..eb12bb4ba 100644 --- a/cmd/containerd/command/main.go +++ b/cmd/containerd/command/main.go @@ -27,6 +27,7 @@ import ( "runtime" "time" + "github.com/containerd/containerd/defaults" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/log" "github.com/containerd/containerd/mount" @@ -80,7 +81,7 @@ can be used and modified as necessary as a custom configuration.` cli.StringFlag{ Name: "config,c", Usage: "path to the configuration file", - Value: defaultConfigPath, + Value: filepath.Join(defaults.DefaultConfigDir, "config.toml"), }, cli.StringFlag{ Name: "log-level,l", diff --git a/cmd/containerd/command/main_unix.go b/cmd/containerd/command/main_unix.go index bdfddc70d..b8970c6d2 100644 --- a/cmd/containerd/command/main_unix.go +++ b/cmd/containerd/command/main_unix.go @@ -27,8 +27,6 @@ import ( "golang.org/x/sys/unix" ) -const defaultConfigPath = "/etc/containerd/config.toml" - var handledSignals = []os.Signal{ unix.SIGTERM, unix.SIGINT, diff --git a/cmd/containerd/command/main_windows.go b/cmd/containerd/command/main_windows.go index 7e3430bb6..774a49618 100644 --- a/cmd/containerd/command/main_windows.go +++ b/cmd/containerd/command/main_windows.go @@ -20,7 +20,6 @@ import ( "context" "fmt" "os" - "path/filepath" "unsafe" "github.com/Microsoft/go-winio/pkg/etw" @@ -33,8 +32,7 @@ import ( ) var ( - defaultConfigPath = filepath.Join(os.Getenv("programfiles"), "containerd", "config.toml") - handledSignals = []os.Signal{ + handledSignals = []os.Signal{ windows.SIGTERM, windows.SIGINT, } diff --git a/defaults/defaults_unix.go b/defaults/defaults_unix.go index 319e8777b..6b69cd06b 100644 --- a/defaults/defaults_unix.go +++ b/defaults/defaults_unix.go @@ -34,4 +34,6 @@ const ( DefaultFIFODir = "/run/containerd/fifo" // DefaultRuntime is the default linux runtime DefaultRuntime = "io.containerd.runc.v2" + // DefaultConfigDir is the default location for config files. + DefaultConfigDir = "/etc/containerd" ) diff --git a/defaults/defaults_windows.go b/defaults/defaults_windows.go index 5eede8de8..a80700075 100644 --- a/defaults/defaults_windows.go +++ b/defaults/defaults_windows.go @@ -30,6 +30,9 @@ var ( // DefaultStateDir is the default location used by containerd to store // transient data DefaultStateDir = filepath.Join(os.Getenv("ProgramData"), "containerd", "state") + + // DefaultConfigDir is the default location for config files. + DefaultConfigDir = filepath.Join(os.Getenv("programfiles"), "containerd") ) const ( From ac2726e12c1432b5bbb378b1a4738aa70acbfb9f Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Mon, 8 Mar 2021 17:44:56 +0900 Subject: [PATCH 2/3] cmd/containerd: deduplicate config*.go `config_linux.go` and `config_windows.go` are identical. `config_unsupported.go` is also almost identical but enables debug logs by default. Signed-off-by: Akihiro Suda --- cmd/containerd/command/config.go | 16 ++++++++++++++++ cmd/containerd/command/config_linux.go | 14 +------------- cmd/containerd/command/config_unsupported.go | 18 +++++------------- cmd/containerd/command/config_windows.go | 14 +------------- 4 files changed, 23 insertions(+), 39 deletions(-) diff --git a/cmd/containerd/command/config.go b/cmd/containerd/command/config.go index f1d590d9f..92b455fc7 100644 --- a/cmd/containerd/command/config.go +++ b/cmd/containerd/command/config.go @@ -22,6 +22,7 @@ import ( "os" "github.com/BurntSushi/toml" + "github.com/containerd/containerd/defaults" "github.com/containerd/containerd/pkg/timeout" "github.com/containerd/containerd/services/server" srvconfig "github.com/containerd/containerd/services/server/config" @@ -113,3 +114,18 @@ var configCommand = cli.Command{ }, }, } + +func platformAgnosticDefaultConfig() *srvconfig.Config { + return &srvconfig.Config{ + Version: 1, + Root: defaults.DefaultRootDir, + State: defaults.DefaultStateDir, + GRPC: srvconfig.GRPCConfig{ + Address: defaults.DefaultAddress, + MaxRecvMsgSize: defaults.DefaultMaxRecvMsgSize, + MaxSendMsgSize: defaults.DefaultMaxSendMsgSize, + }, + DisabledPlugins: []string{}, + RequiredPlugins: []string{}, + } +} diff --git a/cmd/containerd/command/config_linux.go b/cmd/containerd/command/config_linux.go index 9ed7368d7..df8e856cf 100644 --- a/cmd/containerd/command/config_linux.go +++ b/cmd/containerd/command/config_linux.go @@ -17,21 +17,9 @@ package command import ( - "github.com/containerd/containerd/defaults" srvconfig "github.com/containerd/containerd/services/server/config" ) func defaultConfig() *srvconfig.Config { - return &srvconfig.Config{ - Version: 1, - Root: defaults.DefaultRootDir, - State: defaults.DefaultStateDir, - GRPC: srvconfig.GRPCConfig{ - Address: defaults.DefaultAddress, - MaxRecvMsgSize: defaults.DefaultMaxRecvMsgSize, - MaxSendMsgSize: defaults.DefaultMaxSendMsgSize, - }, - DisabledPlugins: []string{}, - RequiredPlugins: []string{}, - } + return platformAgnosticDefaultConfig() } diff --git a/cmd/containerd/command/config_unsupported.go b/cmd/containerd/command/config_unsupported.go index 695a7b466..8dc92bc61 100644 --- a/cmd/containerd/command/config_unsupported.go +++ b/cmd/containerd/command/config_unsupported.go @@ -24,18 +24,10 @@ import ( ) func defaultConfig() *srvconfig.Config { - return &srvconfig.Config{ - Version: 1, - Root: defaults.DefaultRootDir, - State: defaults.DefaultStateDir, - GRPC: srvconfig.GRPCConfig{ - Address: defaults.DefaultAddress, - }, - Debug: srvconfig.Debug{ - Level: "info", - Address: defaults.DefaultDebugAddress, - }, - DisabledPlugins: []string{}, - RequiredPlugins: []string{}, + cfg := platformAgnosticDefaultConfig() + cfg.Debug = srvconfig.Debug{ + Level: "info", + Address: defaults.DefaultDebugAddress, } + return cfg } diff --git a/cmd/containerd/command/config_windows.go b/cmd/containerd/command/config_windows.go index 9ed7368d7..df8e856cf 100644 --- a/cmd/containerd/command/config_windows.go +++ b/cmd/containerd/command/config_windows.go @@ -17,21 +17,9 @@ package command import ( - "github.com/containerd/containerd/defaults" srvconfig "github.com/containerd/containerd/services/server/config" ) func defaultConfig() *srvconfig.Config { - return &srvconfig.Config{ - Version: 1, - Root: defaults.DefaultRootDir, - State: defaults.DefaultStateDir, - GRPC: srvconfig.GRPCConfig{ - Address: defaults.DefaultAddress, - MaxRecvMsgSize: defaults.DefaultMaxRecvMsgSize, - MaxSendMsgSize: defaults.DefaultMaxSendMsgSize, - }, - DisabledPlugins: []string{}, - RequiredPlugins: []string{}, - } + return platformAgnosticDefaultConfig() } From ecb881e5e6e3ea77721865c5bb1d61725579fd54 Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Mon, 8 Mar 2021 18:06:04 +0900 Subject: [PATCH 3/3] add imgcrypt stream processors to the default config Enable the following config by default: ```toml version = 2 [plugins."io.containerd.grpc.v1.cri".image_decryption] key_model = "node" [stream_processors] [stream_processors."io.containerd.ocicrypt.decoder.v1.tar.gzip"] accepts = ["application/vnd.oci.image.layer.v1.tar+gzip+encrypted"] returns = "application/vnd.oci.image.layer.v1.tar+gzip" path = "ctd-decoder" args = ["--decryption-keys-path", "/etc/containerd/ocicrypt/keys"] env = ["OCICRYPT_KEYPROVIDER_CONFIG=/etc/containerd/ocicrypt/ocicrypt_keyprovider.conf"] [stream_processors."io.containerd.ocicrypt.decoder.v1.tar"] accepts = ["application/vnd.oci.image.layer.v1.tar+encrypted"] returns = "application/vnd.oci.image.layer.v1.tar" path = "ctd-decoder" args = ["--decryption-keys-path", "/etc/containerd/ocicrypt/keys"] env = ["OCICRYPT_KEYPROVIDER_CONFIG=/etc/containerd/ocicrypt/ocicrypt_keyprovider.conf"] ``` Fix issue 5128 Signed-off-by: Akihiro Suda --- cmd/containerd/command/config.go | 38 ++++++++++++++++++++++++++++++-- docs/cri/decryption.md | 27 +++++++++++------------ images/mediatypes.go | 3 +++ pkg/cri/config/config_unix.go | 3 +++ pkg/cri/config/config_windows.go | 4 ++++ 5 files changed, 59 insertions(+), 16 deletions(-) diff --git a/cmd/containerd/command/config.go b/cmd/containerd/command/config.go index 92b455fc7..f843b8041 100644 --- a/cmd/containerd/command/config.go +++ b/cmd/containerd/command/config.go @@ -20,12 +20,15 @@ import ( gocontext "context" "io" "os" + "path/filepath" "github.com/BurntSushi/toml" "github.com/containerd/containerd/defaults" + "github.com/containerd/containerd/images" "github.com/containerd/containerd/pkg/timeout" "github.com/containerd/containerd/services/server" srvconfig "github.com/containerd/containerd/services/server/config" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/urfave/cli" ) @@ -125,7 +128,38 @@ func platformAgnosticDefaultConfig() *srvconfig.Config { MaxRecvMsgSize: defaults.DefaultMaxRecvMsgSize, MaxSendMsgSize: defaults.DefaultMaxSendMsgSize, }, - DisabledPlugins: []string{}, - RequiredPlugins: []string{}, + DisabledPlugins: []string{}, + RequiredPlugins: []string{}, + StreamProcessors: streamProcessors(), + } +} + +func streamProcessors() map[string]srvconfig.StreamProcessor { + const ( + ctdDecoder = "ctd-decoder" + basename = "io.containerd.ocicrypt.decoder.v1" + ) + decryptionKeysPath := filepath.Join(defaults.DefaultConfigDir, "ocicrypt", "keys") + ctdDecoderArgs := []string{ + "--decryption-keys-path", decryptionKeysPath, + } + ctdDecoderEnv := []string{ + "OCICRYPT_KEYPROVIDER_CONFIG=" + filepath.Join(defaults.DefaultConfigDir, "ocicrypt", "ocicrypt_keyprovider.conf"), + } + return map[string]srvconfig.StreamProcessor{ + basename + ".tar.gzip": { + Accepts: []string{images.MediaTypeImageLayerGzipEncrypted}, + Returns: ocispec.MediaTypeImageLayerGzip, + Path: ctdDecoder, + Args: ctdDecoderArgs, + Env: ctdDecoderEnv, + }, + basename + ".tar": { + Accepts: []string{images.MediaTypeImageLayerEncrypted}, + Returns: ocispec.MediaTypeImageLayer, + Path: ctdDecoder, + Args: ctdDecoderArgs, + Env: ctdDecoderEnv, + }, } } diff --git a/docs/cri/decryption.md b/docs/cri/decryption.md index abde945b8..32e2cd235 100644 --- a/docs/cri/decryption.md +++ b/docs/cri/decryption.md @@ -15,32 +15,31 @@ In this model encryption is tied to worker nodes. The usecase here revolves arou ### Configuring image decryption for "node" key model -The default configuration does not handle decrypting encrypted container images. +This is the default model since containerd v1.5. -An example for configuring the "node" key model for container image decryption: - -Configure `cri` to enable decryption with "node" key model +For containerd v1.4, you need to add the following configuration to `/etc/containerd/config.toml` and restart the `containerd` service manually. ```toml +version = 2 + [plugins."io.containerd.grpc.v1.cri".image_decryption] key_model = "node" -``` -Configure `containerd` daemon [`stream_processors`](https://github.com/containerd/containerd/blob/master/docs/stream_processors.md) to handle the -encrypted mediatypes. -```toml [stream_processors] [stream_processors."io.containerd.ocicrypt.decoder.v1.tar.gzip"] accepts = ["application/vnd.oci.image.layer.v1.tar+gzip+encrypted"] returns = "application/vnd.oci.image.layer.v1.tar+gzip" - path = "/usr/local/bin/ctd-decoder" - args = ["--decryption-keys-path", "/keys"] + path = "ctd-decoder" + args = ["--decryption-keys-path", "/etc/containerd/ocicrypt/keys"] + env= ["OCICRYPT_KEYPROVIDER_CONFIG=/etc/containerd/ocicrypt/ocicrypt_keyprovider.conf"] [stream_processors."io.containerd.ocicrypt.decoder.v1.tar"] accepts = ["application/vnd.oci.image.layer.v1.tar+encrypted"] returns = "application/vnd.oci.image.layer.v1.tar" - path = "/usr/local/bin/ctd-decoder" - args = ["--decryption-keys-path", "/keys"] + path = "ctd-decoder" + args = ["--decryption-keys-path", "/etc/containerd/ocicrypt/keys"] + env= ["OCICRYPT_KEYPROVIDER_CONFIG=/etc/containerd/ocicrypt/ocicrypt_keyprovider.conf"] ``` -In this example, container image decryption is set to use the "node" key model. In addition, the decryption [`stream_processors`](https://github.com/containerd/containerd/blob/master/docs/stream_processors.md) are configured as specified in [containerd/imgcrypt project](https://github.com/containerd/imgcrypt), with the additional field `--decryption-keys-path` configured to specify where decryption keys are located locally in the node. +In this example, container image decryption is set to use the "node" key model. +In addition, the decryption [`stream_processors`](https://github.com/containerd/containerd/blob/master/docs/stream_processors.md) are configured as specified in [containerd/imgcrypt project](https://github.com/containerd/imgcrypt), with the additional field `--decryption-keys-path` configured to specify where decryption keys are located locally in the node. -After modify this config, you need restart the `containerd` service. +The `$OCICRYPT_KEYPROVIDER_CONFIG` environment variable is used for [ocicrypt keyprovider protocol](https://github.com/containers/ocicrypt/blob/master/docs/keyprovider.md). diff --git a/images/mediatypes.go b/images/mediatypes.go index 996cec59a..785d71291 100644 --- a/images/mediatypes.go +++ b/images/mediatypes.go @@ -49,6 +49,9 @@ const ( MediaTypeContainerd1CheckpointRuntimeOptions = "application/vnd.containerd.container.checkpoint.runtime.options+proto" // Legacy Docker schema1 manifest MediaTypeDockerSchema1Manifest = "application/vnd.docker.distribution.manifest.v1+prettyjws" + // Encypted media types + MediaTypeImageLayerEncrypted = ocispec.MediaTypeImageLayer + "+encrypted" + MediaTypeImageLayerGzipEncrypted = ocispec.MediaTypeImageLayerGzip + "+encrypted" ) // DiffCompression returns the compression as defined by the layer diff media diff --git a/pkg/cri/config/config_unix.go b/pkg/cri/config/config_unix.go index f91208538..66ee417a4 100644 --- a/pkg/cri/config/config_unix.go +++ b/pkg/cri/config/config_unix.go @@ -72,5 +72,8 @@ func DefaultConfig() PluginConfig { TolerateMissingHugetlbController: true, DisableHugetlbController: true, IgnoreImageDefinedVolumes: false, + ImageDecryption: ImageDecryption{ + KeyModel: KeyModelNode, + }, } } diff --git a/pkg/cri/config/config_windows.go b/pkg/cri/config/config_windows.go index 2a1c45753..9d33eb7f8 100644 --- a/pkg/cri/config/config_windows.go +++ b/pkg/cri/config/config_windows.go @@ -67,5 +67,9 @@ func DefaultConfig() PluginConfig { MaxConcurrentDownloads: 3, IgnoreImageDefinedVolumes: false, // TODO(windows): Add platform specific config, so that most common defaults can be shared. + + ImageDecryption: ImageDecryption{ + KeyModel: KeyModelNode, + }, } }