add oci.WithAllDevicesAllowed flag for privileged_without_host_devices

This commit adds a flag that enable all devices whitelisting when
privileged_without_host_devices is already enabled.

Fixes #5679

Signed-off-by: Dat Nguyen <dnguyen7@atlassian.com>
This commit is contained in:
Dat Nguyen 2021-07-05 13:21:12 +10:00
parent 493220b719
commit afe39bebfe
5 changed files with 65 additions and 9 deletions

View File

@ -168,6 +168,14 @@ version = 2
# i.e pass host devices through to privileged containers.
privileged_without_host_devices = false
# privileged_without_host_devices_all_devices_allowed allows the allowlisting of all devices when
# privileged_without_host_devices is enabled.
# In plain privileged mode all host device nodes are added to the container's spec and all devices
# are put in the container's device allowlist. This flags is for the modification of the privileged_without_host_devices
# option so that even when no host devices are implicitly added to the container, all devices allowlisting is still enabled.
# Requires privileged_without_host_devices to be enabled. Defaults to false.
privileged_without_host_devices_all_devices_allowed = false
# base_runtime_spec is a file path to a JSON file with the OCI spec that will be used as the base spec that all
# container's are created from.
# Use containerd's `ctr oci spec > /etc/containerd/cri-base.json` to output initial spec file.

View File

@ -54,6 +54,10 @@ type Runtime struct {
// PrivilegedWithoutHostDevices overloads the default behaviour for adding host devices to the
// runtime spec when the container is privileged. Defaults to false.
PrivilegedWithoutHostDevices bool `toml:"privileged_without_host_devices" json:"privileged_without_host_devices"`
// PrivilegedWithoutHostDevicesAllDevicesAllowed overloads the default behaviour device allowlisting when
// to the runtime spec when the container when PrivilegedWithoutHostDevices is already enabled. Requires
// PrivilegedWithoutHostDevices to be enabled. Defaults to false.
PrivilegedWithoutHostDevicesAllDevicesAllowed bool `toml:"privileged_without_host_devices_all_devices_allowed" json:"privileged_without_host_devices_all_devices_allowed"`
// BaseRuntimeSpec is a json file with OCI spec to use as base spec that all container's will be created from.
BaseRuntimeSpec string `toml:"base_runtime_spec" json:"baseRuntimeSpec"`
}
@ -368,6 +372,9 @@ func ValidatePluginConfig(ctx context.Context, c *PluginConfig) error {
}
log.G(ctx).Warning("`runtime_root` is deprecated, please use runtime `options` instead")
}
if !r.PrivilegedWithoutHostDevices && r.PrivilegedWithoutHostDevicesAllDevicesAllowed {
return errors.Errorf("`privileged_without_host_devices_all_devices_allowed` requires `privileged_without_host_devices` to be enabled")
}
}
useConfigPath := c.Registry.ConfigPath != ""

View File

@ -360,6 +360,21 @@ func TestValidateConfig(t *testing.T) {
},
expectedErr: "`configs.tls` cannot be set when `config_path` is provided",
},
"privileged_without_host_devices_all_devices_allowed without privileged_without_host_devices": {
config: &PluginConfig{
ContainerdConfig: ContainerdConfig{
DefaultRuntimeName: RuntimeDefault,
Runtimes: map[string]Runtime{
RuntimeDefault: {
PrivilegedWithoutHostDevices: false,
PrivilegedWithoutHostDevicesAllDevicesAllowed: true,
Type: "default",
},
},
},
},
expectedErr: "`privileged_without_host_devices_all_devices_allowed` requires `privileged_without_host_devices` to be enabled",
},
} {
t.Run(desc, func(t *testing.T) {
err := ValidatePluginConfig(context.Background(), test.config)

View File

@ -223,6 +223,9 @@ func (c *criService) containerSpec(
specOpts = append(specOpts, oci.WithPrivileged)
if !ociRuntime.PrivilegedWithoutHostDevices {
specOpts = append(specOpts, oci.WithHostDevices, oci.WithAllDevicesAllowed)
} else if ociRuntime.PrivilegedWithoutHostDevicesAllDevicesAllowed {
// allow rwm on all devices for the container
specOpts = append(specOpts, oci.WithAllDevicesAllowed)
}
}

View File

@ -1380,29 +1380,46 @@ func TestPrivilegedDevices(t *testing.T) {
containerConfig, sandboxConfig, imageConfig, _ := getCreateContainerTestData()
for desc, test := range map[string]struct {
privileged bool
privilegedWithoutHostDevices bool
expectHostDevices bool
privileged bool
privilegedWithoutHostDevices bool
privilegedWithoutHostDevicesAllDevicesAllowed bool
expectHostDevices bool
expectAllDevicesAllowed bool
}{
"expect no host devices when privileged is false": {
privileged: false,
privilegedWithoutHostDevices: false,
expectHostDevices: false,
privilegedWithoutHostDevicesAllDevicesAllowed: false,
expectHostDevices: false,
expectAllDevicesAllowed: false,
},
"expect no host devices when privileged is false and privilegedWithoutHostDevices is true": {
privileged: false,
privilegedWithoutHostDevices: true,
expectHostDevices: false,
privilegedWithoutHostDevicesAllDevicesAllowed: false,
expectHostDevices: false,
expectAllDevicesAllowed: false,
},
"expect host devices when privileged is true": {
"expect host devices and all device allowlist when privileged is true": {
privileged: true,
privilegedWithoutHostDevices: false,
expectHostDevices: true,
privilegedWithoutHostDevicesAllDevicesAllowed: false,
expectHostDevices: true,
expectAllDevicesAllowed: true,
},
"expect no host devices when privileged is true and privilegedWithoutHostDevices is true": {
privileged: true,
privilegedWithoutHostDevices: true,
expectHostDevices: false,
privilegedWithoutHostDevicesAllDevicesAllowed: false,
expectHostDevices: false,
expectAllDevicesAllowed: false,
},
"expect host devices and all devices allowlist when privileged is true and privilegedWithoutHostDevices is true and privilegedWithoutHostDevicesAllDevicesAllowed is true": {
privileged: true,
privilegedWithoutHostDevices: true,
privilegedWithoutHostDevicesAllDevicesAllowed: true,
expectHostDevices: false,
expectAllDevicesAllowed: true,
},
} {
t.Logf("TestCase %q", desc)
@ -1411,7 +1428,8 @@ func TestPrivilegedDevices(t *testing.T) {
sandboxConfig.Linux.SecurityContext.Privileged = test.privileged
ociRuntime := config.Runtime{
PrivilegedWithoutHostDevices: test.privilegedWithoutHostDevices,
PrivilegedWithoutHostDevices: test.privilegedWithoutHostDevices,
PrivilegedWithoutHostDevicesAllDevicesAllowed: test.privilegedWithoutHostDevicesAllDevicesAllowed,
}
spec, err := c.containerSpec(t.Name(), testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
assert.NoError(t, err)
@ -1431,6 +1449,11 @@ func TestPrivilegedDevices(t *testing.T) {
} else {
assert.Empty(t, spec.Linux.Devices)
}
assert.Len(t, spec.Linux.Resources.Devices, 1)
assert.Equal(t, spec.Linux.Resources.Devices[0].Allow, test.expectAllDevicesAllowed)
assert.Equal(t, spec.Linux.Resources.Devices[0].Access, "rwm")
}
}