security_context.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /*
  2. Copyright 2016 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 dockershim
  14. import (
  15. "fmt"
  16. "strconv"
  17. "strings"
  18. "github.com/blang/semver"
  19. dockercontainer "github.com/docker/docker/api/types/container"
  20. runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
  21. knetwork "k8s.io/kubernetes/pkg/kubelet/dockershim/network"
  22. )
  23. // applySandboxSecurityContext updates docker sandbox options according to security context.
  24. func applySandboxSecurityContext(lc *runtimeapi.LinuxPodSandboxConfig, config *dockercontainer.Config, hc *dockercontainer.HostConfig, network *knetwork.PluginManager, separator rune) error {
  25. if lc == nil {
  26. return nil
  27. }
  28. var sc *runtimeapi.LinuxContainerSecurityContext
  29. if lc.SecurityContext != nil {
  30. sc = &runtimeapi.LinuxContainerSecurityContext{
  31. SupplementalGroups: lc.SecurityContext.SupplementalGroups,
  32. RunAsUser: lc.SecurityContext.RunAsUser,
  33. RunAsGroup: lc.SecurityContext.RunAsGroup,
  34. ReadonlyRootfs: lc.SecurityContext.ReadonlyRootfs,
  35. SelinuxOptions: lc.SecurityContext.SelinuxOptions,
  36. NamespaceOptions: lc.SecurityContext.NamespaceOptions,
  37. }
  38. }
  39. err := modifyContainerConfig(sc, config)
  40. if err != nil {
  41. return err
  42. }
  43. if err := modifyHostConfig(sc, hc, separator); err != nil {
  44. return err
  45. }
  46. modifySandboxNamespaceOptions(sc.GetNamespaceOptions(), hc, network)
  47. return nil
  48. }
  49. // applyContainerSecurityContext updates docker container options according to security context.
  50. func applyContainerSecurityContext(lc *runtimeapi.LinuxContainerConfig, podSandboxID string, config *dockercontainer.Config, hc *dockercontainer.HostConfig, separator rune) error {
  51. if lc == nil {
  52. return nil
  53. }
  54. err := modifyContainerConfig(lc.SecurityContext, config)
  55. if err != nil {
  56. return err
  57. }
  58. if err := modifyHostConfig(lc.SecurityContext, hc, separator); err != nil {
  59. return err
  60. }
  61. modifyContainerNamespaceOptions(lc.SecurityContext.GetNamespaceOptions(), podSandboxID, hc)
  62. return nil
  63. }
  64. // modifyContainerConfig applies container security context config to dockercontainer.Config.
  65. func modifyContainerConfig(sc *runtimeapi.LinuxContainerSecurityContext, config *dockercontainer.Config) error {
  66. if sc == nil {
  67. return nil
  68. }
  69. if sc.RunAsUser != nil {
  70. config.User = strconv.FormatInt(sc.GetRunAsUser().Value, 10)
  71. }
  72. if sc.RunAsUsername != "" {
  73. config.User = sc.RunAsUsername
  74. }
  75. user := config.User
  76. if sc.RunAsGroup != nil {
  77. if user == "" {
  78. return fmt.Errorf("runAsGroup is specified without a runAsUser.")
  79. }
  80. user = fmt.Sprintf("%s:%d", config.User, sc.GetRunAsGroup().Value)
  81. }
  82. config.User = user
  83. return nil
  84. }
  85. // modifyHostConfig applies security context config to dockercontainer.HostConfig.
  86. func modifyHostConfig(sc *runtimeapi.LinuxContainerSecurityContext, hostConfig *dockercontainer.HostConfig, separator rune) error {
  87. if sc == nil {
  88. return nil
  89. }
  90. // Apply supplemental groups.
  91. for _, group := range sc.SupplementalGroups {
  92. hostConfig.GroupAdd = append(hostConfig.GroupAdd, strconv.FormatInt(group, 10))
  93. }
  94. // Apply security context for the container.
  95. hostConfig.Privileged = sc.Privileged
  96. hostConfig.ReadonlyRootfs = sc.ReadonlyRootfs
  97. if sc.Capabilities != nil {
  98. hostConfig.CapAdd = sc.GetCapabilities().AddCapabilities
  99. hostConfig.CapDrop = sc.GetCapabilities().DropCapabilities
  100. }
  101. if sc.SelinuxOptions != nil {
  102. hostConfig.SecurityOpt = addSELinuxOptions(
  103. hostConfig.SecurityOpt,
  104. sc.SelinuxOptions,
  105. separator,
  106. )
  107. }
  108. // Apply apparmor options.
  109. apparmorSecurityOpts, err := getApparmorSecurityOpts(sc, separator)
  110. if err != nil {
  111. return fmt.Errorf("failed to generate apparmor security options: %v", err)
  112. }
  113. hostConfig.SecurityOpt = append(hostConfig.SecurityOpt, apparmorSecurityOpts...)
  114. if sc.NoNewPrivs {
  115. hostConfig.SecurityOpt = append(hostConfig.SecurityOpt, "no-new-privileges")
  116. }
  117. if !hostConfig.Privileged {
  118. hostConfig.MaskedPaths = sc.MaskedPaths
  119. hostConfig.ReadonlyPaths = sc.ReadonlyPaths
  120. }
  121. return nil
  122. }
  123. // modifySandboxNamespaceOptions apply namespace options for sandbox
  124. func modifySandboxNamespaceOptions(nsOpts *runtimeapi.NamespaceOption, hostConfig *dockercontainer.HostConfig, network *knetwork.PluginManager) {
  125. // The sandbox's PID namespace is the one that's shared, so CONTAINER and POD are equivalent for it
  126. modifyCommonNamespaceOptions(nsOpts, hostConfig)
  127. modifyHostOptionsForSandbox(nsOpts, network, hostConfig)
  128. }
  129. // modifyContainerNamespaceOptions apply namespace options for container
  130. func modifyContainerNamespaceOptions(nsOpts *runtimeapi.NamespaceOption, podSandboxID string, hostConfig *dockercontainer.HostConfig) {
  131. if nsOpts.GetPid() == runtimeapi.NamespaceMode_POD {
  132. hostConfig.PidMode = dockercontainer.PidMode(fmt.Sprintf("container:%v", podSandboxID))
  133. }
  134. modifyCommonNamespaceOptions(nsOpts, hostConfig)
  135. modifyHostOptionsForContainer(nsOpts, podSandboxID, hostConfig)
  136. }
  137. // modifyCommonNamespaceOptions apply common namespace options for sandbox and container
  138. func modifyCommonNamespaceOptions(nsOpts *runtimeapi.NamespaceOption, hostConfig *dockercontainer.HostConfig) {
  139. if nsOpts.GetPid() == runtimeapi.NamespaceMode_NODE {
  140. hostConfig.PidMode = namespaceModeHost
  141. }
  142. }
  143. // modifyHostOptionsForSandbox applies NetworkMode/UTSMode to sandbox's dockercontainer.HostConfig.
  144. func modifyHostOptionsForSandbox(nsOpts *runtimeapi.NamespaceOption, network *knetwork.PluginManager, hc *dockercontainer.HostConfig) {
  145. if nsOpts.GetIpc() == runtimeapi.NamespaceMode_NODE {
  146. hc.IpcMode = namespaceModeHost
  147. }
  148. if nsOpts.GetNetwork() == runtimeapi.NamespaceMode_NODE {
  149. hc.NetworkMode = namespaceModeHost
  150. return
  151. }
  152. if network == nil {
  153. hc.NetworkMode = "default"
  154. return
  155. }
  156. switch network.PluginName() {
  157. case "cni":
  158. fallthrough
  159. case "kubenet":
  160. hc.NetworkMode = "none"
  161. default:
  162. hc.NetworkMode = "default"
  163. }
  164. }
  165. // modifyHostOptionsForContainer applies NetworkMode/UTSMode to container's dockercontainer.HostConfig.
  166. func modifyHostOptionsForContainer(nsOpts *runtimeapi.NamespaceOption, podSandboxID string, hc *dockercontainer.HostConfig) {
  167. sandboxNSMode := fmt.Sprintf("container:%v", podSandboxID)
  168. hc.NetworkMode = dockercontainer.NetworkMode(sandboxNSMode)
  169. hc.IpcMode = dockercontainer.IpcMode(sandboxNSMode)
  170. hc.UTSMode = ""
  171. if nsOpts.GetNetwork() == runtimeapi.NamespaceMode_NODE {
  172. hc.UTSMode = namespaceModeHost
  173. }
  174. }
  175. // modifyPIDNamespaceOverrides implements a temporary override for the default PID namespace sharing for Docker:
  176. // 1. Docker engine prior to API Version 1.24 doesn't support attaching to another container's
  177. // PID namespace, and it didn't stabilize until 1.26. This check can be removed when Kubernetes'
  178. // minimum Docker version is at least 1.13.1 (API version 1.26).
  179. // TODO(verb): remove entirely once these two conditions are satisfied
  180. func modifyContainerPIDNamespaceOverrides(version *semver.Version, hc *dockercontainer.HostConfig, podSandboxID string) {
  181. if version.LT(semver.Version{Major: 1, Minor: 26}) && strings.HasPrefix(string(hc.PidMode), "container:") {
  182. hc.PidMode = ""
  183. }
  184. }