Files
nomad/drivers/shared/capabilities/set.go
Seth Hoenig 191144c3bf drivers/exec: enable setting allow_caps on exec driver
This PR enables setting allow_caps on the exec driver
plugin configuration, as well as cap_add and cap_drop in
exec task configuration. These options replicate the
functionality already present in the docker task driver.

Important: this change also reduces the default set of
capabilities enabled by the exec driver to match the
default set enabled by the docker driver. Until v1.0.5
the exec task driver would enable all capabilities supported
by the operating system. v1.0.5 removed NET_RAW from that
list of default capabilities, but left may others which
could potentially also be leveraged by compromised tasks.

Important: the "root" user is still special cased when
used with the exec driver. Older versions of Nomad enabled
enabled all capabilities supported by the operating system
for tasks set with the root user. To maintain compatibility
with existing clusters we continue supporting this "feature",
however we maintain support for the legacy set of capabilities
rather than enabling all capabilities now supported on modern
operating systems.
2021-05-17 12:37:40 -06:00

111 lines
2.6 KiB
Go

// Package capabilities is used for managing sets of linux capabilities.
package capabilities
import (
"sort"
"strings"
)
type nothing struct{}
var null = nothing{}
// Set represents a group linux capabilities, implementing some useful set
// operations, taking care of name normalization, and sentinel value expansions.
//
// Linux capabilities can be expressed in multiple ways when working with docker
// and/or libcontainer, along with Nomad.
//
// Capability names may be upper or lower case, and may or may not be prefixed
// with "CAP_" or "cap_". On top of that, Nomad interprets the special name "all"
// and "ALL" to mean "all capabilities supported by the operating system".
type Set struct {
data map[string]nothing
}
func New(caps []string) *Set {
m := make(map[string]nothing, len(caps))
for _, c := range caps {
insert(m, c)
}
return &Set{data: m}
}
// Add cap into s.
func (s *Set) Add(cap string) {
insert(s.data, cap)
}
func insert(data map[string]nothing, cap string) {
switch name := normalize(cap); name {
case "":
case "all":
for k, v := range Supported().data {
data[k] = v
}
return
default:
data[name] = null
}
}
// Remove caps from s.
func (s *Set) Remove(caps []string) {
for _, c := range caps {
name := normalize(c)
if name == "all" {
s.data = make(map[string]nothing)
return
}
delete(s.data, name)
}
}
// Difference returns the Set of elements of b not in s.
func (s *Set) Difference(b *Set) *Set {
data := make(map[string]nothing)
for c := range b.data {
if _, exists := s.data[c]; !exists {
data[c] = null
}
}
return &Set{data: data}
}
// Empty return true if no capabilities exist in s.
func (s *Set) Empty() bool {
return len(s.data) == 0
}
// String returns the normalized and sorted string representation of s.
func (s *Set) String() string {
return strings.Join(s.Slice(false), ", ")
}
// Slice returns a sorted slice of capabilities in s.
//
// big - indicates whether to uppercase and prefix capabilities with CAP_
func (s *Set) Slice(upper bool) []string {
caps := make([]string, 0, len(s.data))
for c := range s.data {
if upper {
c = "CAP_" + strings.ToUpper(c)
}
caps = append(caps, c)
}
sort.Strings(caps)
return caps
}
// linux capabilities are often named in 4 possible ways - upper or lower case,
// and with or without a CAP_ prefix
//
// since we must do comparisons on cap names, always normalize the names before
// letting them into the Set data-structure
func normalize(name string) string {
spaces := strings.TrimSpace(name)
lower := strings.ToLower(spaces)
trim := strings.TrimPrefix(lower, "cap_")
return trim
}