Merge pull request #117 from justincormack/uid

Allow uid, gid fields to be numeric or names
This commit is contained in:
Justin Cormack 2017-07-14 18:05:12 +01:00 committed by GitHub
commit f255d671c6
4 changed files with 61 additions and 33 deletions

View File

@ -15,8 +15,8 @@ Each section adds file to the root file system. Sections may be omitted.
Each container that is specified is allocated a unique `uid` and `gid` that it may use if it Each container that is specified is allocated a unique `uid` and `gid` that it may use if it
wishes to run as an isolated user (or user namespace). Anywhere you specify a `uid` or `gid` wishes to run as an isolated user (or user namespace). Anywhere you specify a `uid` or `gid`
field you specify a string that can either be the numeric id, or if you use a name it will field you specify either the numeric id, or if you use a name it will refer to the id allocated
refer to the id allocated to the container with that name. to the container with that name.
``` ```
services: services:

View File

@ -50,8 +50,8 @@ type File struct {
Source string Source string
Optional bool Optional bool
Mode string Mode string
UID string `yaml:"uid" json:"uid"` UID interface{} `yaml:"uid" json:"uid"`
GID string `yaml:"gid" json:"gid"` GID interface{} `yaml:"gid" json:"gid"`
} }
// Image is the type of an image config // Image is the type of an image config
@ -75,9 +75,9 @@ type Image struct {
Readonly *bool `yaml:"readonly" json:"readonly,omitempty"` Readonly *bool `yaml:"readonly" json:"readonly,omitempty"`
MaskedPaths *[]string `yaml:"maskedPaths" json:"maskedPaths,omitempty"` MaskedPaths *[]string `yaml:"maskedPaths" json:"maskedPaths,omitempty"`
ReadonlyPaths *[]string `yaml:"readonlyPaths" json:"readonlyPaths,omitempty"` ReadonlyPaths *[]string `yaml:"readonlyPaths" json:"readonlyPaths,omitempty"`
UID *string `yaml:"uid" json:"uid,omitempty"` UID *interface{} `yaml:"uid" json:"uid,omitempty"`
GID *string `yaml:"gid" json:"gid,omitempty"` GID *interface{} `yaml:"gid" json:"gid,omitempty"`
AdditionalGids *[]string `yaml:"additionalGids" json:"additionalGids,omitempty"` AdditionalGids *[]interface{} `yaml:"additionalGids" json:"additionalGids,omitempty"`
NoNewPrivileges *bool `yaml:"noNewPrivileges" json:"noNewPrivileges,omitempty"` NoNewPrivileges *bool `yaml:"noNewPrivileges" json:"noNewPrivileges,omitempty"`
OOMScoreAdj *int `yaml:"oomScoreAdj" json:"oomScoreAdj,omitempty"` OOMScoreAdj *int `yaml:"oomScoreAdj" json:"oomScoreAdj,omitempty"`
DisableOOMKiller *bool `yaml:"disableOOMKiller" json:"disableOOMKiller,omitempty"` DisableOOMKiller *bool `yaml:"disableOOMKiller" json:"disableOOMKiller,omitempty"`
@ -369,6 +369,29 @@ func assignUint32Array(v1, v2 *[]uint32) []uint32 {
return []uint32{} return []uint32{}
} }
// assignInterface does ordered overrides from Go interfaces
// we return 0 as we are using this for uid and this is the default
func assignInterface(v1, v2 *interface{}) interface{} {
if v2 != nil {
return *v2
}
if v1 != nil {
return *v1
}
return 0
}
// assignInterfaceArray does ordered overrides from arrays of Go interfaces
func assignInterfaceArray(v1, v2 *[]interface{}) []interface{} {
if v2 != nil {
return *v2
}
if v1 != nil {
return *v1
}
return []interface{}{}
}
// assignStrings does ordered overrides from JSON string array pointers // assignStrings does ordered overrides from JSON string array pointers
func assignStrings(v1, v2 *[]string) []string { func assignStrings(v1, v2 *[]string) []string {
if v2 != nil { if v2 != nil {
@ -424,7 +447,7 @@ func assignString(v1, v2 *string) string {
return "" return ""
} }
// assignMappings does prdered overrides from UID, GID maps // assignMappings does ordered overrides from UID, GID maps
func assignMappings(v1, v2 *[]specs.LinuxIDMapping) []specs.LinuxIDMapping { func assignMappings(v1, v2 *[]specs.LinuxIDMapping) []specs.LinuxIDMapping {
if v2 != nil { if v2 != nil {
return *v2 return *v2
@ -512,20 +535,25 @@ var allCaps = []string{
"CAP_WAKE_ALARM", "CAP_WAKE_ALARM",
} }
func idNumeric(id string, idMap map[string]uint32) (uint32, error) { func idNumeric(v interface{}, idMap map[string]uint32) (uint32, error) {
if id == "" || id == "root" { switch id := v.(type) {
return 0, nil case nil:
} return uint32(0), nil
for k, v := range idMap { case int:
if id == k { return uint32(id), nil
return v, nil case string:
if id == "" || id == "root" {
return uint32(0), nil
} }
for k, v := range idMap {
if id == k {
return v, nil
}
}
return 0, fmt.Errorf("Cannot find id: %s", id)
default:
return 0, fmt.Errorf("Bad type for uid or gid")
} }
v, err := strconv.ParseUint(id, 10, 32)
if err != nil {
return 0, fmt.Errorf("Cannot find or parse id (%s): %v", id, err)
}
return uint32(v), nil
} }
// ConfigInspectToOCI converts a config and the output of image inspect to an OCI config // ConfigInspectToOCI converts a config and the output of image inspect to an OCI config
@ -797,19 +825,19 @@ func ConfigInspectToOCI(yaml Image, inspect types.ImageInspect, idMap map[string
} }
// handle mapping of named uid, gid to numbers // handle mapping of named uid, gid to numbers
uidString := assignString(label.UID, yaml.UID) uidIf := assignInterface(label.UID, yaml.UID)
gidString := assignString(label.GID, yaml.GID) gidIf := assignInterface(label.GID, yaml.GID)
agStrings := assignStrings(label.AdditionalGids, yaml.AdditionalGids) agIf := assignInterfaceArray(label.AdditionalGids, yaml.AdditionalGids)
uid, err := idNumeric(uidString, idMap) uid, err := idNumeric(uidIf, idMap)
if err != nil { if err != nil {
return oci, err return oci, err
} }
gid, err := idNumeric(gidString, idMap) gid, err := idNumeric(gidIf, idMap)
if err != nil { if err != nil {
return oci, err return oci, err
} }
additionalGroups := []uint32{} additionalGroups := []uint32{}
for _, id := range agStrings { for _, id := range agIf {
ag, err := idNumeric(id, idMap) ag, err := idNumeric(id, idMap)
if err != nil { if err != nil {
return oci, err return oci, err

View File

@ -81,8 +81,8 @@ func TestInvalidCap(t *testing.T) {
func TestIdMap(t *testing.T) { func TestIdMap(t *testing.T) {
idMap := map[string]uint32{"test": 199} idMap := map[string]uint32{"test": 199}
uid := "test" var uid interface{} = "test"
gid := "76" var gid interface{} = 76
yaml := Image{ yaml := Image{
Name: "test", Name: "test",

View File

@ -27,8 +27,8 @@ var schema = string(`
"source": {"type": "string"}, "source": {"type": "string"},
"optional": {"type": "boolean"}, "optional": {"type": "boolean"},
"mode": {"type": "string"}, "mode": {"type": "string"},
"uid": {"type": "string"}, "uid": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
"gid": {"type": "string"} "gid": {"anyOf": [{"type": "string"}, {"type": "integer"}]}
} }
}, },
"files": { "files": {
@ -97,11 +97,11 @@ var schema = string(`
"readonly": { "type": "boolean"}, "readonly": { "type": "boolean"},
"maskedPaths": { "$ref": "#/definitions/strings" }, "maskedPaths": { "$ref": "#/definitions/strings" },
"readonlyPaths": { "$ref": "#/definitions/strings" }, "readonlyPaths": { "$ref": "#/definitions/strings" },
"uid": {"type": "string"}, "uid": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
"gid": {"type": "string"}, "gid": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
"additionalGids": { "additionalGids": {
"type": "array", "type": "array",
"items": { "type": "string" } "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}
}, },
"noNewPrivileges": {"type": "boolean"}, "noNewPrivileges": {"type": "boolean"},
"hostname": {"type": "string"}, "hostname": {"type": "string"},