util.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  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. "k8s.io/api/core/v1"
  16. )
  17. // HasPrivilegedRequest returns the value of SecurityContext.Privileged, taking into account
  18. // the possibility of nils
  19. func HasPrivilegedRequest(container *v1.Container) bool {
  20. if container.SecurityContext == nil {
  21. return false
  22. }
  23. if container.SecurityContext.Privileged == nil {
  24. return false
  25. }
  26. return *container.SecurityContext.Privileged
  27. }
  28. // HasCapabilitiesRequest returns true if Adds or Drops are defined in the security context
  29. // capabilities, taking into account nils
  30. func HasCapabilitiesRequest(container *v1.Container) bool {
  31. if container.SecurityContext == nil {
  32. return false
  33. }
  34. if container.SecurityContext.Capabilities == nil {
  35. return false
  36. }
  37. return len(container.SecurityContext.Capabilities.Add) > 0 || len(container.SecurityContext.Capabilities.Drop) > 0
  38. }
  39. // DetermineEffectiveSecurityContext returns a synthesized SecurityContext for reading effective configurations
  40. // from the provided pod's and container's security context. Container's fields take precedence in cases where both
  41. // are set
  42. func DetermineEffectiveSecurityContext(pod *v1.Pod, container *v1.Container) *v1.SecurityContext {
  43. effectiveSc := securityContextFromPodSecurityContext(pod)
  44. containerSc := container.SecurityContext
  45. if effectiveSc == nil && containerSc == nil {
  46. return &v1.SecurityContext{}
  47. }
  48. if effectiveSc != nil && containerSc == nil {
  49. return effectiveSc
  50. }
  51. if effectiveSc == nil && containerSc != nil {
  52. return containerSc
  53. }
  54. if containerSc.SELinuxOptions != nil {
  55. effectiveSc.SELinuxOptions = new(v1.SELinuxOptions)
  56. *effectiveSc.SELinuxOptions = *containerSc.SELinuxOptions
  57. }
  58. if containerSc.WindowsOptions != nil {
  59. // only override fields that are set at the container level, not the whole thing
  60. if effectiveSc.WindowsOptions == nil {
  61. effectiveSc.WindowsOptions = &v1.WindowsSecurityContextOptions{}
  62. }
  63. if containerSc.WindowsOptions.GMSACredentialSpecName != nil || containerSc.WindowsOptions.GMSACredentialSpec != nil {
  64. // both GMSA fields go hand in hand
  65. effectiveSc.WindowsOptions.GMSACredentialSpecName = containerSc.WindowsOptions.GMSACredentialSpecName
  66. effectiveSc.WindowsOptions.GMSACredentialSpec = containerSc.WindowsOptions.GMSACredentialSpec
  67. }
  68. if containerSc.WindowsOptions.RunAsUserName != nil {
  69. effectiveSc.WindowsOptions.RunAsUserName = containerSc.WindowsOptions.RunAsUserName
  70. }
  71. }
  72. if containerSc.Capabilities != nil {
  73. effectiveSc.Capabilities = new(v1.Capabilities)
  74. *effectiveSc.Capabilities = *containerSc.Capabilities
  75. }
  76. if containerSc.Privileged != nil {
  77. effectiveSc.Privileged = new(bool)
  78. *effectiveSc.Privileged = *containerSc.Privileged
  79. }
  80. if containerSc.RunAsUser != nil {
  81. effectiveSc.RunAsUser = new(int64)
  82. *effectiveSc.RunAsUser = *containerSc.RunAsUser
  83. }
  84. if containerSc.RunAsGroup != nil {
  85. effectiveSc.RunAsGroup = new(int64)
  86. *effectiveSc.RunAsGroup = *containerSc.RunAsGroup
  87. }
  88. if containerSc.RunAsNonRoot != nil {
  89. effectiveSc.RunAsNonRoot = new(bool)
  90. *effectiveSc.RunAsNonRoot = *containerSc.RunAsNonRoot
  91. }
  92. if containerSc.ReadOnlyRootFilesystem != nil {
  93. effectiveSc.ReadOnlyRootFilesystem = new(bool)
  94. *effectiveSc.ReadOnlyRootFilesystem = *containerSc.ReadOnlyRootFilesystem
  95. }
  96. if containerSc.AllowPrivilegeEscalation != nil {
  97. effectiveSc.AllowPrivilegeEscalation = new(bool)
  98. *effectiveSc.AllowPrivilegeEscalation = *containerSc.AllowPrivilegeEscalation
  99. }
  100. if containerSc.ProcMount != nil {
  101. effectiveSc.ProcMount = new(v1.ProcMountType)
  102. *effectiveSc.ProcMount = *containerSc.ProcMount
  103. }
  104. return effectiveSc
  105. }
  106. func securityContextFromPodSecurityContext(pod *v1.Pod) *v1.SecurityContext {
  107. if pod.Spec.SecurityContext == nil {
  108. return nil
  109. }
  110. synthesized := &v1.SecurityContext{}
  111. if pod.Spec.SecurityContext.SELinuxOptions != nil {
  112. synthesized.SELinuxOptions = &v1.SELinuxOptions{}
  113. *synthesized.SELinuxOptions = *pod.Spec.SecurityContext.SELinuxOptions
  114. }
  115. if pod.Spec.SecurityContext.WindowsOptions != nil {
  116. synthesized.WindowsOptions = &v1.WindowsSecurityContextOptions{}
  117. *synthesized.WindowsOptions = *pod.Spec.SecurityContext.WindowsOptions
  118. }
  119. if pod.Spec.SecurityContext.RunAsUser != nil {
  120. synthesized.RunAsUser = new(int64)
  121. *synthesized.RunAsUser = *pod.Spec.SecurityContext.RunAsUser
  122. }
  123. if pod.Spec.SecurityContext.RunAsGroup != nil {
  124. synthesized.RunAsGroup = new(int64)
  125. *synthesized.RunAsGroup = *pod.Spec.SecurityContext.RunAsGroup
  126. }
  127. if pod.Spec.SecurityContext.RunAsNonRoot != nil {
  128. synthesized.RunAsNonRoot = new(bool)
  129. *synthesized.RunAsNonRoot = *pod.Spec.SecurityContext.RunAsNonRoot
  130. }
  131. return synthesized
  132. }
  133. // AddNoNewPrivileges returns if we should add the no_new_privs option.
  134. func AddNoNewPrivileges(sc *v1.SecurityContext) bool {
  135. if sc == nil {
  136. return false
  137. }
  138. // handle the case where the user did not set the default and did not explicitly set allowPrivilegeEscalation
  139. if sc.AllowPrivilegeEscalation == nil {
  140. return false
  141. }
  142. // handle the case where defaultAllowPrivilegeEscalation is false or the user explicitly set allowPrivilegeEscalation to true/false
  143. return !*sc.AllowPrivilegeEscalation
  144. }
  145. var (
  146. // These *must* be kept in sync with moby/moby.
  147. // https://github.com/moby/moby/blob/master/oci/defaults.go#L116-L134
  148. // @jessfraz will watch changes to those files upstream.
  149. defaultMaskedPaths = []string{
  150. "/proc/acpi",
  151. "/proc/kcore",
  152. "/proc/keys",
  153. "/proc/latency_stats",
  154. "/proc/timer_list",
  155. "/proc/timer_stats",
  156. "/proc/sched_debug",
  157. "/proc/scsi",
  158. "/sys/firmware",
  159. }
  160. defaultReadonlyPaths = []string{
  161. "/proc/asound",
  162. "/proc/bus",
  163. "/proc/fs",
  164. "/proc/irq",
  165. "/proc/sys",
  166. "/proc/sysrq-trigger",
  167. }
  168. )
  169. // ConvertToRuntimeMaskedPaths converts the ProcMountType to the specified or default
  170. // masked paths.
  171. func ConvertToRuntimeMaskedPaths(opt *v1.ProcMountType) []string {
  172. if opt != nil && *opt == v1.UnmaskedProcMount {
  173. // Unmasked proc mount should have no paths set as masked.
  174. return []string{}
  175. }
  176. // Otherwise, add the default masked paths to the runtime security context.
  177. return defaultMaskedPaths
  178. }
  179. // ConvertToRuntimeReadonlyPaths converts the ProcMountType to the specified or default
  180. // readonly paths.
  181. func ConvertToRuntimeReadonlyPaths(opt *v1.ProcMountType) []string {
  182. if opt != nil && *opt == v1.UnmaskedProcMount {
  183. // Unmasked proc mount should have no paths set as readonly.
  184. return []string{}
  185. }
  186. // Otherwise, add the default readonly paths to the runtime security context.
  187. return defaultReadonlyPaths
  188. }