admission_test.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  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 scdeny
  14. import (
  15. "context"
  16. "testing"
  17. "k8s.io/apiserver/pkg/admission"
  18. api "k8s.io/kubernetes/pkg/apis/core"
  19. )
  20. // ensures the SecurityContext is denied if it defines anything more than Caps or Privileged
  21. func TestAdmission(t *testing.T) {
  22. handler := NewSecurityContextDeny()
  23. runAsUser := int64(1)
  24. priv := true
  25. cases := []struct {
  26. name string
  27. sc *api.SecurityContext
  28. podSc *api.PodSecurityContext
  29. expectError bool
  30. }{
  31. {
  32. name: "unset",
  33. },
  34. {
  35. name: "empty container.SecurityContext",
  36. sc: &api.SecurityContext{},
  37. },
  38. {
  39. name: "empty pod.Spec.SecurityContext",
  40. podSc: &api.PodSecurityContext{},
  41. },
  42. {
  43. name: "valid container.SecurityContext",
  44. sc: &api.SecurityContext{Privileged: &priv, Capabilities: &api.Capabilities{}},
  45. },
  46. {
  47. name: "valid pod.Spec.SecurityContext",
  48. podSc: &api.PodSecurityContext{},
  49. },
  50. {
  51. name: "container.SecurityContext.RunAsUser",
  52. sc: &api.SecurityContext{RunAsUser: &runAsUser},
  53. expectError: true,
  54. },
  55. {
  56. name: "container.SecurityContext.SELinuxOptions",
  57. sc: &api.SecurityContext{SELinuxOptions: &api.SELinuxOptions{}},
  58. expectError: true,
  59. },
  60. {
  61. name: "pod.Spec.SecurityContext.RunAsUser",
  62. podSc: &api.PodSecurityContext{RunAsUser: &runAsUser},
  63. expectError: true,
  64. },
  65. {
  66. name: "pod.Spec.SecurityContext.SELinuxOptions",
  67. podSc: &api.PodSecurityContext{SELinuxOptions: &api.SELinuxOptions{}},
  68. expectError: true,
  69. },
  70. }
  71. for _, tc := range cases {
  72. p := pod()
  73. p.Spec.SecurityContext = tc.podSc
  74. p.Spec.Containers[0].SecurityContext = tc.sc
  75. err := handler.Validate(context.TODO(), admission.NewAttributesRecord(p, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", nil, false, nil), nil)
  76. if err != nil && !tc.expectError {
  77. t.Errorf("%v: unexpected error: %v", tc.name, err)
  78. } else if err == nil && tc.expectError {
  79. t.Errorf("%v: expected error", tc.name)
  80. }
  81. // verify init containers are also checked
  82. p = pod()
  83. p.Spec.SecurityContext = tc.podSc
  84. p.Spec.Containers[0].SecurityContext = tc.sc
  85. p.Spec.InitContainers = p.Spec.Containers
  86. p.Spec.Containers = nil
  87. err = handler.Validate(context.TODO(), admission.NewAttributesRecord(p, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", nil, false, nil), nil)
  88. if err != nil && !tc.expectError {
  89. t.Errorf("%v: unexpected error: %v", tc.name, err)
  90. } else if err == nil && tc.expectError {
  91. t.Errorf("%v: expected error", tc.name)
  92. }
  93. }
  94. }
  95. func TestPodSecurityContextAdmission(t *testing.T) {
  96. handler := NewSecurityContextDeny()
  97. pod := api.Pod{
  98. Spec: api.PodSpec{
  99. Containers: []api.Container{
  100. {},
  101. },
  102. },
  103. }
  104. fsGroup := int64(1001)
  105. tests := []struct {
  106. securityContext api.PodSecurityContext
  107. errorExpected bool
  108. }{
  109. {
  110. securityContext: api.PodSecurityContext{},
  111. errorExpected: false,
  112. },
  113. {
  114. securityContext: api.PodSecurityContext{
  115. SupplementalGroups: []int64{int64(1234)},
  116. },
  117. errorExpected: true,
  118. },
  119. {
  120. securityContext: api.PodSecurityContext{
  121. FSGroup: &fsGroup,
  122. },
  123. errorExpected: true,
  124. },
  125. }
  126. for _, test := range tests {
  127. pod.Spec.SecurityContext = &test.securityContext
  128. err := handler.Validate(context.TODO(), admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", nil, false, nil), nil)
  129. if test.errorExpected && err == nil {
  130. t.Errorf("Expected error for security context %+v but did not get an error", test.securityContext)
  131. }
  132. if !test.errorExpected && err != nil {
  133. t.Errorf("Unexpected error %v for security context %+v", err, test.securityContext)
  134. }
  135. }
  136. }
  137. func TestHandles(t *testing.T) {
  138. handler := NewSecurityContextDeny()
  139. tests := map[admission.Operation]bool{
  140. admission.Update: true,
  141. admission.Create: true,
  142. admission.Delete: false,
  143. admission.Connect: false,
  144. }
  145. for op, expected := range tests {
  146. result := handler.Handles(op)
  147. if result != expected {
  148. t.Errorf("Unexpected result for operation %s: %v\n", op, result)
  149. }
  150. }
  151. }
  152. func pod() *api.Pod {
  153. return &api.Pod{
  154. Spec: api.PodSpec{
  155. Containers: []api.Container{
  156. {},
  157. },
  158. },
  159. }
  160. }