Inline some SecurityContext fields into PodSecurityContext

This commit is contained in:
Paul Morie
2015-10-20 14:03:32 -04:00
parent 236193a26d
commit 393e2bc019
22 changed files with 22183 additions and 21218 deletions

View File

@@ -38,11 +38,12 @@ type SimpleSecurityContextProvider struct{}
// The security context provider can make changes to the Config with which
// the container is created.
func (p SimpleSecurityContextProvider) ModifyContainerConfig(pod *api.Pod, container *api.Container, config *docker.Config) {
if container.SecurityContext == nil {
effectiveSC := determineEffectiveSecurityContext(pod, container)
if effectiveSC == nil {
return
}
if container.SecurityContext.RunAsUser != nil {
config.User = strconv.FormatInt(*container.SecurityContext.RunAsUser, 10)
if effectiveSC.RunAsUser != nil {
config.User = strconv.Itoa(int(*effectiveSC.RunAsUser))
}
}
@@ -62,30 +63,32 @@ func (p SimpleSecurityContextProvider) ModifyHostConfig(pod *api.Pod, container
if pod.Spec.SecurityContext.SupplementalGroups != nil && container.Name != leaky.PodInfraContainerName {
hostConfig.GroupAdd = make([]string, len(pod.Spec.SecurityContext.SupplementalGroups))
for i, group := range pod.Spec.SecurityContext.SupplementalGroups {
hostConfig.GroupAdd[i] = strconv.FormatInt(group, 10)
hostConfig.GroupAdd[i] = strconv.Itoa(int(group))
}
}
}
// Apply container security context
if container.SecurityContext == nil {
// Apply effective security context for container
effectiveSC := determineEffectiveSecurityContext(pod, container)
if effectiveSC == nil {
return
}
if container.SecurityContext.Privileged != nil {
hostConfig.Privileged = *container.SecurityContext.Privileged
if effectiveSC.Privileged != nil {
hostConfig.Privileged = *effectiveSC.Privileged
}
if container.SecurityContext.Capabilities != nil {
add, drop := makeCapabilites(container.SecurityContext.Capabilities.Add, container.SecurityContext.Capabilities.Drop)
if effectiveSC.Capabilities != nil {
add, drop := makeCapabilites(effectiveSC.Capabilities.Add, effectiveSC.Capabilities.Drop)
hostConfig.CapAdd = add
hostConfig.CapDrop = drop
}
if container.SecurityContext.SELinuxOptions != nil {
hostConfig.SecurityOpt = modifySecurityOption(hostConfig.SecurityOpt, dockerLabelUser, container.SecurityContext.SELinuxOptions.User)
hostConfig.SecurityOpt = modifySecurityOption(hostConfig.SecurityOpt, dockerLabelRole, container.SecurityContext.SELinuxOptions.Role)
hostConfig.SecurityOpt = modifySecurityOption(hostConfig.SecurityOpt, dockerLabelType, container.SecurityContext.SELinuxOptions.Type)
hostConfig.SecurityOpt = modifySecurityOption(hostConfig.SecurityOpt, dockerLabelLevel, container.SecurityContext.SELinuxOptions.Level)
if effectiveSC.SELinuxOptions != nil {
hostConfig.SecurityOpt = modifySecurityOption(hostConfig.SecurityOpt, dockerLabelUser, effectiveSC.SELinuxOptions.User)
hostConfig.SecurityOpt = modifySecurityOption(hostConfig.SecurityOpt, dockerLabelRole, effectiveSC.SELinuxOptions.Role)
hostConfig.SecurityOpt = modifySecurityOption(hostConfig.SecurityOpt, dockerLabelType, effectiveSC.SELinuxOptions.Type)
hostConfig.SecurityOpt = modifySecurityOption(hostConfig.SecurityOpt, dockerLabelLevel, effectiveSC.SELinuxOptions.Level)
}
}
@@ -112,3 +115,69 @@ func makeCapabilites(capAdd []api.Capability, capDrop []api.Capability) ([]strin
}
return addCaps, dropCaps
}
func determineEffectiveSecurityContext(pod *api.Pod, container *api.Container) *api.SecurityContext {
effectiveSc := securityContextFromPodSecurityContext(pod)
containerSc := container.SecurityContext
if effectiveSc == nil && containerSc == nil {
return nil
}
if effectiveSc != nil && containerSc == nil {
return effectiveSc
}
if effectiveSc == nil && containerSc != nil {
return containerSc
}
if containerSc.SELinuxOptions != nil {
effectiveSc.SELinuxOptions = new(api.SELinuxOptions)
*effectiveSc.SELinuxOptions = *containerSc.SELinuxOptions
}
if containerSc.Capabilities != nil {
effectiveSc.Capabilities = new(api.Capabilities)
*effectiveSc.Capabilities = *containerSc.Capabilities
}
if containerSc.Privileged != nil {
effectiveSc.Privileged = new(bool)
*effectiveSc.Privileged = *containerSc.Privileged
}
if containerSc.RunAsUser != nil {
effectiveSc.RunAsUser = new(int64)
*effectiveSc.RunAsUser = *containerSc.RunAsUser
}
if containerSc.RunAsNonRoot != nil {
effectiveSc.RunAsNonRoot = new(bool)
*effectiveSc.RunAsNonRoot = *containerSc.RunAsNonRoot
}
return effectiveSc
}
func securityContextFromPodSecurityContext(pod *api.Pod) *api.SecurityContext {
if pod.Spec.SecurityContext == nil {
return nil
}
synthesized := &api.SecurityContext{}
if pod.Spec.SecurityContext.SELinuxOptions != nil {
synthesized.SELinuxOptions = &api.SELinuxOptions{}
*synthesized.SELinuxOptions = *pod.Spec.SecurityContext.SELinuxOptions
}
if pod.Spec.SecurityContext.RunAsUser != nil {
synthesized.RunAsUser = new(int64)
*synthesized.RunAsUser = *pod.Spec.SecurityContext.RunAsUser
}
if pod.Spec.SecurityContext.RunAsNonRoot != nil {
synthesized.RunAsNonRoot = new(bool)
*synthesized.RunAsNonRoot = *pod.Spec.SecurityContext.RunAsNonRoot
}
return synthesized
}

View File

@@ -28,94 +28,148 @@ import (
)
func TestModifyContainerConfig(t *testing.T) {
var uid int64 = 1
testCases := map[string]struct {
securityContext *api.SecurityContext
expected *docker.Config
var uid int64 = 123
var overrideUid int64 = 321
cases := []struct {
name string
podSc *api.PodSecurityContext
sc *api.SecurityContext
expected *docker.Config
}{
"modify config, value set for user": {
securityContext: &api.SecurityContext{
{
name: "container.SecurityContext.RunAsUser set",
sc: &api.SecurityContext{
RunAsUser: &uid,
},
expected: &docker.Config{
User: strconv.FormatInt(uid, 10),
},
},
"modify config, nil user value": {
securityContext: &api.SecurityContext{},
expected: &docker.Config{},
{
name: "no RunAsUser value set",
sc: &api.SecurityContext{},
expected: &docker.Config{},
},
{
name: "pod.Spec.SecurityContext.RunAsUser set",
podSc: &api.PodSecurityContext{
RunAsUser: &uid,
},
expected: &docker.Config{
User: strconv.FormatInt(uid, 10),
},
},
{
name: "container.SecurityContext.RunAsUser overrides pod.Spec.SecurityContext.RunAsUser",
podSc: &api.PodSecurityContext{
RunAsUser: &uid,
},
sc: &api.SecurityContext{
RunAsUser: &overrideUid,
},
expected: &docker.Config{
User: strconv.FormatInt(overrideUid, 10),
},
},
}
provider := NewSimpleSecurityContextProvider()
dummyContainer := &api.Container{}
for k, v := range testCases {
dummyContainer.SecurityContext = v.securityContext
for _, tc := range cases {
pod := &api.Pod{Spec: api.PodSpec{SecurityContext: tc.podSc}}
dummyContainer.SecurityContext = tc.sc
dockerCfg := &docker.Config{}
provider.ModifyContainerConfig(nil, dummyContainer, dockerCfg)
if !reflect.DeepEqual(v.expected, dockerCfg) {
t.Errorf("unexpected modification of docker config for %s. Expected: %#v Got: %#v", k, v.expected, dockerCfg)
provider.ModifyContainerConfig(pod, dummyContainer, dockerCfg)
if e, a := tc.expected, dockerCfg; !reflect.DeepEqual(e, a) {
t.Errorf("%v: unexpected modification of docker config\nExpected:\n\n%#v\n\nGot:\n\n%#v", tc.name, e, a)
}
}
}
func TestModifyHostConfig(t *testing.T) {
nilPrivSC := fullValidSecurityContext()
nilPrivSC.Privileged = nil
nilPrivHC := fullValidHostConfig()
nilPrivHC.Privileged = false
priv := true
setPrivSC := &api.SecurityContext{}
setPrivSC.Privileged = &priv
setPrivHC := &docker.HostConfig{
Privileged: true,
}
nilCapsSC := fullValidSecurityContext()
nilCapsSC.Capabilities = nil
nilCapsHC := fullValidHostConfig()
nilCapsHC.CapAdd = *new([]string)
nilCapsHC.CapDrop = *new([]string)
setCapsHC := &docker.HostConfig{
CapAdd: []string{"addCapA", "addCapB"},
CapDrop: []string{"dropCapA", "dropCapB"},
}
nilSELinuxSC := fullValidSecurityContext()
nilSELinuxSC.SELinuxOptions = nil
nilSELinuxHC := fullValidHostConfig()
nilSELinuxHC.SecurityOpt = *new([]string)
setSELinuxHC := &docker.HostConfig{}
setSELinuxHC.SecurityOpt = []string{
fmt.Sprintf("%s:%s", dockerLabelUser, "user"),
fmt.Sprintf("%s:%s", dockerLabelRole, "role"),
fmt.Sprintf("%s:%s", dockerLabelType, "type"),
fmt.Sprintf("%s:%s", dockerLabelLevel, "level"),
}
seLinuxLabelsSC := fullValidSecurityContext()
seLinuxLabelsHC := fullValidHostConfig()
// seLinuxLabelsSC := fullValidSecurityContext()
// seLinuxLabelsHC := fullValidHostConfig()
testCases := map[string]struct {
securityContext *api.SecurityContext
expected *docker.HostConfig
cases := []struct {
name string
podSc *api.PodSecurityContext
sc *api.SecurityContext
expected *docker.HostConfig
}{
"full settings": {
securityContext: fullValidSecurityContext(),
expected: fullValidHostConfig(),
{
name: "fully set container.SecurityContext",
sc: fullValidSecurityContext(),
expected: fullValidHostConfig(),
},
"nil privileged": {
securityContext: nilPrivSC,
expected: nilPrivHC,
{
name: "container.SecurityContext.Privileged",
sc: setPrivSC,
expected: setPrivHC,
},
"nil capabilities": {
securityContext: nilCapsSC,
expected: nilCapsHC,
{
name: "container.SecurityContext.Capabilities",
sc: &api.SecurityContext{
Capabilities: inputCapabilities(),
},
expected: setCapsHC,
},
"nil selinux options": {
securityContext: nilSELinuxSC,
expected: nilSELinuxHC,
{
name: "container.SecurityContext.SELinuxOptions",
sc: &api.SecurityContext{
SELinuxOptions: inputSELinuxOptions(),
},
expected: setSELinuxHC,
},
"selinux labels": {
securityContext: seLinuxLabelsSC,
expected: seLinuxLabelsHC,
{
name: "pod.Spec.SecurityContext.SELinuxOptions",
podSc: &api.PodSecurityContext{
SELinuxOptions: inputSELinuxOptions(),
},
expected: setSELinuxHC,
},
{
name: "container.SecurityContext overrides pod.Spec.SecurityContext",
podSc: overridePodSecurityContext(),
sc: fullValidSecurityContext(),
expected: fullValidHostConfig(),
},
}
provider := NewSimpleSecurityContextProvider()
dummyContainer := &api.Container{}
dummyPod := &api.Pod{
Spec: apitesting.DeepEqualSafePodSpec(),
}
for k, v := range testCases {
dummyContainer.SecurityContext = v.securityContext
for _, tc := range cases {
pod := &api.Pod{Spec: api.PodSpec{SecurityContext: tc.podSc}}
dummyContainer.SecurityContext = tc.sc
dockerCfg := &docker.HostConfig{}
provider.ModifyHostConfig(dummyPod, dummyContainer, dockerCfg)
if !reflect.DeepEqual(v.expected, dockerCfg) {
t.Errorf("unexpected modification of host config for %s. Expected: %#v Got: %#v", k, v.expected, dockerCfg)
provider.ModifyHostConfig(pod, dummyContainer, dockerCfg)
if e, a := tc.expected, dockerCfg; !reflect.DeepEqual(e, a) {
t.Errorf("%v: unexpected modification of host config\nExpected:\n\n%#v\n\nGot:\n\n%#v", tc.name, e, a)
}
}
}
@@ -189,20 +243,45 @@ func TestModifySecurityOption(t *testing.T) {
}
}
func overridePodSecurityContext() *api.PodSecurityContext {
return &api.PodSecurityContext{
SELinuxOptions: &api.SELinuxOptions{
User: "user2",
Role: "role2",
Type: "type2",
Level: "level2",
},
}
}
func fullValidPodSecurityContext() *api.PodSecurityContext {
return &api.PodSecurityContext{
SELinuxOptions: inputSELinuxOptions(),
}
}
func fullValidSecurityContext() *api.SecurityContext {
priv := true
return &api.SecurityContext{
Privileged: &priv,
Capabilities: &api.Capabilities{
Add: []api.Capability{"addCapA", "addCapB"},
Drop: []api.Capability{"dropCapA", "dropCapB"},
},
SELinuxOptions: &api.SELinuxOptions{
User: "user",
Role: "role",
Type: "type",
Level: "level",
},
Privileged: &priv,
Capabilities: inputCapabilities(),
SELinuxOptions: inputSELinuxOptions(),
}
}
func inputCapabilities() *api.Capabilities {
return &api.Capabilities{
Add: []api.Capability{"addCapA", "addCapB"},
Drop: []api.Capability{"dropCapA", "dropCapB"},
}
}
func inputSELinuxOptions() *api.SELinuxOptions {
return &api.SELinuxOptions{
User: "user",
Role: "role",
Type: "type",
Level: "level",
}
}