Merge pull request #100 from justincormack/userns

Add partial user namespace support
This commit is contained in:
Justin Cormack 2017-07-10 14:30:30 +01:00 committed by GitHub
commit ec7e73b304
3 changed files with 76 additions and 34 deletions

View File

@ -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.

View File

@ -65,6 +65,7 @@ type Image struct {
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"`
@ -79,6 +80,8 @@ type Image struct {
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,8 +823,8 @@ func ConfigInspectToOCI(yaml Image, inspect types.ImageInspect, idMap map[string
oci.Mounts = mountList
oci.Linux = &specs.Linux{
// UIDMappings
// GIDMappings
UIDMappings: assignMappings(label.UIDMappings, yaml.UIDMappings),
GIDMappings: assignMappings(label.GIDMappings, yaml.GIDMappings),
Sysctl: assignMaps(label.Sysctl, yaml.Sysctl),
Resources: &specs.LinuxResources{
// Devices

View File

@ -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": {