provider.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package securitycontext
  14. import (
  15. "fmt"
  16. "strconv"
  17. "k8s.io/kubernetes/pkg/api"
  18. "k8s.io/kubernetes/pkg/kubelet/leaky"
  19. dockercontainer "github.com/docker/engine-api/types/container"
  20. )
  21. // NewSimpleSecurityContextProvider creates a new SimpleSecurityContextProvider.
  22. func NewSimpleSecurityContextProvider() SecurityContextProvider {
  23. return SimpleSecurityContextProvider{}
  24. }
  25. // SimpleSecurityContextProvider is the default implementation of a SecurityContextProvider.
  26. type SimpleSecurityContextProvider struct{}
  27. // ModifyContainerConfig is called before the Docker createContainer call.
  28. // The security context provider can make changes to the Config with which
  29. // the container is created.
  30. func (p SimpleSecurityContextProvider) ModifyContainerConfig(pod *api.Pod, container *api.Container, config *dockercontainer.Config) {
  31. effectiveSC := DetermineEffectiveSecurityContext(pod, container)
  32. if effectiveSC == nil {
  33. return
  34. }
  35. if effectiveSC.RunAsUser != nil {
  36. config.User = strconv.Itoa(int(*effectiveSC.RunAsUser))
  37. }
  38. }
  39. // ModifyHostConfig is called before the Docker runContainer call. The
  40. // security context provider can make changes to the HostConfig, affecting
  41. // security options, whether the container is privileged, volume binds, etc.
  42. func (p SimpleSecurityContextProvider) ModifyHostConfig(pod *api.Pod, container *api.Container, hostConfig *dockercontainer.HostConfig, supplementalGids []int64) {
  43. // Apply supplemental groups
  44. if container.Name != leaky.PodInfraContainerName {
  45. // TODO: We skip application of supplemental groups to the
  46. // infra container to work around a runc issue which
  47. // requires containers to have the '/etc/group'. For
  48. // more information see:
  49. // https://github.com/opencontainers/runc/pull/313
  50. // This can be removed once the fix makes it into the
  51. // required version of docker.
  52. if pod.Spec.SecurityContext != nil {
  53. for _, group := range pod.Spec.SecurityContext.SupplementalGroups {
  54. hostConfig.GroupAdd = append(hostConfig.GroupAdd, strconv.Itoa(int(group)))
  55. }
  56. if pod.Spec.SecurityContext.FSGroup != nil {
  57. hostConfig.GroupAdd = append(hostConfig.GroupAdd, strconv.Itoa(int(*pod.Spec.SecurityContext.FSGroup)))
  58. }
  59. }
  60. for _, group := range supplementalGids {
  61. hostConfig.GroupAdd = append(hostConfig.GroupAdd, strconv.Itoa(int(group)))
  62. }
  63. }
  64. // Apply effective security context for container
  65. effectiveSC := DetermineEffectiveSecurityContext(pod, container)
  66. if effectiveSC == nil {
  67. return
  68. }
  69. if effectiveSC.Privileged != nil {
  70. hostConfig.Privileged = *effectiveSC.Privileged
  71. }
  72. if effectiveSC.Capabilities != nil {
  73. add, drop := MakeCapabilities(effectiveSC.Capabilities.Add, effectiveSC.Capabilities.Drop)
  74. hostConfig.CapAdd = add
  75. hostConfig.CapDrop = drop
  76. }
  77. if effectiveSC.SELinuxOptions != nil {
  78. hostConfig.SecurityOpt = modifySecurityOption(hostConfig.SecurityOpt, dockerLabelUser, effectiveSC.SELinuxOptions.User)
  79. hostConfig.SecurityOpt = modifySecurityOption(hostConfig.SecurityOpt, dockerLabelRole, effectiveSC.SELinuxOptions.Role)
  80. hostConfig.SecurityOpt = modifySecurityOption(hostConfig.SecurityOpt, dockerLabelType, effectiveSC.SELinuxOptions.Type)
  81. hostConfig.SecurityOpt = modifySecurityOption(hostConfig.SecurityOpt, dockerLabelLevel, effectiveSC.SELinuxOptions.Level)
  82. }
  83. }
  84. // modifySecurityOption adds the security option of name to the config array with value in the form
  85. // of name:value
  86. func modifySecurityOption(config []string, name, value string) []string {
  87. if len(value) > 0 {
  88. config = append(config, fmt.Sprintf("%s:%s", name, value))
  89. }
  90. return config
  91. }
  92. // MakeCapabilities creates string slices from Capability slices
  93. func MakeCapabilities(capAdd []api.Capability, capDrop []api.Capability) ([]string, []string) {
  94. var (
  95. addCaps []string
  96. dropCaps []string
  97. )
  98. for _, cap := range capAdd {
  99. addCaps = append(addCaps, string(cap))
  100. }
  101. for _, cap := range capDrop {
  102. dropCaps = append(dropCaps, string(cap))
  103. }
  104. return addCaps, dropCaps
  105. }
  106. func DetermineEffectiveSecurityContext(pod *api.Pod, container *api.Container) *api.SecurityContext {
  107. effectiveSc := securityContextFromPodSecurityContext(pod)
  108. containerSc := container.SecurityContext
  109. if effectiveSc == nil && containerSc == nil {
  110. return nil
  111. }
  112. if effectiveSc != nil && containerSc == nil {
  113. return effectiveSc
  114. }
  115. if effectiveSc == nil && containerSc != nil {
  116. return containerSc
  117. }
  118. if containerSc.SELinuxOptions != nil {
  119. effectiveSc.SELinuxOptions = new(api.SELinuxOptions)
  120. *effectiveSc.SELinuxOptions = *containerSc.SELinuxOptions
  121. }
  122. if containerSc.Capabilities != nil {
  123. effectiveSc.Capabilities = new(api.Capabilities)
  124. *effectiveSc.Capabilities = *containerSc.Capabilities
  125. }
  126. if containerSc.Privileged != nil {
  127. effectiveSc.Privileged = new(bool)
  128. *effectiveSc.Privileged = *containerSc.Privileged
  129. }
  130. if containerSc.RunAsUser != nil {
  131. effectiveSc.RunAsUser = new(int64)
  132. *effectiveSc.RunAsUser = *containerSc.RunAsUser
  133. }
  134. if containerSc.RunAsNonRoot != nil {
  135. effectiveSc.RunAsNonRoot = new(bool)
  136. *effectiveSc.RunAsNonRoot = *containerSc.RunAsNonRoot
  137. }
  138. if containerSc.ReadOnlyRootFilesystem != nil {
  139. effectiveSc.ReadOnlyRootFilesystem = new(bool)
  140. *effectiveSc.ReadOnlyRootFilesystem = *containerSc.ReadOnlyRootFilesystem
  141. }
  142. return effectiveSc
  143. }
  144. func securityContextFromPodSecurityContext(pod *api.Pod) *api.SecurityContext {
  145. if pod.Spec.SecurityContext == nil {
  146. return nil
  147. }
  148. synthesized := &api.SecurityContext{}
  149. if pod.Spec.SecurityContext.SELinuxOptions != nil {
  150. synthesized.SELinuxOptions = &api.SELinuxOptions{}
  151. *synthesized.SELinuxOptions = *pod.Spec.SecurityContext.SELinuxOptions
  152. }
  153. if pod.Spec.SecurityContext.RunAsUser != nil {
  154. synthesized.RunAsUser = new(int64)
  155. *synthesized.RunAsUser = *pod.Spec.SecurityContext.RunAsUser
  156. }
  157. if pod.Spec.SecurityContext.RunAsNonRoot != nil {
  158. synthesized.RunAsNonRoot = new(bool)
  159. *synthesized.RunAsNonRoot = *pod.Spec.SecurityContext.RunAsNonRoot
  160. }
  161. return synthesized
  162. }