util_test.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. /*
  2. Copyright 2018 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 podsecuritypolicy
  14. import (
  15. "fmt"
  16. "reflect"
  17. "testing"
  18. "github.com/stretchr/testify/assert"
  19. "k8s.io/apimachinery/pkg/util/diff"
  20. utilfeature "k8s.io/apiserver/pkg/util/feature"
  21. featuregatetesting "k8s.io/component-base/featuregate/testing"
  22. api "k8s.io/kubernetes/pkg/apis/core"
  23. "k8s.io/kubernetes/pkg/apis/policy"
  24. "k8s.io/kubernetes/pkg/features"
  25. )
  26. func TestDropAllowedProcMountTypes(t *testing.T) {
  27. allowedProcMountTypes := []api.ProcMountType{api.UnmaskedProcMount}
  28. scWithoutAllowedProcMountTypes := func() *policy.PodSecurityPolicySpec {
  29. return &policy.PodSecurityPolicySpec{}
  30. }
  31. scWithAllowedProcMountTypes := func() *policy.PodSecurityPolicySpec {
  32. return &policy.PodSecurityPolicySpec{
  33. AllowedProcMountTypes: allowedProcMountTypes,
  34. }
  35. }
  36. scInfo := []struct {
  37. description string
  38. hasAllowedProcMountTypes bool
  39. sc func() *policy.PodSecurityPolicySpec
  40. }{
  41. {
  42. description: "PodSecurityPolicySpec Without AllowedProcMountTypes",
  43. hasAllowedProcMountTypes: false,
  44. sc: scWithoutAllowedProcMountTypes,
  45. },
  46. {
  47. description: "PodSecurityPolicySpec With AllowedProcMountTypes",
  48. hasAllowedProcMountTypes: true,
  49. sc: scWithAllowedProcMountTypes,
  50. },
  51. {
  52. description: "is nil",
  53. hasAllowedProcMountTypes: false,
  54. sc: func() *policy.PodSecurityPolicySpec { return nil },
  55. },
  56. }
  57. for _, enabled := range []bool{true, false} {
  58. for _, oldPSPSpecInfo := range scInfo {
  59. for _, newPSPSpecInfo := range scInfo {
  60. oldPSPSpecHasAllowedProcMountTypes, oldPSPSpec := oldPSPSpecInfo.hasAllowedProcMountTypes, oldPSPSpecInfo.sc()
  61. newPSPSpecHasAllowedProcMountTypes, newPSPSpec := newPSPSpecInfo.hasAllowedProcMountTypes, newPSPSpecInfo.sc()
  62. if newPSPSpec == nil {
  63. continue
  64. }
  65. t.Run(fmt.Sprintf("feature enabled=%v, old PodSecurityPolicySpec %v, new PodSecurityPolicySpec %v", enabled, oldPSPSpecInfo.description, newPSPSpecInfo.description), func(t *testing.T) {
  66. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ProcMountType, enabled)()
  67. DropDisabledFields(newPSPSpec, oldPSPSpec)
  68. // old PodSecurityPolicySpec should never be changed
  69. if !reflect.DeepEqual(oldPSPSpec, oldPSPSpecInfo.sc()) {
  70. t.Errorf("old PodSecurityPolicySpec changed: %v", diff.ObjectReflectDiff(oldPSPSpec, oldPSPSpecInfo.sc()))
  71. }
  72. switch {
  73. case enabled || oldPSPSpecHasAllowedProcMountTypes:
  74. // new PodSecurityPolicySpec should not be changed if the feature is enabled, or if the old PodSecurityPolicySpec had AllowedProcMountTypes
  75. if !reflect.DeepEqual(newPSPSpec, newPSPSpecInfo.sc()) {
  76. t.Errorf("new PodSecurityPolicySpec changed: %v", diff.ObjectReflectDiff(newPSPSpec, newPSPSpecInfo.sc()))
  77. }
  78. case newPSPSpecHasAllowedProcMountTypes:
  79. // new PodSecurityPolicySpec should be changed
  80. if reflect.DeepEqual(newPSPSpec, newPSPSpecInfo.sc()) {
  81. t.Errorf("new PodSecurityPolicySpec was not changed")
  82. }
  83. // new PodSecurityPolicySpec should not have AllowedProcMountTypes
  84. if !reflect.DeepEqual(newPSPSpec, scWithoutAllowedProcMountTypes()) {
  85. t.Errorf("new PodSecurityPolicySpec had PodSecurityPolicySpecAllowedProcMountTypes: %v", diff.ObjectReflectDiff(newPSPSpec, scWithoutAllowedProcMountTypes()))
  86. }
  87. default:
  88. // new PodSecurityPolicySpec should not need to be changed
  89. if !reflect.DeepEqual(newPSPSpec, newPSPSpecInfo.sc()) {
  90. t.Errorf("new PodSecurityPolicySpec changed: %v", diff.ObjectReflectDiff(newPSPSpec, newPSPSpecInfo.sc()))
  91. }
  92. }
  93. })
  94. }
  95. }
  96. }
  97. }
  98. func TestDropRunAsGroup(t *testing.T) {
  99. group := func() *policy.RunAsGroupStrategyOptions {
  100. return &policy.RunAsGroupStrategyOptions{}
  101. }
  102. scWithoutRunAsGroup := func() *policy.PodSecurityPolicySpec {
  103. return &policy.PodSecurityPolicySpec{}
  104. }
  105. scWithRunAsGroup := func() *policy.PodSecurityPolicySpec {
  106. return &policy.PodSecurityPolicySpec{
  107. RunAsGroup: group(),
  108. }
  109. }
  110. scInfo := []struct {
  111. description string
  112. hasRunAsGroup bool
  113. sc func() *policy.PodSecurityPolicySpec
  114. }{
  115. {
  116. description: "PodSecurityPolicySpec Without RunAsGroup",
  117. hasRunAsGroup: false,
  118. sc: scWithoutRunAsGroup,
  119. },
  120. {
  121. description: "PodSecurityPolicySpec With RunAsGroup",
  122. hasRunAsGroup: true,
  123. sc: scWithRunAsGroup,
  124. },
  125. {
  126. description: "is nil",
  127. hasRunAsGroup: false,
  128. sc: func() *policy.PodSecurityPolicySpec { return nil },
  129. },
  130. }
  131. for _, enabled := range []bool{true, false} {
  132. for _, oldPSPSpecInfo := range scInfo {
  133. for _, newPSPSpecInfo := range scInfo {
  134. oldPSPSpecHasRunAsGroup, oldPSPSpec := oldPSPSpecInfo.hasRunAsGroup, oldPSPSpecInfo.sc()
  135. newPSPSpecHasRunAsGroup, newPSPSpec := newPSPSpecInfo.hasRunAsGroup, newPSPSpecInfo.sc()
  136. if newPSPSpec == nil {
  137. continue
  138. }
  139. t.Run(fmt.Sprintf("feature enabled=%v, old PodSecurityPolicySpec %v, new PodSecurityPolicySpec %v", enabled, oldPSPSpecInfo.description, newPSPSpecInfo.description), func(t *testing.T) {
  140. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.RunAsGroup, enabled)()
  141. DropDisabledFields(newPSPSpec, oldPSPSpec)
  142. // old PodSecurityPolicySpec should never be changed
  143. if !reflect.DeepEqual(oldPSPSpec, oldPSPSpecInfo.sc()) {
  144. t.Errorf("old PodSecurityPolicySpec changed: %v", diff.ObjectReflectDiff(oldPSPSpec, oldPSPSpecInfo.sc()))
  145. }
  146. switch {
  147. case enabled || oldPSPSpecHasRunAsGroup:
  148. // new PodSecurityPolicySpec should not be changed if the feature is enabled, or if the old PodSecurityPolicySpec had RunAsGroup
  149. if !reflect.DeepEqual(newPSPSpec, newPSPSpecInfo.sc()) {
  150. t.Errorf("new PodSecurityPolicySpec changed: %v", diff.ObjectReflectDiff(newPSPSpec, newPSPSpecInfo.sc()))
  151. }
  152. case newPSPSpecHasRunAsGroup:
  153. // new PodSecurityPolicySpec should be changed
  154. if reflect.DeepEqual(newPSPSpec, newPSPSpecInfo.sc()) {
  155. t.Errorf("new PodSecurityPolicySpec was not changed")
  156. }
  157. // new PodSecurityPolicySpec should not have RunAsGroup
  158. if !reflect.DeepEqual(newPSPSpec, scWithoutRunAsGroup()) {
  159. t.Errorf("new PodSecurityPolicySpec had RunAsGroup: %v", diff.ObjectReflectDiff(newPSPSpec, scWithoutRunAsGroup()))
  160. }
  161. default:
  162. // new PodSecurityPolicySpec should not need to be changed
  163. if !reflect.DeepEqual(newPSPSpec, newPSPSpecInfo.sc()) {
  164. t.Errorf("new PodSecurityPolicySpec changed: %v", diff.ObjectReflectDiff(newPSPSpec, newPSPSpecInfo.sc()))
  165. }
  166. }
  167. })
  168. }
  169. }
  170. }
  171. }
  172. func TestDropSysctls(t *testing.T) {
  173. scWithSysctls := func() *policy.PodSecurityPolicySpec {
  174. return &policy.PodSecurityPolicySpec{
  175. AllowedUnsafeSysctls: []string{"foo/*"},
  176. ForbiddenSysctls: []string{"bar.*"},
  177. }
  178. }
  179. scWithOneSysctls := func() *policy.PodSecurityPolicySpec {
  180. return &policy.PodSecurityPolicySpec{
  181. AllowedUnsafeSysctls: []string{"foo/*"},
  182. }
  183. }
  184. scWithoutSysctls := func() *policy.PodSecurityPolicySpec {
  185. return &policy.PodSecurityPolicySpec{}
  186. }
  187. scInfo := []struct {
  188. description string
  189. hasSysctls bool
  190. sc func() *policy.PodSecurityPolicySpec
  191. }{
  192. {
  193. description: "has Sysctls",
  194. hasSysctls: true,
  195. sc: scWithSysctls,
  196. },
  197. {
  198. description: "has one Sysctl",
  199. hasSysctls: true,
  200. sc: scWithOneSysctls,
  201. },
  202. {
  203. description: "does not have Sysctls",
  204. hasSysctls: false,
  205. sc: scWithoutSysctls,
  206. },
  207. {
  208. description: "is nil",
  209. hasSysctls: false,
  210. sc: func() *policy.PodSecurityPolicySpec { return nil },
  211. },
  212. }
  213. for _, enabled := range []bool{true, false} {
  214. for _, oldPSPSpecInfo := range scInfo {
  215. for _, newPSPSpecInfo := range scInfo {
  216. oldPSPSpecHasSysctls, oldPSPSpec := oldPSPSpecInfo.hasSysctls, oldPSPSpecInfo.sc()
  217. newPSPSpecHasSysctls, newPSPSpec := newPSPSpecInfo.hasSysctls, newPSPSpecInfo.sc()
  218. if newPSPSpec == nil {
  219. continue
  220. }
  221. t.Run(fmt.Sprintf("feature enabled=%v, old PodSecurityPolicySpec %v, new PodSecurityPolicySpec %v", enabled, oldPSPSpecInfo.description, newPSPSpecInfo.description), func(t *testing.T) {
  222. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.Sysctls, enabled)()
  223. DropDisabledFields(newPSPSpec, oldPSPSpec)
  224. // old PodSecurityPolicySpec should never be changed
  225. if !reflect.DeepEqual(oldPSPSpec, oldPSPSpecInfo.sc()) {
  226. t.Errorf("old PodSecurityPolicySpec changed: %v", diff.ObjectReflectDiff(oldPSPSpec, oldPSPSpecInfo.sc()))
  227. }
  228. switch {
  229. case enabled || oldPSPSpecHasSysctls:
  230. // new PodSecurityPolicySpec should not be changed if the feature is enabled, or if the old PodSecurityPolicySpec had Sysctls
  231. if !reflect.DeepEqual(newPSPSpec, newPSPSpecInfo.sc()) {
  232. t.Errorf("new PodSecurityPolicySpec changed: %v", diff.ObjectReflectDiff(newPSPSpec, newPSPSpecInfo.sc()))
  233. }
  234. case newPSPSpecHasSysctls:
  235. // new PodSecurityPolicySpec should be changed
  236. if reflect.DeepEqual(newPSPSpec, newPSPSpecInfo.sc()) {
  237. t.Errorf("new PodSecurityPolicySpec was not changed")
  238. }
  239. // new PodSecurityPolicySpec should not have Sysctls
  240. if !reflect.DeepEqual(newPSPSpec, scWithoutSysctls()) {
  241. t.Errorf("new PodSecurityPolicySpec had Sysctls: %v", diff.ObjectReflectDiff(newPSPSpec, scWithoutSysctls()))
  242. }
  243. default:
  244. // new PodSecurityPolicySpec should not need to be changed
  245. if !reflect.DeepEqual(newPSPSpec, newPSPSpecInfo.sc()) {
  246. t.Errorf("new PodSecurityPolicySpec changed: %v", diff.ObjectReflectDiff(newPSPSpec, newPSPSpecInfo.sc()))
  247. }
  248. }
  249. })
  250. }
  251. }
  252. }
  253. }
  254. func TestDropRuntimeClass(t *testing.T) {
  255. type testcase struct {
  256. name string
  257. featureEnabled bool
  258. pspSpec, oldPSPSpec *policy.PodSecurityPolicySpec
  259. expectRuntimeClass bool
  260. }
  261. tests := []testcase{}
  262. pspGenerator := func(withRuntimeClass bool) *policy.PodSecurityPolicySpec {
  263. psp := &policy.PodSecurityPolicySpec{}
  264. if withRuntimeClass {
  265. psp.RuntimeClass = &policy.RuntimeClassStrategyOptions{
  266. AllowedRuntimeClassNames: []string{policy.AllowAllRuntimeClassNames},
  267. }
  268. }
  269. return psp
  270. }
  271. for _, enabled := range []bool{true, false} {
  272. for _, hasRuntimeClass := range []bool{true, false} {
  273. tests = append(tests, testcase{
  274. name: fmt.Sprintf("create feature:%t hasRC:%t", enabled, hasRuntimeClass),
  275. featureEnabled: enabled,
  276. pspSpec: pspGenerator(hasRuntimeClass),
  277. expectRuntimeClass: enabled && hasRuntimeClass,
  278. })
  279. for _, hadRuntimeClass := range []bool{true, false} {
  280. tests = append(tests, testcase{
  281. name: fmt.Sprintf("update feature:%t hasRC:%t hadRC:%t", enabled, hasRuntimeClass, hadRuntimeClass),
  282. featureEnabled: enabled,
  283. pspSpec: pspGenerator(hasRuntimeClass),
  284. oldPSPSpec: pspGenerator(hadRuntimeClass),
  285. expectRuntimeClass: hasRuntimeClass && (enabled || hadRuntimeClass),
  286. })
  287. }
  288. }
  289. }
  290. for _, test := range tests {
  291. t.Run(test.name, func(t *testing.T) {
  292. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.RuntimeClass, test.featureEnabled)()
  293. DropDisabledFields(test.pspSpec, test.oldPSPSpec)
  294. if test.expectRuntimeClass {
  295. assert.NotNil(t, test.pspSpec.RuntimeClass)
  296. } else {
  297. assert.Nil(t, test.pspSpec.RuntimeClass)
  298. }
  299. })
  300. }
  301. }