diff --git a/docs/yaml.md b/docs/yaml.md index a48a2b79b..9b9db8ea2 100644 --- a/docs/yaml.md +++ b/docs/yaml.md @@ -158,6 +158,9 @@ bind mounted into a container. - `sysctl` sets a list of `sysctl` key value pairs that are set inside the container namespace. - `rmlimits` sets a list of `rlimit` values in the form `name,soft,hard`, eg `nofile,100,200`. You can use `unlimited` as a value too. +There are experimental `userns`, `uidMappings` and `gidMappings` options for user namespaces but these are not yet supported, and may have +permissions issues in use. + ### Mount Options When mounting filesystem paths into a container - whether as part of `onboot` or `services` - there are several options of which you need to be aware. Using them properly is necessary for your containers to function properly. diff --git a/src/moby/config.go b/src/moby/config.go index d0306f2ef..e425fc6e9 100644 --- a/src/moby/config.go +++ b/src/moby/config.go @@ -51,34 +51,37 @@ type File struct { // Image is the type of an image config type Image struct { - Name string `yaml:"name" json:"name"` - Image string `yaml:"image" json:"image"` - Capabilities *[]string `yaml:"capabilities" json:"capabilities,omitempty"` - Ambient *[]string `yaml:"ambient" json:"ambient,omitempty"` - Mounts *[]specs.Mount `yaml:"mounts" json:"mounts,omitempty"` - Binds *[]string `yaml:"binds" json:"binds,omitempty"` - Tmpfs *[]string `yaml:"tmpfs" json:"tmpfs,omitempty"` - Command *[]string `yaml:"command" json:"command,omitempty"` - Env *[]string `yaml:"env" json:"env,omitempty"` - Cwd string `yaml:"cwd" json:"cwd"` - Net string `yaml:"net" json:"net"` - Pid string `yaml:"pid" json:"pid"` - Ipc string `yaml:"ipc" json:"ipc"` - Uts string `yaml:"uts" json:"uts"` - Hostname string `yaml:"hostname" json:"hostname"` - Readonly *bool `yaml:"readonly" json:"readonly,omitempty"` - MaskedPaths *[]string `yaml:"maskedPaths" json:"maskedPaths,omitempty"` - ReadonlyPaths *[]string `yaml:"readonlyPaths" json:"readonlyPaths,omitempty"` - UID *string `yaml:"uid" json:"uid,omitempty"` - GID *string `yaml:"gid" json:"gid,omitempty"` - AdditionalGids *[]string `yaml:"additionalGids" json:"additionalGids,omitempty"` - NoNewPrivileges *bool `yaml:"noNewPrivileges" json:"noNewPrivileges,omitempty"` - OOMScoreAdj *int `yaml:"oomScoreAdj" json:"oomScoreAdj,omitempty"` - DisableOOMKiller *bool `yaml:"disableOOMKiller" json:"disableOOMKiller,omitempty"` - RootfsPropagation *string `yaml:"rootfsPropagation" json:"rootfsPropagation,omitempty"` - CgroupsPath *string `yaml:"cgroupsPath" json:"cgroupsPath,omitempty"` - Sysctl *map[string]string `yaml:"sysctl" json:"sysctl,omitempty"` - Rlimits *[]string `yaml:"rlimits" json:"rlimits,omitempty"` + Name string `yaml:"name" json:"name"` + Image string `yaml:"image" json:"image"` + Capabilities *[]string `yaml:"capabilities" json:"capabilities,omitempty"` + Ambient *[]string `yaml:"ambient" json:"ambient,omitempty"` + Mounts *[]specs.Mount `yaml:"mounts" json:"mounts,omitempty"` + Binds *[]string `yaml:"binds" json:"binds,omitempty"` + Tmpfs *[]string `yaml:"tmpfs" json:"tmpfs,omitempty"` + Command *[]string `yaml:"command" json:"command,omitempty"` + Env *[]string `yaml:"env" json:"env,omitempty"` + Cwd string `yaml:"cwd" json:"cwd"` + Net string `yaml:"net" json:"net"` + Pid string `yaml:"pid" json:"pid"` + Ipc string `yaml:"ipc" json:"ipc"` + Uts string `yaml:"uts" json:"uts"` + Userns string `yaml:"userns" json:"userns"` + Hostname string `yaml:"hostname" json:"hostname"` + Readonly *bool `yaml:"readonly" json:"readonly,omitempty"` + MaskedPaths *[]string `yaml:"maskedPaths" json:"maskedPaths,omitempty"` + ReadonlyPaths *[]string `yaml:"readonlyPaths" json:"readonlyPaths,omitempty"` + UID *string `yaml:"uid" json:"uid,omitempty"` + GID *string `yaml:"gid" json:"gid,omitempty"` + AdditionalGids *[]string `yaml:"additionalGids" json:"additionalGids,omitempty"` + NoNewPrivileges *bool `yaml:"noNewPrivileges" json:"noNewPrivileges,omitempty"` + OOMScoreAdj *int `yaml:"oomScoreAdj" json:"oomScoreAdj,omitempty"` + DisableOOMKiller *bool `yaml:"disableOOMKiller" json:"disableOOMKiller,omitempty"` + RootfsPropagation *string `yaml:"rootfsPropagation" json:"rootfsPropagation,omitempty"` + CgroupsPath *string `yaml:"cgroupsPath" json:"cgroupsPath,omitempty"` + Sysctl *map[string]string `yaml:"sysctl" json:"sysctl,omitempty"` + Rlimits *[]string `yaml:"rlimits" json:"rlimits,omitempty"` + UIDMappings *[]specs.LinuxIDMapping `yaml:"uidMappings" json:"uidMappings,omitempty"` + GIDMappings *[]specs.LinuxIDMapping `yaml:"gidMappings" json:"gidMappings,omitempty"` } // github.com/go-yaml/yaml treats map keys as interface{} while encoding/json @@ -390,6 +393,17 @@ func assignString(v1, v2 *string) string { return "" } +// assignMappings does prdered overrides from UID, GID maps +func assignMappings(v1, v2 *[]specs.LinuxIDMapping) []specs.LinuxIDMapping { + if v2 != nil { + return *v2 + } + if v1 != nil { + return *v1 + } + return []specs.LinuxIDMapping{} +} + // assignStringEmpty does ordered overrides if strings are empty, for // values where there is always an explicit override eg "none" func assignStringEmpty(v1, v2 string) string { @@ -604,7 +618,7 @@ func ConfigInspectToOCI(yaml Image, inspect types.ImageInspect, idMap map[string namespaces := []specs.LinuxNamespace{} // to attach to an existing namespace, easiest to bind mount with nsfs in a system container - // net, ipc and uts namespaces: default to not creating a new namespace (usually host namespace) + // net, ipc, and uts namespaces: default to not creating a new namespace (usually host namespace) netNS := assignStringEmpty3("root", label.Net, yaml.Net) if netNS != "host" && netNS != "root" { if netNS == "none" || netNS == "new" { @@ -636,10 +650,19 @@ func ConfigInspectToOCI(yaml Image, inspect types.ImageInspect, idMap map[string namespaces = append(namespaces, specs.LinuxNamespace{Type: specs.PIDNamespace, Path: pidNS}) } + // do not create a user namespace unless asked, needs additional configuration + userNS := assignStringEmpty3("root", label.Userns, yaml.Userns) + if userNS != "host" && userNS != "root" { + if userNS == "new" { + userNS = "" + } + namespaces = append(namespaces, specs.LinuxNamespace{Type: specs.UserNamespace, Path: userNS}) + } + // Always create a new mount namespace namespaces = append(namespaces, specs.LinuxNamespace{Type: specs.MountNamespace}) - // TODO user, cgroup namespaces + // TODO cgroup namespaces // Capabilities capCheck := map[string]bool{} @@ -800,9 +823,9 @@ func ConfigInspectToOCI(yaml Image, inspect types.ImageInspect, idMap map[string oci.Mounts = mountList oci.Linux = &specs.Linux{ - // UIDMappings - // GIDMappings - Sysctl: assignMaps(label.Sysctl, yaml.Sysctl), + UIDMappings: assignMappings(label.UIDMappings, yaml.UIDMappings), + GIDMappings: assignMappings(label.GIDMappings, yaml.GIDMappings), + Sysctl: assignMaps(label.Sysctl, yaml.Sysctl), Resources: &specs.LinuxResources{ // Devices DisableOOMKiller: assignBoolPtr(label.DisableOOMKiller, yaml.DisableOOMKiller), diff --git a/src/moby/schema.go b/src/moby/schema.go index 33a181d55..3539c205c 100644 --- a/src/moby/schema.go +++ b/src/moby/schema.go @@ -59,6 +59,19 @@ var schema = string(` "type": "array", "items": { "$ref": "#/definitions/mount" } }, + "idmapping": { + "type": "object", + "additionalProperties": false, + "properties": { + "hostID": { "type": "integer" }, + "containerID": { "type": "integer" }, + "size": { "type": "integer" } + } + }, + "idmappings": { + "type": "array", + "items": { "$ref": "#/definitions/idmapping" } + }, "image": { "type": "object", "additionalProperties": false, @@ -78,6 +91,7 @@ var schema = string(` "pid": { "type": "string"}, "ipc": { "type": "string"}, "uts": { "type": "string"}, + "userns": { "type": "string"}, "readonly": { "type": "boolean"}, "maskedPaths": { "$ref": "#/definitions/strings" }, "readonlyPaths": { "$ref": "#/definitions/strings" }, @@ -97,7 +111,9 @@ var schema = string(` "type": "array", "items": { "$ref": "#/definitions/strings" } }, - "rlimits": { "$ref": "#/definitions/strings" } + "rlimits": { "$ref": "#/definitions/strings" }, + "uidMappings": { "$ref": "#/definitions/idmappings" }, + "gidMappings": { "$ref": "#/definitions/idmappings" } } }, "images": {