Inline some SecurityContext fields into PodSecurityContext
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
@@ -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",
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user