diff --git a/cmd/hepto/config.go b/cmd/hepto/config.go index 15cef956d1e97c72daf34b99fe9bc40c7749bd27..0724439855110f037dbc4350ddba78a679e010ec 100644 --- a/cmd/hepto/config.go +++ b/cmd/hepto/config.go @@ -24,6 +24,43 @@ var defaultDNS = []net.IP{ {0x26, 0x06, 0x47, 0, 0x47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0x01}, } +// Required capabilities for kubernetes +var additionalCapabilities = []string{ + // Necessary for bind mounts by kubelet + "CAP_SYS_ADMIN", + // Required for raw sockets, including ICMP + "CAP_NET_RAW", + // Required for unpacking docker images properly + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + // Required for adjusting oom score by runc + "CAP_SYS_RESOURCE", + // Required for setting uid and gid by runc + "CAP_SETUID", + "CAP_SETGID", + // Required to read ns/ipc file in downstream runc + "CAP_SYS_PTRACE", + // Not used explicitely by runc, but currently default in libcontainer + // and not customizable + "CAP_FOWNER", + "CAP_FSETID", + "CAP_KILL", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_MKNOD", + "CAP_AUDIT_WRITE", + "CAP_SETFCAP", + "CAP_FSETID", +} + +// Required devices for kubernetes +var additionalDevices = []string { + "/dev/kmsg", + "/dev/full", + "/dev/tty", +} + func (c Config) dataPath(subPath string) string { dir := path.Join(c.DataDir, c.Cluster.Name, c.Node.Name, subPath) os.MkdirAll(dir, 0700) @@ -34,6 +71,8 @@ func (c *Config) Complete() { c.Container.Root = c.dataPath("root") c.Container.Data = c.dataPath("containers") c.Container.Name = c.Node.Name + c.Container.Capabilities = additionalCapabilities + c.Container.Devices = additionalDevices } var config Config diff --git a/pkg/selfcontain/config.go b/pkg/selfcontain/config.go index 212b0b1ecde9b5291da8666eb5e3ce55f5bdd89b..cf7d4c033fe106b337753cce6d0349f4236149f8 100644 --- a/pkg/selfcontain/config.go +++ b/pkg/selfcontain/config.go @@ -19,4 +19,8 @@ type Config struct { GW net.IP // List of DNS servers for the container DNS []net.IP + // List of non-standard capabilities (required capabilities are always enabled) + Capabilities []string + // List of non-standard devices + Devices []string } diff --git a/pkg/selfcontain/container.go b/pkg/selfcontain/container.go index 4f5e49d1acbe99371b5e6d50e374a501bb3e8e78..4b70914854ca0f41acb733399e42a59d10eb6e0d 100644 --- a/pkg/selfcontain/container.go +++ b/pkg/selfcontain/container.go @@ -51,8 +51,8 @@ func New(config *Config) (*Container, error) { if err != nil { return nil, err } - // Use the default container configuration and create the container and process - defaults := makeDefaults(config.Name, config.Root, self) + // Customize the default container configuration and create the container and process + defaults := makeDefaults(config.Name, config.Root, self, config.Capabilities, config.Devices) container, err := factory.Create(config.Name, defaults) if err != nil { return nil, err diff --git a/pkg/selfcontain/defaults.go b/pkg/selfcontain/defaults.go index f3cfbe104585f99505be6982622249c33ec506a3..fbab5d1f9cc97fa481b57147855f67287485bc2a 100644 --- a/pkg/selfcontain/defaults.go +++ b/pkg/selfcontain/defaults.go @@ -12,107 +12,14 @@ import ( // as a libcontainer init, which in turn is handled by init() const argInit = "selfcontain-arg-libcontainer" -// Restrict access to the bare minimum for hepto to run properly +// Restrict access to the bare minimum for container to run properly // See https://pkg.go.dev/github.com/opencontainers/runc@v1.0.2/libcontainer/specconv // for comments about issues with default restrictions -var allowedDevices = []*devices.Device{ - { - Path: "/dev/null", - FileMode: 0o666, - Uid: 0, - Gid: 0, - Rule: devices.Rule{ - Type: devices.CharDevice, - Major: 1, - Minor: 3, - Permissions: "rw", - Allow: true, - }, - }, - { - Path: "/dev/zero", - FileMode: 0o666, - Uid: 0, - Gid: 0, - Rule: devices.Rule{ - Type: devices.CharDevice, - Major: 1, - Minor: 5, - Permissions: "rwm", - Allow: true, - }, - }, - { - Path: "/dev/urandom", - FileMode: 0o666, - Uid: 0, - Gid: 0, - Rule: devices.Rule{ - Type: devices.CharDevice, - Major: 1, - Minor: 9, - Permissions: "rwm", - Allow: true, - }, - }, - // Required by kubelet and other kubernetes related downstream - // processes - { - Path: "/dev/kmsg", - FileMode: 0o666, - Uid: 0, - Gid: 0, - Rule: devices.Rule{ - Type: devices.CharDevice, - Major: 1, - Minor: 11, - Permissions: "r", - Allow: true, - }, - }, - // Required by many downstream processes, including anything - // like an http client which does tls - { - Path: "/dev/random", - FileMode: 0o666, - Uid: 0, - Gid: 0, - Rule: devices.Rule{ - Type: devices.CharDevice, - Major: 1, - Minor: 8, - Permissions: "r", - Allow: true, - }, - }, - // Required by downstream runc for mounting - { - Path: "/dev/full", - FileMode: 0o666, - Uid: 0, - Gid: 0, - Rule: devices.Rule{ - Type: devices.CharDevice, - Major: 1, - Minor: 7, - Permissions: "rw", - Allow: true, - }, - }, - // Required by downstream containers for mounting a tty - { - Path: "/dev/tty", - FileMode: 0o666, - Uid: 0, - Gid: 0, - Rule: devices.Rule{ - Type: devices.CharDevice, - Major: 5, - Minor: 0, - Permissions: "rw", - Allow: true, - }, - }, +var baseDevices = []string{ + "/dev/null", + "/dev/zero", + "/dev/urandom", + "/dev/random", } // These path will be mounted as a default base inside the container @@ -165,34 +72,9 @@ var defaultMounts = []*configs.Mount{ // Restrict capabilities to strictly required capabilities // All capabilities are inheritable and ambient, so that init execve works properly -var capabilities = []string{ - // TODO: remove this and avoid bind mounts - "CAP_SYS_ADMIN", +var baseCapabilities = []string{ // Required for later setting up networking "CAP_NET_ADMIN", - // Required for raw sockets, including ICMP - "CAP_NET_RAW", - // Required for unpacking archives and images - "CAP_CHOWN", - "CAP_DAC_OVERRIDE", - // Required for adjusting oom score by runc - "CAP_SYS_RESOURCE", - // Required for setting uid and gid by runc - "CAP_SETUID", - "CAP_SETGID", - // Added temporarily to accomodate runc capabilities - "CAP_FOWNER", - "CAP_FSETID", - "CAP_KILL", - "CAP_SETPCAP", - "CAP_NET_BIND_SERVICE", - "CAP_NET_RAW", - "CAP_SYS_CHROOT", - "CAP_MKNOD", - "CAP_AUDIT_WRITE", - "CAP_SETFCAP", - "CAP_FSETID", - "CAP_SYS_PTRACE", // To read ns/ipc files } // These networks will be setup as a default base inside the container @@ -223,7 +105,16 @@ var readOnlyPath = []string{ } // Make a container configuration using defaults -func makeDefaults(name string, root string, self string) *configs.Config { +func makeDefaults(name string, root string, self string, capabilities []string, deviceNames []string) *configs.Config { + allowedDevices := []*devices.Device{} + for _, path := range deviceNames { + // TODO: do not ignore the error + device, _ := devices.DeviceFromPath(path, "rw") + allowedDevices = append(allowedDevices, device) + } + for _, capability := range baseCapabilities { + capabilities = append(capabilities, capability) + } deviceRules := []*devices.Rule{} for _, device := range allowedDevices { deviceRules = append(deviceRules, &device.Rule)