accessors_test.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769
  1. /*
  2. Copyright 2017 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. "reflect"
  16. "testing"
  17. "k8s.io/apimachinery/pkg/util/diff"
  18. api "k8s.io/kubernetes/pkg/apis/core"
  19. )
  20. func TestPodSecurityContextAccessor(t *testing.T) {
  21. fsGroup := int64(2)
  22. runAsUser := int64(1)
  23. runAsGroup := int64(1)
  24. runAsNonRoot := true
  25. testcases := []*api.PodSecurityContext{
  26. nil,
  27. {},
  28. {FSGroup: &fsGroup},
  29. {HostIPC: true},
  30. {HostNetwork: true},
  31. {HostPID: true},
  32. {RunAsNonRoot: &runAsNonRoot},
  33. {RunAsUser: &runAsUser},
  34. {RunAsGroup: &runAsGroup},
  35. {SELinuxOptions: &api.SELinuxOptions{User: "bob"}},
  36. {SupplementalGroups: []int64{1, 2, 3}},
  37. }
  38. for i, tc := range testcases {
  39. expected := tc
  40. if expected == nil {
  41. expected = &api.PodSecurityContext{}
  42. }
  43. a := NewPodSecurityContextAccessor(tc)
  44. if v := a.FSGroup(); !reflect.DeepEqual(expected.FSGroup, v) {
  45. t.Errorf("%d: expected %#v, got %#v", i, expected.FSGroup, v)
  46. }
  47. if v := a.HostIPC(); !reflect.DeepEqual(expected.HostIPC, v) {
  48. t.Errorf("%d: expected %#v, got %#v", i, expected.HostIPC, v)
  49. }
  50. if v := a.HostNetwork(); !reflect.DeepEqual(expected.HostNetwork, v) {
  51. t.Errorf("%d: expected %#v, got %#v", i, expected.HostNetwork, v)
  52. }
  53. if v := a.HostPID(); !reflect.DeepEqual(expected.HostPID, v) {
  54. t.Errorf("%d: expected %#v, got %#v", i, expected.HostPID, v)
  55. }
  56. if v := a.RunAsNonRoot(); !reflect.DeepEqual(expected.RunAsNonRoot, v) {
  57. t.Errorf("%d: expected %#v, got %#v", i, expected.RunAsNonRoot, v)
  58. }
  59. if v := a.RunAsUser(); !reflect.DeepEqual(expected.RunAsUser, v) {
  60. t.Errorf("%d: expected %#v, got %#v", i, expected.RunAsUser, v)
  61. }
  62. if v := a.RunAsGroup(); !reflect.DeepEqual(expected.RunAsGroup, v) {
  63. t.Errorf("%d: expected %#v, got %#v", i, expected.RunAsGroup, v)
  64. }
  65. if v := a.SELinuxOptions(); !reflect.DeepEqual(expected.SELinuxOptions, v) {
  66. t.Errorf("%d: expected %#v, got %#v", i, expected.SELinuxOptions, v)
  67. }
  68. if v := a.SupplementalGroups(); !reflect.DeepEqual(expected.SupplementalGroups, v) {
  69. t.Errorf("%d: expected %#v, got %#v", i, expected.SupplementalGroups, v)
  70. }
  71. }
  72. }
  73. func TestPodSecurityContextMutator(t *testing.T) {
  74. testcases := map[string]struct {
  75. newSC func() *api.PodSecurityContext
  76. }{
  77. "nil": {
  78. newSC: func() *api.PodSecurityContext { return nil },
  79. },
  80. "zero": {
  81. newSC: func() *api.PodSecurityContext { return &api.PodSecurityContext{} },
  82. },
  83. "populated": {
  84. newSC: func() *api.PodSecurityContext {
  85. return &api.PodSecurityContext{
  86. HostNetwork: true,
  87. HostIPC: true,
  88. HostPID: true,
  89. SELinuxOptions: &api.SELinuxOptions{},
  90. RunAsUser: nil,
  91. RunAsGroup: nil,
  92. RunAsNonRoot: nil,
  93. SupplementalGroups: nil,
  94. FSGroup: nil,
  95. }
  96. },
  97. },
  98. }
  99. nonNilSC := func(sc *api.PodSecurityContext) *api.PodSecurityContext {
  100. if sc == nil {
  101. return &api.PodSecurityContext{}
  102. }
  103. return sc
  104. }
  105. for k, tc := range testcases {
  106. {
  107. sc := tc.newSC()
  108. originalSC := tc.newSC()
  109. m := NewPodSecurityContextMutator(sc)
  110. // no-op sets should not modify the object
  111. m.SetFSGroup(m.FSGroup())
  112. m.SetHostNetwork(m.HostNetwork())
  113. m.SetHostIPC(m.HostIPC())
  114. m.SetHostPID(m.HostPID())
  115. m.SetRunAsNonRoot(m.RunAsNonRoot())
  116. m.SetRunAsUser(m.RunAsUser())
  117. m.SetRunAsGroup(m.RunAsGroup())
  118. m.SetSELinuxOptions(m.SELinuxOptions())
  119. m.SetSupplementalGroups(m.SupplementalGroups())
  120. if !reflect.DeepEqual(sc, originalSC) {
  121. t.Errorf("%s: unexpected mutation: %#v, %#v", k, sc, originalSC)
  122. }
  123. if !reflect.DeepEqual(m.PodSecurityContext(), originalSC) {
  124. t.Errorf("%s: unexpected mutation: %#v, %#v", k, m.PodSecurityContext(), originalSC)
  125. }
  126. }
  127. // FSGroup
  128. {
  129. modifiedSC := nonNilSC(tc.newSC())
  130. m := NewPodSecurityContextMutator(tc.newSC())
  131. i := int64(1123)
  132. modifiedSC.FSGroup = &i
  133. m.SetFSGroup(&i)
  134. if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) {
  135. t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext()))
  136. continue
  137. }
  138. }
  139. // HostNetwork
  140. {
  141. modifiedSC := nonNilSC(tc.newSC())
  142. m := NewPodSecurityContextMutator(tc.newSC())
  143. modifiedSC.HostNetwork = !modifiedSC.HostNetwork
  144. m.SetHostNetwork(!m.HostNetwork())
  145. if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) {
  146. t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext()))
  147. continue
  148. }
  149. }
  150. // HostIPC
  151. {
  152. modifiedSC := nonNilSC(tc.newSC())
  153. m := NewPodSecurityContextMutator(tc.newSC())
  154. modifiedSC.HostIPC = !modifiedSC.HostIPC
  155. m.SetHostIPC(!m.HostIPC())
  156. if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) {
  157. t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext()))
  158. continue
  159. }
  160. }
  161. // HostPID
  162. {
  163. modifiedSC := nonNilSC(tc.newSC())
  164. m := NewPodSecurityContextMutator(tc.newSC())
  165. modifiedSC.HostPID = !modifiedSC.HostPID
  166. m.SetHostPID(!m.HostPID())
  167. if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) {
  168. t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext()))
  169. continue
  170. }
  171. }
  172. // RunAsNonRoot
  173. {
  174. modifiedSC := nonNilSC(tc.newSC())
  175. m := NewPodSecurityContextMutator(tc.newSC())
  176. b := true
  177. modifiedSC.RunAsNonRoot = &b
  178. m.SetRunAsNonRoot(&b)
  179. if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) {
  180. t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext()))
  181. continue
  182. }
  183. }
  184. // RunAsUser
  185. {
  186. modifiedSC := nonNilSC(tc.newSC())
  187. m := NewPodSecurityContextMutator(tc.newSC())
  188. i := int64(1123)
  189. modifiedSC.RunAsUser = &i
  190. m.SetRunAsUser(&i)
  191. if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) {
  192. t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext()))
  193. continue
  194. }
  195. }
  196. // RunAsGroup
  197. {
  198. modifiedSC := nonNilSC(tc.newSC())
  199. m := NewPodSecurityContextMutator(tc.newSC())
  200. i := int64(1123)
  201. modifiedSC.RunAsGroup = &i
  202. m.SetRunAsGroup(&i)
  203. if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) {
  204. t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext()))
  205. continue
  206. }
  207. }
  208. // SELinuxOptions
  209. {
  210. modifiedSC := nonNilSC(tc.newSC())
  211. m := NewPodSecurityContextMutator(tc.newSC())
  212. modifiedSC.SELinuxOptions = &api.SELinuxOptions{User: "bob"}
  213. m.SetSELinuxOptions(&api.SELinuxOptions{User: "bob"})
  214. if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) {
  215. t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext()))
  216. continue
  217. }
  218. }
  219. // SupplementalGroups
  220. {
  221. modifiedSC := nonNilSC(tc.newSC())
  222. m := NewPodSecurityContextMutator(tc.newSC())
  223. modifiedSC.SupplementalGroups = []int64{1, 1, 2, 3}
  224. m.SetSupplementalGroups([]int64{1, 1, 2, 3})
  225. if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) {
  226. t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext()))
  227. continue
  228. }
  229. }
  230. }
  231. }
  232. func TestContainerSecurityContextAccessor(t *testing.T) {
  233. privileged := true
  234. runAsUser := int64(1)
  235. runAsNonRoot := true
  236. readOnlyRootFilesystem := true
  237. allowPrivilegeEscalation := true
  238. testcases := []*api.SecurityContext{
  239. nil,
  240. {},
  241. {Capabilities: &api.Capabilities{Drop: []api.Capability{"test"}}},
  242. {Privileged: &privileged},
  243. {SELinuxOptions: &api.SELinuxOptions{User: "bob"}},
  244. {RunAsUser: &runAsUser},
  245. {RunAsNonRoot: &runAsNonRoot},
  246. {ReadOnlyRootFilesystem: &readOnlyRootFilesystem},
  247. {AllowPrivilegeEscalation: &allowPrivilegeEscalation},
  248. }
  249. for i, tc := range testcases {
  250. expected := tc
  251. if expected == nil {
  252. expected = &api.SecurityContext{}
  253. }
  254. a := NewContainerSecurityContextAccessor(tc)
  255. if v := a.Capabilities(); !reflect.DeepEqual(expected.Capabilities, v) {
  256. t.Errorf("%d: expected %#v, got %#v", i, expected.Capabilities, v)
  257. }
  258. if v := a.Privileged(); !reflect.DeepEqual(expected.Privileged, v) {
  259. t.Errorf("%d: expected %#v, got %#v", i, expected.Privileged, v)
  260. }
  261. if v := a.RunAsNonRoot(); !reflect.DeepEqual(expected.RunAsNonRoot, v) {
  262. t.Errorf("%d: expected %#v, got %#v", i, expected.RunAsNonRoot, v)
  263. }
  264. if v := a.RunAsUser(); !reflect.DeepEqual(expected.RunAsUser, v) {
  265. t.Errorf("%d: expected %#v, got %#v", i, expected.RunAsUser, v)
  266. }
  267. if v := a.SELinuxOptions(); !reflect.DeepEqual(expected.SELinuxOptions, v) {
  268. t.Errorf("%d: expected %#v, got %#v", i, expected.SELinuxOptions, v)
  269. }
  270. if v := a.ReadOnlyRootFilesystem(); !reflect.DeepEqual(expected.ReadOnlyRootFilesystem, v) {
  271. t.Errorf("%d: expected %#v, got %#v", i, expected.ReadOnlyRootFilesystem, v)
  272. }
  273. if v := a.AllowPrivilegeEscalation(); !reflect.DeepEqual(expected.AllowPrivilegeEscalation, v) {
  274. t.Errorf("%d: expected %#v, got %#v", i, expected.AllowPrivilegeEscalation, v)
  275. }
  276. }
  277. }
  278. func TestContainerSecurityContextMutator(t *testing.T) {
  279. testcases := map[string]struct {
  280. newSC func() *api.SecurityContext
  281. }{
  282. "nil": {
  283. newSC: func() *api.SecurityContext { return nil },
  284. },
  285. "zero": {
  286. newSC: func() *api.SecurityContext { return &api.SecurityContext{} },
  287. },
  288. "populated": {
  289. newSC: func() *api.SecurityContext {
  290. return &api.SecurityContext{
  291. Capabilities: &api.Capabilities{Drop: []api.Capability{"test"}},
  292. SELinuxOptions: &api.SELinuxOptions{},
  293. }
  294. },
  295. },
  296. }
  297. nonNilSC := func(sc *api.SecurityContext) *api.SecurityContext {
  298. if sc == nil {
  299. return &api.SecurityContext{}
  300. }
  301. return sc
  302. }
  303. for k, tc := range testcases {
  304. {
  305. sc := tc.newSC()
  306. originalSC := tc.newSC()
  307. m := NewContainerSecurityContextMutator(sc)
  308. // no-op sets should not modify the object
  309. m.SetAllowPrivilegeEscalation(m.AllowPrivilegeEscalation())
  310. m.SetCapabilities(m.Capabilities())
  311. m.SetPrivileged(m.Privileged())
  312. m.SetReadOnlyRootFilesystem(m.ReadOnlyRootFilesystem())
  313. m.SetRunAsNonRoot(m.RunAsNonRoot())
  314. m.SetRunAsUser(m.RunAsUser())
  315. m.SetSELinuxOptions(m.SELinuxOptions())
  316. if !reflect.DeepEqual(sc, originalSC) {
  317. t.Errorf("%s: unexpected mutation: %#v, %#v", k, sc, originalSC)
  318. }
  319. if !reflect.DeepEqual(m.ContainerSecurityContext(), originalSC) {
  320. t.Errorf("%s: unexpected mutation: %#v, %#v", k, m.ContainerSecurityContext(), originalSC)
  321. }
  322. }
  323. // AllowPrivilegeEscalation
  324. {
  325. modifiedSC := nonNilSC(tc.newSC())
  326. m := NewContainerSecurityContextMutator(tc.newSC())
  327. b := true
  328. modifiedSC.AllowPrivilegeEscalation = &b
  329. m.SetAllowPrivilegeEscalation(&b)
  330. if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
  331. t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
  332. continue
  333. }
  334. }
  335. // Capabilities
  336. {
  337. modifiedSC := nonNilSC(tc.newSC())
  338. m := NewContainerSecurityContextMutator(tc.newSC())
  339. modifiedSC.Capabilities = &api.Capabilities{Drop: []api.Capability{"test2"}}
  340. m.SetCapabilities(&api.Capabilities{Drop: []api.Capability{"test2"}})
  341. if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
  342. t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
  343. continue
  344. }
  345. }
  346. // Privileged
  347. {
  348. modifiedSC := nonNilSC(tc.newSC())
  349. m := NewContainerSecurityContextMutator(tc.newSC())
  350. b := true
  351. modifiedSC.Privileged = &b
  352. m.SetPrivileged(&b)
  353. if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
  354. t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
  355. continue
  356. }
  357. }
  358. // ReadOnlyRootFilesystem
  359. {
  360. modifiedSC := nonNilSC(tc.newSC())
  361. m := NewContainerSecurityContextMutator(tc.newSC())
  362. b := true
  363. modifiedSC.ReadOnlyRootFilesystem = &b
  364. m.SetReadOnlyRootFilesystem(&b)
  365. if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
  366. t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
  367. continue
  368. }
  369. }
  370. // RunAsNonRoot
  371. {
  372. modifiedSC := nonNilSC(tc.newSC())
  373. m := NewContainerSecurityContextMutator(tc.newSC())
  374. b := true
  375. modifiedSC.RunAsNonRoot = &b
  376. m.SetRunAsNonRoot(&b)
  377. if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
  378. t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
  379. continue
  380. }
  381. }
  382. // RunAsUser
  383. {
  384. modifiedSC := nonNilSC(tc.newSC())
  385. m := NewContainerSecurityContextMutator(tc.newSC())
  386. i := int64(1123)
  387. modifiedSC.RunAsUser = &i
  388. m.SetRunAsUser(&i)
  389. if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
  390. t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
  391. continue
  392. }
  393. }
  394. // SELinuxOptions
  395. {
  396. modifiedSC := nonNilSC(tc.newSC())
  397. m := NewContainerSecurityContextMutator(tc.newSC())
  398. modifiedSC.SELinuxOptions = &api.SELinuxOptions{User: "bob"}
  399. m.SetSELinuxOptions(&api.SELinuxOptions{User: "bob"})
  400. if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
  401. t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
  402. continue
  403. }
  404. }
  405. }
  406. }
  407. func TestEffectiveContainerSecurityContextAccessor(t *testing.T) {
  408. privileged := true
  409. runAsUser := int64(1)
  410. runAsUserPod := int64(12)
  411. runAsGroup := int64(1)
  412. runAsGroupPod := int64(12)
  413. runAsNonRoot := true
  414. runAsNonRootPod := false
  415. readOnlyRootFilesystem := true
  416. allowPrivilegeEscalation := true
  417. testcases := []struct {
  418. PodSC *api.PodSecurityContext
  419. SC *api.SecurityContext
  420. Effective *api.SecurityContext
  421. }{
  422. {
  423. PodSC: nil,
  424. SC: nil,
  425. Effective: nil,
  426. },
  427. {
  428. PodSC: &api.PodSecurityContext{},
  429. SC: &api.SecurityContext{},
  430. Effective: &api.SecurityContext{},
  431. },
  432. {
  433. PodSC: &api.PodSecurityContext{
  434. SELinuxOptions: &api.SELinuxOptions{User: "bob"},
  435. RunAsUser: &runAsUser,
  436. RunAsNonRoot: &runAsNonRoot,
  437. },
  438. SC: nil,
  439. Effective: &api.SecurityContext{
  440. SELinuxOptions: &api.SELinuxOptions{User: "bob"},
  441. RunAsUser: &runAsUser,
  442. RunAsNonRoot: &runAsNonRoot,
  443. },
  444. },
  445. {
  446. PodSC: &api.PodSecurityContext{
  447. SELinuxOptions: &api.SELinuxOptions{User: "bob"},
  448. RunAsUser: &runAsUserPod,
  449. RunAsNonRoot: &runAsNonRootPod,
  450. },
  451. SC: &api.SecurityContext{},
  452. Effective: &api.SecurityContext{
  453. SELinuxOptions: &api.SELinuxOptions{User: "bob"},
  454. RunAsUser: &runAsUserPod,
  455. RunAsNonRoot: &runAsNonRootPod,
  456. },
  457. },
  458. {
  459. PodSC: &api.PodSecurityContext{
  460. SELinuxOptions: &api.SELinuxOptions{User: "bob"},
  461. RunAsUser: &runAsUserPod,
  462. RunAsNonRoot: &runAsNonRootPod,
  463. },
  464. SC: &api.SecurityContext{
  465. AllowPrivilegeEscalation: &allowPrivilegeEscalation,
  466. Capabilities: &api.Capabilities{Drop: []api.Capability{"test"}},
  467. Privileged: &privileged,
  468. ReadOnlyRootFilesystem: &readOnlyRootFilesystem,
  469. RunAsUser: &runAsUser,
  470. RunAsNonRoot: &runAsNonRoot,
  471. SELinuxOptions: &api.SELinuxOptions{User: "bob"},
  472. },
  473. Effective: &api.SecurityContext{
  474. AllowPrivilegeEscalation: &allowPrivilegeEscalation,
  475. Capabilities: &api.Capabilities{Drop: []api.Capability{"test"}},
  476. Privileged: &privileged,
  477. ReadOnlyRootFilesystem: &readOnlyRootFilesystem,
  478. RunAsUser: &runAsUser,
  479. RunAsNonRoot: &runAsNonRoot,
  480. SELinuxOptions: &api.SELinuxOptions{User: "bob"},
  481. },
  482. },
  483. {
  484. PodSC: &api.PodSecurityContext{
  485. RunAsGroup: &runAsGroup,
  486. },
  487. SC: nil,
  488. Effective: &api.SecurityContext{
  489. RunAsGroup: &runAsGroup,
  490. },
  491. },
  492. {
  493. PodSC: &api.PodSecurityContext{
  494. RunAsGroup: &runAsGroupPod,
  495. },
  496. SC: &api.SecurityContext{
  497. RunAsGroup: &runAsGroup,
  498. },
  499. Effective: &api.SecurityContext{
  500. RunAsGroup: &runAsGroup,
  501. },
  502. },
  503. }
  504. for i, tc := range testcases {
  505. expected := tc.Effective
  506. if expected == nil {
  507. expected = &api.SecurityContext{}
  508. }
  509. a := NewEffectiveContainerSecurityContextAccessor(
  510. NewPodSecurityContextAccessor(tc.PodSC),
  511. NewContainerSecurityContextMutator(tc.SC),
  512. )
  513. if v := a.Capabilities(); !reflect.DeepEqual(expected.Capabilities, v) {
  514. t.Errorf("%d: expected %#v, got %#v", i, expected.Capabilities, v)
  515. }
  516. if v := a.Privileged(); !reflect.DeepEqual(expected.Privileged, v) {
  517. t.Errorf("%d: expected %#v, got %#v", i, expected.Privileged, v)
  518. }
  519. if v := a.RunAsNonRoot(); !reflect.DeepEqual(expected.RunAsNonRoot, v) {
  520. t.Errorf("%d: expected %#v, got %#v", i, expected.RunAsNonRoot, v)
  521. }
  522. if v := a.RunAsUser(); !reflect.DeepEqual(expected.RunAsUser, v) {
  523. t.Errorf("%d: expected %#v, got %#v", i, expected.RunAsUser, v)
  524. }
  525. if v := a.SELinuxOptions(); !reflect.DeepEqual(expected.SELinuxOptions, v) {
  526. t.Errorf("%d: expected %#v, got %#v", i, expected.SELinuxOptions, v)
  527. }
  528. if v := a.ReadOnlyRootFilesystem(); !reflect.DeepEqual(expected.ReadOnlyRootFilesystem, v) {
  529. t.Errorf("%d: expected %#v, got %#v", i, expected.ReadOnlyRootFilesystem, v)
  530. }
  531. if v := a.AllowPrivilegeEscalation(); !reflect.DeepEqual(expected.AllowPrivilegeEscalation, v) {
  532. t.Errorf("%d: expected %#v, got %#v", i, expected.AllowPrivilegeEscalation, v)
  533. }
  534. }
  535. }
  536. func TestEffectiveContainerSecurityContextMutator(t *testing.T) {
  537. runAsNonRootPod := false
  538. runAsUserPod := int64(12)
  539. testcases := map[string]struct {
  540. newPodSC func() *api.PodSecurityContext
  541. newSC func() *api.SecurityContext
  542. }{
  543. "nil": {
  544. newPodSC: func() *api.PodSecurityContext { return nil },
  545. newSC: func() *api.SecurityContext { return nil },
  546. },
  547. "zero": {
  548. newPodSC: func() *api.PodSecurityContext { return &api.PodSecurityContext{} },
  549. newSC: func() *api.SecurityContext { return &api.SecurityContext{} },
  550. },
  551. "populated pod sc": {
  552. newPodSC: func() *api.PodSecurityContext {
  553. return &api.PodSecurityContext{
  554. SELinuxOptions: &api.SELinuxOptions{User: "poduser"},
  555. RunAsNonRoot: &runAsNonRootPod,
  556. RunAsUser: &runAsUserPod,
  557. }
  558. },
  559. newSC: func() *api.SecurityContext {
  560. return &api.SecurityContext{}
  561. },
  562. },
  563. "populated sc": {
  564. newPodSC: func() *api.PodSecurityContext { return nil },
  565. newSC: func() *api.SecurityContext {
  566. return &api.SecurityContext{
  567. Capabilities: &api.Capabilities{Drop: []api.Capability{"test"}},
  568. SELinuxOptions: &api.SELinuxOptions{},
  569. }
  570. },
  571. },
  572. }
  573. nonNilSC := func(sc *api.SecurityContext) *api.SecurityContext {
  574. if sc == nil {
  575. return &api.SecurityContext{}
  576. }
  577. return sc
  578. }
  579. for k, tc := range testcases {
  580. {
  581. podSC := tc.newPodSC()
  582. sc := tc.newSC()
  583. originalPodSC := tc.newPodSC()
  584. originalSC := tc.newSC()
  585. m := NewEffectiveContainerSecurityContextMutator(
  586. NewPodSecurityContextAccessor(podSC),
  587. NewContainerSecurityContextMutator(sc),
  588. )
  589. // no-op sets should not modify the object
  590. m.SetAllowPrivilegeEscalation(m.AllowPrivilegeEscalation())
  591. m.SetCapabilities(m.Capabilities())
  592. m.SetPrivileged(m.Privileged())
  593. m.SetReadOnlyRootFilesystem(m.ReadOnlyRootFilesystem())
  594. m.SetRunAsNonRoot(m.RunAsNonRoot())
  595. m.SetRunAsUser(m.RunAsUser())
  596. m.SetSELinuxOptions(m.SELinuxOptions())
  597. if !reflect.DeepEqual(podSC, originalPodSC) {
  598. t.Errorf("%s: unexpected mutation: %#v, %#v", k, podSC, originalPodSC)
  599. }
  600. if !reflect.DeepEqual(sc, originalSC) {
  601. t.Errorf("%s: unexpected mutation: %#v, %#v", k, sc, originalSC)
  602. }
  603. if !reflect.DeepEqual(m.ContainerSecurityContext(), originalSC) {
  604. t.Errorf("%s: unexpected mutation: %#v, %#v", k, m.ContainerSecurityContext(), originalSC)
  605. }
  606. }
  607. // AllowPrivilegeEscalation
  608. {
  609. modifiedSC := nonNilSC(tc.newSC())
  610. m := NewEffectiveContainerSecurityContextMutator(
  611. NewPodSecurityContextAccessor(tc.newPodSC()),
  612. NewContainerSecurityContextMutator(tc.newSC()),
  613. )
  614. b := true
  615. modifiedSC.AllowPrivilegeEscalation = &b
  616. m.SetAllowPrivilegeEscalation(&b)
  617. if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
  618. t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
  619. continue
  620. }
  621. }
  622. // Capabilities
  623. {
  624. modifiedSC := nonNilSC(tc.newSC())
  625. m := NewEffectiveContainerSecurityContextMutator(
  626. NewPodSecurityContextAccessor(tc.newPodSC()),
  627. NewContainerSecurityContextMutator(tc.newSC()),
  628. )
  629. modifiedSC.Capabilities = &api.Capabilities{Drop: []api.Capability{"test2"}}
  630. m.SetCapabilities(&api.Capabilities{Drop: []api.Capability{"test2"}})
  631. if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
  632. t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
  633. continue
  634. }
  635. }
  636. // Privileged
  637. {
  638. modifiedSC := nonNilSC(tc.newSC())
  639. m := NewEffectiveContainerSecurityContextMutator(
  640. NewPodSecurityContextAccessor(tc.newPodSC()),
  641. NewContainerSecurityContextMutator(tc.newSC()),
  642. )
  643. b := true
  644. modifiedSC.Privileged = &b
  645. m.SetPrivileged(&b)
  646. if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
  647. t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
  648. continue
  649. }
  650. }
  651. // ReadOnlyRootFilesystem
  652. {
  653. modifiedSC := nonNilSC(tc.newSC())
  654. m := NewEffectiveContainerSecurityContextMutator(
  655. NewPodSecurityContextAccessor(tc.newPodSC()),
  656. NewContainerSecurityContextMutator(tc.newSC()),
  657. )
  658. b := true
  659. modifiedSC.ReadOnlyRootFilesystem = &b
  660. m.SetReadOnlyRootFilesystem(&b)
  661. if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
  662. t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
  663. continue
  664. }
  665. }
  666. // RunAsNonRoot
  667. {
  668. modifiedSC := nonNilSC(tc.newSC())
  669. m := NewEffectiveContainerSecurityContextMutator(
  670. NewPodSecurityContextAccessor(tc.newPodSC()),
  671. NewContainerSecurityContextMutator(tc.newSC()),
  672. )
  673. b := true
  674. modifiedSC.RunAsNonRoot = &b
  675. m.SetRunAsNonRoot(&b)
  676. if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
  677. t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
  678. continue
  679. }
  680. }
  681. // RunAsUser
  682. {
  683. modifiedSC := nonNilSC(tc.newSC())
  684. m := NewEffectiveContainerSecurityContextMutator(
  685. NewPodSecurityContextAccessor(tc.newPodSC()),
  686. NewContainerSecurityContextMutator(tc.newSC()),
  687. )
  688. i := int64(1123)
  689. modifiedSC.RunAsUser = &i
  690. m.SetRunAsUser(&i)
  691. if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
  692. t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
  693. continue
  694. }
  695. }
  696. // SELinuxOptions
  697. {
  698. modifiedSC := nonNilSC(tc.newSC())
  699. m := NewEffectiveContainerSecurityContextMutator(
  700. NewPodSecurityContextAccessor(tc.newPodSC()),
  701. NewContainerSecurityContextMutator(tc.newSC()),
  702. )
  703. modifiedSC.SELinuxOptions = &api.SELinuxOptions{User: "bob"}
  704. m.SetSELinuxOptions(&api.SELinuxOptions{User: "bob"})
  705. if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) {
  706. t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext()))
  707. continue
  708. }
  709. }
  710. }
  711. }