admission_test.go 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088
  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 serviceaccount
  14. import (
  15. "reflect"
  16. "strings"
  17. "testing"
  18. "github.com/stretchr/testify/assert"
  19. corev1 "k8s.io/api/core/v1"
  20. "k8s.io/apimachinery/pkg/api/errors"
  21. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  22. "k8s.io/apimachinery/pkg/types"
  23. "k8s.io/apiserver/pkg/admission"
  24. admissiontesting "k8s.io/apiserver/pkg/admission/testing"
  25. "k8s.io/client-go/informers"
  26. "k8s.io/client-go/kubernetes/fake"
  27. corev1listers "k8s.io/client-go/listers/core/v1"
  28. "k8s.io/client-go/tools/cache"
  29. "k8s.io/component-base/featuregate"
  30. api "k8s.io/kubernetes/pkg/apis/core"
  31. "k8s.io/kubernetes/pkg/controller"
  32. kubefeatures "k8s.io/kubernetes/pkg/features"
  33. kubelet "k8s.io/kubernetes/pkg/kubelet/types"
  34. )
  35. var (
  36. deprecationDisabledFeature = featuregate.NewFeatureGate()
  37. deprecationEnabledFeature = featuregate.NewFeatureGate()
  38. )
  39. func init() {
  40. if err := deprecationDisabledFeature.Add(map[featuregate.Feature]featuregate.FeatureSpec{kubefeatures.BoundServiceAccountTokenVolume: {Default: false}}); err != nil {
  41. panic(err)
  42. }
  43. if err := deprecationEnabledFeature.Add(map[featuregate.Feature]featuregate.FeatureSpec{kubefeatures.BoundServiceAccountTokenVolume: {Default: true}}); err != nil {
  44. panic(err)
  45. }
  46. }
  47. func TestIgnoresNonCreate(t *testing.T) {
  48. for _, op := range []admission.Operation{admission.Delete, admission.Connect} {
  49. handler := NewServiceAccount()
  50. if handler.Handles(op) {
  51. t.Errorf("Expected not to handle operation %s", op)
  52. }
  53. }
  54. }
  55. func TestIgnoresNonPodResource(t *testing.T) {
  56. pod := &api.Pod{}
  57. attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("CustomResource").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  58. handler := admissiontesting.WithReinvocationTesting(t, NewServiceAccount())
  59. err := handler.Admit(attrs, nil)
  60. if err != nil {
  61. t.Errorf("Expected non-pod resource allowed, got err: %v", err)
  62. }
  63. }
  64. func TestIgnoresNilObject(t *testing.T) {
  65. attrs := admission.NewAttributesRecord(nil, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  66. handler := admissiontesting.WithReinvocationTesting(t, NewServiceAccount())
  67. err := handler.Admit(attrs, nil)
  68. if err != nil {
  69. t.Errorf("Expected nil object allowed allowed, got err: %v", err)
  70. }
  71. }
  72. func TestIgnoresNonPodObject(t *testing.T) {
  73. obj := &api.Namespace{}
  74. attrs := admission.NewAttributesRecord(obj, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  75. handler := admissiontesting.WithReinvocationTesting(t, NewServiceAccount())
  76. err := handler.Admit(attrs, nil)
  77. if err != nil {
  78. t.Errorf("Expected non pod object allowed, got err: %v", err)
  79. }
  80. }
  81. func TestIgnoresMirrorPod(t *testing.T) {
  82. pod := &api.Pod{
  83. ObjectMeta: metav1.ObjectMeta{
  84. Annotations: map[string]string{
  85. kubelet.ConfigMirrorAnnotationKey: "true",
  86. },
  87. },
  88. Spec: api.PodSpec{
  89. Volumes: []api.Volume{
  90. {VolumeSource: api.VolumeSource{}},
  91. },
  92. },
  93. }
  94. attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  95. err := admissiontesting.WithReinvocationTesting(t, NewServiceAccount()).Admit(attrs, nil)
  96. if err != nil {
  97. t.Errorf("Expected mirror pod without service account or secrets allowed, got err: %v", err)
  98. }
  99. }
  100. func TestRejectsMirrorPodWithServiceAccount(t *testing.T) {
  101. pod := &api.Pod{
  102. ObjectMeta: metav1.ObjectMeta{
  103. Annotations: map[string]string{
  104. kubelet.ConfigMirrorAnnotationKey: "true",
  105. },
  106. },
  107. Spec: api.PodSpec{
  108. ServiceAccountName: "default",
  109. },
  110. }
  111. attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  112. err := admissiontesting.WithReinvocationTesting(t, NewServiceAccount()).Admit(attrs, nil)
  113. if err == nil {
  114. t.Errorf("Expected a mirror pod to be prevented from referencing a service account")
  115. }
  116. }
  117. func TestRejectsMirrorPodWithSecretVolumes(t *testing.T) {
  118. pod := &api.Pod{
  119. ObjectMeta: metav1.ObjectMeta{
  120. Annotations: map[string]string{
  121. kubelet.ConfigMirrorAnnotationKey: "true",
  122. },
  123. },
  124. Spec: api.PodSpec{
  125. Volumes: []api.Volume{
  126. {VolumeSource: api.VolumeSource{Secret: &api.SecretVolumeSource{}}},
  127. },
  128. },
  129. }
  130. attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  131. err := admissiontesting.WithReinvocationTesting(t, NewServiceAccount()).Admit(attrs, nil)
  132. if err == nil {
  133. t.Errorf("Expected a mirror pod to be prevented from referencing a secret volume")
  134. }
  135. }
  136. func TestRejectsMirrorPodWithServiceAccountTokenVolumeProjections(t *testing.T) {
  137. pod := &api.Pod{
  138. ObjectMeta: metav1.ObjectMeta{
  139. Annotations: map[string]string{
  140. kubelet.ConfigMirrorAnnotationKey: "true",
  141. },
  142. },
  143. Spec: api.PodSpec{
  144. Volumes: []api.Volume{
  145. {VolumeSource: api.VolumeSource{
  146. Projected: &api.ProjectedVolumeSource{
  147. Sources: []api.VolumeProjection{{ServiceAccountToken: &api.ServiceAccountTokenProjection{}}},
  148. },
  149. },
  150. },
  151. },
  152. },
  153. }
  154. attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), "myns", "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  155. err := admissiontesting.WithReinvocationTesting(t, NewServiceAccount()).Admit(attrs, nil)
  156. if err == nil {
  157. t.Errorf("Expected a mirror pod to be prevented from referencing a ServiceAccountToken volume projection")
  158. }
  159. }
  160. func TestAssignsDefaultServiceAccountAndToleratesMissingAPIToken(t *testing.T) {
  161. ns := "myns"
  162. admit := NewServiceAccount()
  163. informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
  164. admit.SetExternalKubeInformerFactory(informerFactory)
  165. admit.MountServiceAccountToken = true
  166. admit.RequireAPIToken = false
  167. // Add the default service account for the ns into the cache
  168. informerFactory.Core().V1().ServiceAccounts().Informer().GetStore().Add(&corev1.ServiceAccount{
  169. ObjectMeta: metav1.ObjectMeta{
  170. Name: DefaultServiceAccountName,
  171. Namespace: ns,
  172. },
  173. })
  174. pod := &api.Pod{}
  175. attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  176. err := admissiontesting.WithReinvocationTesting(t, admit).Admit(attrs, nil)
  177. if err != nil {
  178. t.Errorf("Unexpected error: %v", err)
  179. }
  180. if pod.Spec.ServiceAccountName != DefaultServiceAccountName {
  181. t.Errorf("Expected service account %s assigned, got %s", DefaultServiceAccountName, pod.Spec.ServiceAccountName)
  182. }
  183. }
  184. func TestAssignsDefaultServiceAccountAndRejectsMissingAPIToken(t *testing.T) {
  185. ns := "myns"
  186. admit := NewServiceAccount()
  187. informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
  188. admit.SetExternalKubeInformerFactory(informerFactory)
  189. admit.MountServiceAccountToken = true
  190. admit.RequireAPIToken = true
  191. // Add the default service account for the ns into the cache
  192. informerFactory.Core().V1().ServiceAccounts().Informer().GetStore().Add(&corev1.ServiceAccount{
  193. ObjectMeta: metav1.ObjectMeta{
  194. Name: DefaultServiceAccountName,
  195. Namespace: ns,
  196. },
  197. })
  198. pod := &api.Pod{}
  199. attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  200. err := admissiontesting.WithReinvocationTesting(t, admit).Admit(attrs, nil)
  201. if err == nil || !errors.IsServerTimeout(err) {
  202. t.Errorf("Expected server timeout error for missing API token: %v", err)
  203. }
  204. }
  205. func TestFetchesUncachedServiceAccount(t *testing.T) {
  206. ns := "myns"
  207. // Build a test client that the admission plugin can use to look up the service account missing from its cache
  208. client := fake.NewSimpleClientset(&corev1.ServiceAccount{
  209. ObjectMeta: metav1.ObjectMeta{
  210. Name: DefaultServiceAccountName,
  211. Namespace: ns,
  212. },
  213. })
  214. admit := NewServiceAccount()
  215. informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
  216. admit.SetExternalKubeInformerFactory(informerFactory)
  217. admit.client = client
  218. admit.RequireAPIToken = false
  219. pod := &api.Pod{}
  220. attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  221. err := admissiontesting.WithReinvocationTesting(t, admit).Admit(attrs, nil)
  222. if err != nil {
  223. t.Errorf("Unexpected error: %v", err)
  224. }
  225. if pod.Spec.ServiceAccountName != DefaultServiceAccountName {
  226. t.Errorf("Expected service account %s assigned, got %s", DefaultServiceAccountName, pod.Spec.ServiceAccountName)
  227. }
  228. }
  229. func TestDeniesInvalidServiceAccount(t *testing.T) {
  230. ns := "myns"
  231. // Build a test client that the admission plugin can use to look up the service account missing from its cache
  232. client := fake.NewSimpleClientset()
  233. admit := NewServiceAccount()
  234. admit.SetExternalKubeClientSet(client)
  235. informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
  236. admit.SetExternalKubeInformerFactory(informerFactory)
  237. pod := &api.Pod{}
  238. attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  239. err := admissiontesting.WithReinvocationTesting(t, admit).Admit(attrs, nil)
  240. if err == nil {
  241. t.Errorf("Expected error for missing service account, got none")
  242. }
  243. }
  244. func TestAutomountsAPIToken(t *testing.T) {
  245. testBoundServiceAccountTokenVolumePhases(t, func(t *testing.T, applyFeatures func(*Plugin) *Plugin) {
  246. admit := applyFeatures(NewServiceAccount())
  247. informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
  248. admit.SetExternalKubeInformerFactory(informerFactory)
  249. admit.generateName = testGenerateName
  250. admit.MountServiceAccountToken = true
  251. admit.RequireAPIToken = true
  252. ns := "myns"
  253. serviceAccountName := DefaultServiceAccountName
  254. serviceAccountUID := "12345"
  255. tokenName := "token-name"
  256. if admit.featureGate.Enabled(kubefeatures.BoundServiceAccountTokenVolume) {
  257. tokenName = generatedVolumeName
  258. }
  259. expectedVolume := admit.createVolume(tokenName, tokenName)
  260. expectedVolumeMount := api.VolumeMount{
  261. Name: tokenName,
  262. ReadOnly: true,
  263. MountPath: DefaultAPITokenMountPath,
  264. }
  265. // Add the default service account for the ns with a token into the cache
  266. informerFactory.Core().V1().ServiceAccounts().Informer().GetStore().Add(&corev1.ServiceAccount{
  267. ObjectMeta: metav1.ObjectMeta{
  268. Name: serviceAccountName,
  269. Namespace: ns,
  270. UID: types.UID(serviceAccountUID),
  271. },
  272. Secrets: []corev1.ObjectReference{
  273. {Name: tokenName},
  274. },
  275. })
  276. // Add a token for the service account into the cache
  277. informerFactory.Core().V1().Secrets().Informer().GetStore().Add(&corev1.Secret{
  278. ObjectMeta: metav1.ObjectMeta{
  279. Name: tokenName,
  280. Namespace: ns,
  281. Annotations: map[string]string{
  282. corev1.ServiceAccountNameKey: serviceAccountName,
  283. corev1.ServiceAccountUIDKey: serviceAccountUID,
  284. },
  285. },
  286. Type: corev1.SecretTypeServiceAccountToken,
  287. Data: map[string][]byte{
  288. api.ServiceAccountTokenKey: []byte("token-data"),
  289. },
  290. })
  291. pod := &api.Pod{
  292. Spec: api.PodSpec{
  293. Containers: []api.Container{
  294. {},
  295. },
  296. },
  297. }
  298. attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  299. err := admissiontesting.WithReinvocationTesting(t, admit).Admit(attrs, nil)
  300. if err != nil {
  301. t.Errorf("Unexpected error: %v", err)
  302. }
  303. if pod.Spec.ServiceAccountName != DefaultServiceAccountName {
  304. t.Errorf("Expected service account %s assigned, got %s", DefaultServiceAccountName, pod.Spec.ServiceAccountName)
  305. }
  306. if len(pod.Spec.Volumes) != 1 {
  307. t.Fatalf("Expected 1 volume, got %d", len(pod.Spec.Volumes))
  308. }
  309. if !reflect.DeepEqual(expectedVolume, pod.Spec.Volumes[0]) {
  310. t.Fatalf("Expected\n\t%#v\ngot\n\t%#v", expectedVolume, pod.Spec.Volumes[0])
  311. }
  312. if len(pod.Spec.Containers[0].VolumeMounts) != 1 {
  313. t.Fatalf("Expected 1 volume mount, got %d", len(pod.Spec.Containers[0].VolumeMounts))
  314. }
  315. if !reflect.DeepEqual(expectedVolumeMount, pod.Spec.Containers[0].VolumeMounts[0]) {
  316. t.Fatalf("Expected\n\t%#v\ngot\n\t%#v", expectedVolumeMount, pod.Spec.Containers[0].VolumeMounts[0])
  317. }
  318. // testing InitContainers
  319. pod = &api.Pod{
  320. Spec: api.PodSpec{
  321. InitContainers: []api.Container{
  322. {},
  323. },
  324. },
  325. }
  326. attrs = admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  327. if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(attrs, nil); err != nil {
  328. t.Errorf("Unexpected error: %v", err)
  329. }
  330. if pod.Spec.ServiceAccountName != DefaultServiceAccountName {
  331. t.Errorf("Expected service account %s assigned, got %s", DefaultServiceAccountName, pod.Spec.ServiceAccountName)
  332. }
  333. if len(pod.Spec.Volumes) != 1 {
  334. t.Fatalf("Expected 1 volume, got %d", len(pod.Spec.Volumes))
  335. }
  336. if !reflect.DeepEqual(expectedVolume, pod.Spec.Volumes[0]) {
  337. t.Fatalf("Expected\n\t%#v\ngot\n\t%#v", expectedVolume, pod.Spec.Volumes[0])
  338. }
  339. if len(pod.Spec.InitContainers[0].VolumeMounts) != 1 {
  340. t.Fatalf("Expected 1 volume mount, got %d", len(pod.Spec.InitContainers[0].VolumeMounts))
  341. }
  342. if !reflect.DeepEqual(expectedVolumeMount, pod.Spec.InitContainers[0].VolumeMounts[0]) {
  343. t.Fatalf("Expected\n\t%#v\ngot\n\t%#v", expectedVolumeMount, pod.Spec.InitContainers[0].VolumeMounts[0])
  344. }
  345. })
  346. }
  347. func TestRespectsExistingMount(t *testing.T) {
  348. testBoundServiceAccountTokenVolumePhases(t, func(t *testing.T, applyFeatures func(*Plugin) *Plugin) {
  349. ns := "myns"
  350. tokenName := "token-name"
  351. serviceAccountName := DefaultServiceAccountName
  352. serviceAccountUID := "12345"
  353. expectedVolumeMount := api.VolumeMount{
  354. Name: "my-custom-mount",
  355. ReadOnly: false,
  356. MountPath: DefaultAPITokenMountPath,
  357. }
  358. admit := applyFeatures(NewServiceAccount())
  359. informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
  360. admit.SetExternalKubeInformerFactory(informerFactory)
  361. admit.MountServiceAccountToken = true
  362. admit.RequireAPIToken = true
  363. // Add the default service account for the ns with a token into the cache
  364. informerFactory.Core().V1().ServiceAccounts().Informer().GetStore().Add(&corev1.ServiceAccount{
  365. ObjectMeta: metav1.ObjectMeta{
  366. Name: serviceAccountName,
  367. Namespace: ns,
  368. UID: types.UID(serviceAccountUID),
  369. },
  370. Secrets: []corev1.ObjectReference{
  371. {Name: tokenName},
  372. },
  373. })
  374. // Add a token for the service account into the cache
  375. informerFactory.Core().V1().Secrets().Informer().GetStore().Add(&corev1.Secret{
  376. ObjectMeta: metav1.ObjectMeta{
  377. Name: tokenName,
  378. Namespace: ns,
  379. Annotations: map[string]string{
  380. corev1.ServiceAccountNameKey: serviceAccountName,
  381. corev1.ServiceAccountUIDKey: serviceAccountUID,
  382. },
  383. },
  384. Type: corev1.SecretTypeServiceAccountToken,
  385. Data: map[string][]byte{
  386. corev1.ServiceAccountTokenKey: []byte("token-data"),
  387. },
  388. })
  389. // Define a pod with a container that already mounts a volume at the API token path
  390. // Admission should respect that
  391. // Additionally, no volume should be created if no container is going to use it
  392. pod := &api.Pod{
  393. Spec: api.PodSpec{
  394. Containers: []api.Container{
  395. {
  396. VolumeMounts: []api.VolumeMount{
  397. expectedVolumeMount,
  398. },
  399. },
  400. },
  401. },
  402. }
  403. attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  404. err := admissiontesting.WithReinvocationTesting(t, admit).Admit(attrs, nil)
  405. if err != nil {
  406. t.Errorf("Unexpected error: %v", err)
  407. }
  408. if pod.Spec.ServiceAccountName != DefaultServiceAccountName {
  409. t.Errorf("Expected service account %s assigned, got %s", DefaultServiceAccountName, pod.Spec.ServiceAccountName)
  410. }
  411. if len(pod.Spec.Volumes) != 0 {
  412. t.Fatalf("Expected 0 volumes (shouldn't create a volume for a secret we don't need), got %d", len(pod.Spec.Volumes))
  413. }
  414. if len(pod.Spec.Containers[0].VolumeMounts) != 1 {
  415. t.Fatalf("Expected 1 volume mount, got %d", len(pod.Spec.Containers[0].VolumeMounts))
  416. }
  417. if !reflect.DeepEqual(expectedVolumeMount, pod.Spec.Containers[0].VolumeMounts[0]) {
  418. t.Fatalf("Expected\n\t%#v\ngot\n\t%#v", expectedVolumeMount, pod.Spec.Containers[0].VolumeMounts[0])
  419. }
  420. // check init containers
  421. pod = &api.Pod{
  422. Spec: api.PodSpec{
  423. InitContainers: []api.Container{
  424. {
  425. VolumeMounts: []api.VolumeMount{
  426. expectedVolumeMount,
  427. },
  428. },
  429. },
  430. },
  431. }
  432. attrs = admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  433. if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(attrs, nil); err != nil {
  434. t.Errorf("Unexpected error: %v", err)
  435. }
  436. if pod.Spec.ServiceAccountName != DefaultServiceAccountName {
  437. t.Errorf("Expected service account %s assigned, got %s", DefaultServiceAccountName, pod.Spec.ServiceAccountName)
  438. }
  439. if len(pod.Spec.Volumes) != 0 {
  440. t.Fatalf("Expected 0 volumes (shouldn't create a volume for a secret we don't need), got %d", len(pod.Spec.Volumes))
  441. }
  442. if len(pod.Spec.InitContainers[0].VolumeMounts) != 1 {
  443. t.Fatalf("Expected 1 volume mount, got %d", len(pod.Spec.InitContainers[0].VolumeMounts))
  444. }
  445. if !reflect.DeepEqual(expectedVolumeMount, pod.Spec.InitContainers[0].VolumeMounts[0]) {
  446. t.Fatalf("Expected\n\t%#v\ngot\n\t%#v", expectedVolumeMount, pod.Spec.InitContainers[0].VolumeMounts[0])
  447. }
  448. })
  449. }
  450. func TestAllowsReferencedSecret(t *testing.T) {
  451. ns := "myns"
  452. admit := NewServiceAccount()
  453. informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
  454. admit.SetExternalKubeInformerFactory(informerFactory)
  455. admit.LimitSecretReferences = true
  456. admit.RequireAPIToken = false
  457. // Add the default service account for the ns with a secret reference into the cache
  458. informerFactory.Core().V1().ServiceAccounts().Informer().GetStore().Add(&corev1.ServiceAccount{
  459. ObjectMeta: metav1.ObjectMeta{
  460. Name: DefaultServiceAccountName,
  461. Namespace: ns,
  462. },
  463. Secrets: []corev1.ObjectReference{
  464. {Name: "foo"},
  465. },
  466. })
  467. pod1 := &api.Pod{
  468. Spec: api.PodSpec{
  469. Volumes: []api.Volume{
  470. {VolumeSource: api.VolumeSource{Secret: &api.SecretVolumeSource{SecretName: "foo"}}},
  471. },
  472. },
  473. }
  474. attrs := admission.NewAttributesRecord(pod1, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  475. if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(attrs, nil); err != nil {
  476. t.Errorf("Unexpected error: %v", err)
  477. }
  478. pod2 := &api.Pod{
  479. Spec: api.PodSpec{
  480. Containers: []api.Container{
  481. {
  482. Name: "container-1",
  483. Env: []api.EnvVar{
  484. {
  485. Name: "env-1",
  486. ValueFrom: &api.EnvVarSource{
  487. SecretKeyRef: &api.SecretKeySelector{
  488. LocalObjectReference: api.LocalObjectReference{Name: "foo"},
  489. },
  490. },
  491. },
  492. },
  493. },
  494. },
  495. },
  496. }
  497. attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  498. if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(attrs, nil); err != nil {
  499. t.Errorf("Unexpected error: %v", err)
  500. }
  501. pod2 = &api.Pod{
  502. Spec: api.PodSpec{
  503. InitContainers: []api.Container{
  504. {
  505. Name: "container-1",
  506. Env: []api.EnvVar{
  507. {
  508. Name: "env-1",
  509. ValueFrom: &api.EnvVarSource{
  510. SecretKeyRef: &api.SecretKeySelector{
  511. LocalObjectReference: api.LocalObjectReference{Name: "foo"},
  512. },
  513. },
  514. },
  515. },
  516. },
  517. },
  518. },
  519. }
  520. attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  521. if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(attrs, nil); err != nil {
  522. t.Errorf("Unexpected error: %v", err)
  523. }
  524. }
  525. func TestRejectsUnreferencedSecretVolumes(t *testing.T) {
  526. ns := "myns"
  527. admit := NewServiceAccount()
  528. informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
  529. admit.SetExternalKubeInformerFactory(informerFactory)
  530. admit.LimitSecretReferences = true
  531. admit.RequireAPIToken = false
  532. // Add the default service account for the ns into the cache
  533. informerFactory.Core().V1().ServiceAccounts().Informer().GetStore().Add(&corev1.ServiceAccount{
  534. ObjectMeta: metav1.ObjectMeta{
  535. Name: DefaultServiceAccountName,
  536. Namespace: ns,
  537. },
  538. })
  539. pod1 := &api.Pod{
  540. Spec: api.PodSpec{
  541. Volumes: []api.Volume{
  542. {VolumeSource: api.VolumeSource{Secret: &api.SecretVolumeSource{SecretName: "foo"}}},
  543. },
  544. },
  545. }
  546. attrs := admission.NewAttributesRecord(pod1, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  547. if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(attrs, nil); err == nil {
  548. t.Errorf("Expected rejection for using a secret the service account does not reference")
  549. }
  550. pod2 := &api.Pod{
  551. Spec: api.PodSpec{
  552. Containers: []api.Container{
  553. {
  554. Name: "container-1",
  555. Env: []api.EnvVar{
  556. {
  557. Name: "env-1",
  558. ValueFrom: &api.EnvVarSource{
  559. SecretKeyRef: &api.SecretKeySelector{
  560. LocalObjectReference: api.LocalObjectReference{Name: "foo"},
  561. },
  562. },
  563. },
  564. },
  565. },
  566. },
  567. },
  568. }
  569. attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  570. if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(attrs, nil); err == nil || !strings.Contains(err.Error(), "with envVar") {
  571. t.Errorf("Unexpected error: %v", err)
  572. }
  573. pod2 = &api.Pod{
  574. Spec: api.PodSpec{
  575. InitContainers: []api.Container{
  576. {
  577. Name: "container-1",
  578. Env: []api.EnvVar{
  579. {
  580. Name: "env-1",
  581. ValueFrom: &api.EnvVarSource{
  582. SecretKeyRef: &api.SecretKeySelector{
  583. LocalObjectReference: api.LocalObjectReference{Name: "foo"},
  584. },
  585. },
  586. },
  587. },
  588. },
  589. },
  590. },
  591. }
  592. attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  593. if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(attrs, nil); err == nil || !strings.Contains(err.Error(), "with envVar") {
  594. t.Errorf("Unexpected error: %v", err)
  595. }
  596. }
  597. func TestAllowUnreferencedSecretVolumesForPermissiveSAs(t *testing.T) {
  598. ns := "myns"
  599. admit := NewServiceAccount()
  600. informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
  601. admit.SetExternalKubeInformerFactory(informerFactory)
  602. admit.LimitSecretReferences = false
  603. admit.RequireAPIToken = false
  604. // Add the default service account for the ns into the cache
  605. informerFactory.Core().V1().ServiceAccounts().Informer().GetStore().Add(&corev1.ServiceAccount{
  606. ObjectMeta: metav1.ObjectMeta{
  607. Name: DefaultServiceAccountName,
  608. Namespace: ns,
  609. Annotations: map[string]string{EnforceMountableSecretsAnnotation: "true"},
  610. },
  611. })
  612. pod := &api.Pod{
  613. Spec: api.PodSpec{
  614. Volumes: []api.Volume{
  615. {VolumeSource: api.VolumeSource{Secret: &api.SecretVolumeSource{SecretName: "foo"}}},
  616. },
  617. },
  618. }
  619. attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  620. err := admissiontesting.WithReinvocationTesting(t, admit).Admit(attrs, nil)
  621. if err == nil {
  622. t.Errorf("Expected rejection for using a secret the service account does not reference")
  623. }
  624. }
  625. func TestAllowsReferencedImagePullSecrets(t *testing.T) {
  626. ns := "myns"
  627. admit := NewServiceAccount()
  628. informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
  629. admit.SetExternalKubeInformerFactory(informerFactory)
  630. admit.LimitSecretReferences = true
  631. admit.RequireAPIToken = false
  632. // Add the default service account for the ns with a secret reference into the cache
  633. informerFactory.Core().V1().ServiceAccounts().Informer().GetStore().Add(&corev1.ServiceAccount{
  634. ObjectMeta: metav1.ObjectMeta{
  635. Name: DefaultServiceAccountName,
  636. Namespace: ns,
  637. },
  638. ImagePullSecrets: []corev1.LocalObjectReference{
  639. {Name: "foo"},
  640. },
  641. })
  642. pod := &api.Pod{
  643. Spec: api.PodSpec{
  644. ImagePullSecrets: []api.LocalObjectReference{{Name: "foo"}},
  645. },
  646. }
  647. attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  648. err := admissiontesting.WithReinvocationTesting(t, admit).Admit(attrs, nil)
  649. if err != nil {
  650. t.Errorf("Unexpected error: %v", err)
  651. }
  652. }
  653. func TestRejectsUnreferencedImagePullSecrets(t *testing.T) {
  654. ns := "myns"
  655. admit := NewServiceAccount()
  656. informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
  657. admit.SetExternalKubeInformerFactory(informerFactory)
  658. admit.LimitSecretReferences = true
  659. admit.RequireAPIToken = false
  660. // Add the default service account for the ns into the cache
  661. informerFactory.Core().V1().ServiceAccounts().Informer().GetStore().Add(&corev1.ServiceAccount{
  662. ObjectMeta: metav1.ObjectMeta{
  663. Name: DefaultServiceAccountName,
  664. Namespace: ns,
  665. },
  666. })
  667. pod := &api.Pod{
  668. Spec: api.PodSpec{
  669. ImagePullSecrets: []api.LocalObjectReference{{Name: "foo"}},
  670. },
  671. }
  672. attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  673. err := admissiontesting.WithReinvocationTesting(t, admit).Admit(attrs, nil)
  674. if err == nil {
  675. t.Errorf("Expected rejection for using a secret the service account does not reference")
  676. }
  677. }
  678. func TestDoNotAddImagePullSecrets(t *testing.T) {
  679. ns := "myns"
  680. admit := NewServiceAccount()
  681. informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
  682. admit.SetExternalKubeInformerFactory(informerFactory)
  683. admit.LimitSecretReferences = true
  684. admit.RequireAPIToken = false
  685. // Add the default service account for the ns with a secret reference into the cache
  686. informerFactory.Core().V1().ServiceAccounts().Informer().GetStore().Add(&corev1.ServiceAccount{
  687. ObjectMeta: metav1.ObjectMeta{
  688. Name: DefaultServiceAccountName,
  689. Namespace: ns,
  690. },
  691. ImagePullSecrets: []corev1.LocalObjectReference{
  692. {Name: "foo"},
  693. {Name: "bar"},
  694. },
  695. })
  696. pod := &api.Pod{
  697. Spec: api.PodSpec{
  698. ImagePullSecrets: []api.LocalObjectReference{{Name: "foo"}},
  699. },
  700. }
  701. attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  702. err := admissiontesting.WithReinvocationTesting(t, admit).Admit(attrs, nil)
  703. if err != nil {
  704. t.Errorf("Unexpected error: %v", err)
  705. }
  706. if len(pod.Spec.ImagePullSecrets) != 1 || pod.Spec.ImagePullSecrets[0].Name != "foo" {
  707. t.Errorf("unexpected image pull secrets: %v", pod.Spec.ImagePullSecrets)
  708. }
  709. }
  710. func TestAddImagePullSecrets(t *testing.T) {
  711. ns := "myns"
  712. admit := NewServiceAccount()
  713. informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
  714. admit.SetExternalKubeInformerFactory(informerFactory)
  715. admit.LimitSecretReferences = true
  716. admit.RequireAPIToken = false
  717. sa := &corev1.ServiceAccount{
  718. ObjectMeta: metav1.ObjectMeta{
  719. Name: DefaultServiceAccountName,
  720. Namespace: ns,
  721. },
  722. ImagePullSecrets: []corev1.LocalObjectReference{
  723. {Name: "foo"},
  724. {Name: "bar"},
  725. },
  726. }
  727. // Add the default service account for the ns with a secret reference into the cache
  728. informerFactory.Core().V1().ServiceAccounts().Informer().GetStore().Add(sa)
  729. pod := &api.Pod{}
  730. attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  731. err := admissiontesting.WithReinvocationTesting(t, admit).Admit(attrs, nil)
  732. if err != nil {
  733. t.Errorf("Unexpected error: %v", err)
  734. }
  735. assert.EqualValues(t, sa.ImagePullSecrets, pod.Spec.ImagePullSecrets, "expected %v, got %v", sa.ImagePullSecrets, pod.Spec.ImagePullSecrets)
  736. pod.Spec.ImagePullSecrets[1] = api.LocalObjectReference{Name: "baz"}
  737. if reflect.DeepEqual(sa.ImagePullSecrets, pod.Spec.ImagePullSecrets) {
  738. t.Errorf("accidentally mutated the ServiceAccount.ImagePullSecrets: %v", sa.ImagePullSecrets)
  739. }
  740. }
  741. func TestMultipleReferencedSecrets(t *testing.T) {
  742. var (
  743. ns = "myns"
  744. serviceAccountName = "mysa"
  745. serviceAccountUID = "mysauid"
  746. token1 = "token1"
  747. token2 = "token2"
  748. )
  749. admit := NewServiceAccount()
  750. informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
  751. admit.SetExternalKubeInformerFactory(informerFactory)
  752. admit.MountServiceAccountToken = true
  753. admit.RequireAPIToken = true
  754. sa := &corev1.ServiceAccount{
  755. ObjectMeta: metav1.ObjectMeta{
  756. Name: serviceAccountName,
  757. UID: types.UID(serviceAccountUID),
  758. Namespace: ns,
  759. },
  760. Secrets: []corev1.ObjectReference{
  761. {Name: token1},
  762. {Name: token2},
  763. },
  764. }
  765. informerFactory.Core().V1().ServiceAccounts().Informer().GetStore().Add(sa)
  766. // Add two tokens for the service account into the cache.
  767. informerFactory.Core().V1().Secrets().Informer().GetStore().Add(&corev1.Secret{
  768. ObjectMeta: metav1.ObjectMeta{
  769. Name: token2,
  770. Namespace: ns,
  771. Annotations: map[string]string{
  772. api.ServiceAccountNameKey: serviceAccountName,
  773. api.ServiceAccountUIDKey: serviceAccountUID,
  774. },
  775. },
  776. Type: corev1.SecretTypeServiceAccountToken,
  777. Data: map[string][]byte{
  778. api.ServiceAccountTokenKey: []byte("token-data"),
  779. },
  780. })
  781. informerFactory.Core().V1().Secrets().Informer().GetStore().Add(&corev1.Secret{
  782. ObjectMeta: metav1.ObjectMeta{
  783. Name: token1,
  784. Namespace: ns,
  785. Annotations: map[string]string{
  786. api.ServiceAccountNameKey: serviceAccountName,
  787. api.ServiceAccountUIDKey: serviceAccountUID,
  788. },
  789. },
  790. Type: corev1.SecretTypeServiceAccountToken,
  791. Data: map[string][]byte{
  792. api.ServiceAccountTokenKey: []byte("token-data"),
  793. },
  794. })
  795. pod := &api.Pod{
  796. Spec: api.PodSpec{
  797. ServiceAccountName: serviceAccountName,
  798. Containers: []api.Container{
  799. {Name: "container-1"},
  800. },
  801. },
  802. }
  803. attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  804. if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(attrs, nil); err != nil {
  805. t.Fatal(err)
  806. }
  807. if n := len(pod.Spec.Volumes); n != 1 {
  808. t.Fatalf("expected 1 volume mount, got %d", n)
  809. }
  810. if name := pod.Spec.Volumes[0].Name; name != token1 {
  811. t.Errorf("expected first referenced secret to be mounted, got %q", name)
  812. }
  813. }
  814. func newSecret(secretType corev1.SecretType, namespace, name, serviceAccountName, serviceAccountUID string) *corev1.Secret {
  815. return &corev1.Secret{
  816. ObjectMeta: metav1.ObjectMeta{
  817. Namespace: namespace,
  818. Name: name,
  819. Annotations: map[string]string{
  820. corev1.ServiceAccountNameKey: serviceAccountName,
  821. corev1.ServiceAccountUIDKey: serviceAccountUID,
  822. },
  823. },
  824. Type: secretType,
  825. }
  826. }
  827. func TestGetServiceAccountTokens(t *testing.T) {
  828. testBoundServiceAccountTokenVolumePhases(t, func(t *testing.T, applyFeatures func(*Plugin) *Plugin) {
  829. admit := applyFeatures(NewServiceAccount())
  830. indexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{})
  831. admit.secretLister = corev1listers.NewSecretLister(indexer)
  832. ns := "namespace"
  833. serviceAccountUID := "12345"
  834. sa := &corev1.ServiceAccount{
  835. ObjectMeta: metav1.ObjectMeta{
  836. Name: DefaultServiceAccountName,
  837. Namespace: ns,
  838. UID: types.UID(serviceAccountUID),
  839. },
  840. }
  841. nonSATokenSecret := newSecret(corev1.SecretTypeDockercfg, ns, "nonSATokenSecret", DefaultServiceAccountName, serviceAccountUID)
  842. indexer.Add(nonSATokenSecret)
  843. differentSAToken := newSecret(corev1.SecretTypeServiceAccountToken, ns, "differentSAToken", "someOtherSA", "someOtherUID")
  844. indexer.Add(differentSAToken)
  845. matchingSAToken := newSecret(corev1.SecretTypeServiceAccountToken, ns, "matchingSAToken", DefaultServiceAccountName, serviceAccountUID)
  846. indexer.Add(matchingSAToken)
  847. tokens, err := admit.getServiceAccountTokens(sa)
  848. if err != nil {
  849. t.Fatalf("unexpected error: %v", err)
  850. }
  851. if len(tokens) != 1 {
  852. names := make([]string, 0, len(tokens))
  853. for _, token := range tokens {
  854. names = append(names, token.Name)
  855. }
  856. t.Fatalf("expected only 1 token, got %v", names)
  857. }
  858. if e, a := matchingSAToken.Name, tokens[0].Name; e != a {
  859. t.Errorf("expected token %s, got %s", e, a)
  860. }
  861. })
  862. }
  863. func TestAutomountIsBackwardsCompatible(t *testing.T) {
  864. ns := "myns"
  865. tokenName := "token-name"
  866. serviceAccountName := DefaultServiceAccountName
  867. serviceAccountUID := "12345"
  868. defaultTokenName := "default-token-abc123"
  869. expectedVolume := api.Volume{
  870. Name: defaultTokenName,
  871. VolumeSource: api.VolumeSource{
  872. Secret: &api.SecretVolumeSource{
  873. SecretName: defaultTokenName,
  874. },
  875. },
  876. }
  877. expectedVolumeMount := api.VolumeMount{
  878. Name: defaultTokenName,
  879. ReadOnly: true,
  880. MountPath: DefaultAPITokenMountPath,
  881. }
  882. admit := NewServiceAccount()
  883. admit.generateName = testGenerateName
  884. admit.featureGate = deprecationEnabledFeature
  885. informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
  886. admit.SetExternalKubeInformerFactory(informerFactory)
  887. admit.MountServiceAccountToken = true
  888. admit.RequireAPIToken = true
  889. // Add the default service account for the ns with a token into the cache
  890. informerFactory.Core().V1().ServiceAccounts().Informer().GetStore().Add(&corev1.ServiceAccount{
  891. ObjectMeta: metav1.ObjectMeta{
  892. Name: serviceAccountName,
  893. Namespace: ns,
  894. UID: types.UID(serviceAccountUID),
  895. },
  896. Secrets: []corev1.ObjectReference{
  897. {Name: tokenName},
  898. },
  899. })
  900. // Add a token for the service account into the cache
  901. informerFactory.Core().V1().Secrets().Informer().GetStore().Add(&corev1.Secret{
  902. ObjectMeta: metav1.ObjectMeta{
  903. Name: tokenName,
  904. Namespace: ns,
  905. Annotations: map[string]string{
  906. corev1.ServiceAccountNameKey: serviceAccountName,
  907. corev1.ServiceAccountUIDKey: serviceAccountUID,
  908. },
  909. },
  910. Type: corev1.SecretTypeServiceAccountToken,
  911. Data: map[string][]byte{
  912. api.ServiceAccountTokenKey: []byte("token-data"),
  913. },
  914. })
  915. pod := &api.Pod{
  916. Spec: api.PodSpec{
  917. Containers: []api.Container{
  918. {
  919. Name: "c-1",
  920. VolumeMounts: []api.VolumeMount{
  921. {
  922. Name: defaultTokenName,
  923. MountPath: DefaultAPITokenMountPath,
  924. ReadOnly: true,
  925. },
  926. },
  927. },
  928. },
  929. Volumes: []api.Volume{
  930. {
  931. Name: defaultTokenName,
  932. VolumeSource: api.VolumeSource{
  933. Secret: &api.SecretVolumeSource{
  934. SecretName: defaultTokenName,
  935. },
  936. },
  937. },
  938. },
  939. },
  940. }
  941. attrs := admission.NewAttributesRecord(pod, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
  942. err := admissiontesting.WithReinvocationTesting(t, admit).Admit(attrs, nil)
  943. if err != nil {
  944. t.Errorf("Unexpected error: %v", err)
  945. }
  946. if pod.Spec.ServiceAccountName != DefaultServiceAccountName {
  947. t.Errorf("Expected service account %s assigned, got %s", DefaultServiceAccountName, pod.Spec.ServiceAccountName)
  948. }
  949. _ = expectedVolume
  950. _ = expectedVolumeMount
  951. if len(pod.Spec.Volumes) != 1 {
  952. t.Fatalf("Expected 1 volume, got %d", len(pod.Spec.Volumes))
  953. }
  954. if !reflect.DeepEqual(expectedVolume, pod.Spec.Volumes[0]) {
  955. t.Fatalf("Expected\n\t%#v\ngot\n\t%#v", expectedVolume, pod.Spec.Volumes[0])
  956. }
  957. if len(pod.Spec.Containers[0].VolumeMounts) != 1 {
  958. t.Fatalf("Expected 1 volume mount, got %d", len(pod.Spec.Containers[0].VolumeMounts))
  959. }
  960. if !reflect.DeepEqual(expectedVolumeMount, pod.Spec.Containers[0].VolumeMounts[0]) {
  961. t.Fatalf("Expected\n\t%#v\ngot\n\t%#v", expectedVolumeMount, pod.Spec.Containers[0].VolumeMounts[0])
  962. }
  963. }
  964. func testGenerateName(n string) string {
  965. return n + "abc123"
  966. }
  967. var generatedVolumeName = testGenerateName(ServiceAccountVolumeName + "-")
  968. func testBoundServiceAccountTokenVolumePhases(t *testing.T, f func(*testing.T, func(*Plugin) *Plugin)) {
  969. t.Run("BoundServiceAccountTokenVolume disabled", func(t *testing.T) {
  970. f(t, func(s *Plugin) *Plugin {
  971. s.featureGate = deprecationDisabledFeature
  972. return s
  973. })
  974. })
  975. t.Run("BoundServiceAccountTokenVolume enabled", func(t *testing.T) {
  976. f(t, func(s *Plugin) *Plugin {
  977. s.featureGate = deprecationEnabledFeature
  978. return s
  979. })
  980. })
  981. }