k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/test/integration/auth/node_test.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package auth 18 19 import ( 20 "context" 21 "fmt" 22 "os" 23 "strings" 24 "testing" 25 "time" 26 27 coordination "k8s.io/api/coordination/v1" 28 corev1 "k8s.io/api/core/v1" 29 policy "k8s.io/api/policy/v1" 30 "k8s.io/api/resource/v1alpha2" 31 storagev1 "k8s.io/api/storage/v1" 32 apierrors "k8s.io/apimachinery/pkg/api/errors" 33 "k8s.io/apimachinery/pkg/api/resource" 34 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 35 "k8s.io/apimachinery/pkg/types" 36 "k8s.io/apimachinery/pkg/util/wait" 37 utilfeature "k8s.io/apiserver/pkg/util/feature" 38 clientset "k8s.io/client-go/kubernetes" 39 featuregatetesting "k8s.io/component-base/featuregate/testing" 40 kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing" 41 "k8s.io/kubernetes/pkg/features" 42 "k8s.io/kubernetes/test/integration/framework" 43 "k8s.io/utils/pointer" 44 ) 45 46 func TestNodeAuthorizer(t *testing.T) { 47 const ( 48 // Define credentials 49 // Fake values for testing. 50 tokenMaster = "master-token" 51 tokenNodeUnknown = "unknown-token" 52 tokenNode1 = "node1-token" 53 tokenNode2 = "node2-token" 54 ) 55 56 tokenFile, err := os.CreateTemp("", "kubeconfig") 57 if err != nil { 58 t.Fatal(err) 59 } 60 tokenFile.WriteString(strings.Join([]string{ 61 fmt.Sprintf(`%s,admin,uid1,"system:masters"`, tokenMaster), 62 fmt.Sprintf(`%s,unknown,uid2,"system:nodes"`, tokenNodeUnknown), 63 fmt.Sprintf(`%s,system:node:node1,uid3,"system:nodes"`, tokenNode1), 64 fmt.Sprintf(`%s,system:node:node2,uid4,"system:nodes"`, tokenNode2), 65 }, "\n")) 66 tokenFile.Close() 67 68 featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.DynamicResourceAllocation, true) 69 70 server := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{ 71 "--runtime-config=api/all=true", 72 "--authorization-mode", "Node,RBAC", 73 "--token-auth-file", tokenFile.Name(), 74 "--enable-admission-plugins", "NodeRestriction", 75 // The "default" SA is not installed, causing the ServiceAccount plugin to retry for ~1s per 76 // API request. 77 "--disable-admission-plugins", "ServiceAccount,TaintNodesByCondition", 78 }, framework.SharedEtcd()) 79 defer server.TearDownFn() 80 81 // Build client config and superuser clientset 82 clientConfig := server.ClientConfig 83 superuserClient, superuserClientExternal := clientsetForToken(tokenMaster, clientConfig) 84 85 // Wait for a healthy server 86 for { 87 result := superuserClient.CoreV1().RESTClient().Get().AbsPath("/healthz").Do(context.TODO()) 88 _, err := result.Raw() 89 if err == nil { 90 break 91 } 92 t.Log(err) 93 time.Sleep(time.Second) 94 } 95 96 // Create objects 97 if _, err := superuserClient.CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "ns"}}, metav1.CreateOptions{}); err != nil { 98 t.Fatal(err) 99 } 100 101 if _, err := superuserClient.CoreV1().Secrets("ns").Create(context.TODO(), &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "mysecret"}}, metav1.CreateOptions{}); err != nil { 102 t.Fatal(err) 103 } 104 if _, err := superuserClient.CoreV1().Secrets("ns").Create(context.TODO(), &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "mypvsecret"}}, metav1.CreateOptions{}); err != nil { 105 t.Fatal(err) 106 } 107 if _, err := superuserClient.CoreV1().ConfigMaps("ns").Create(context.TODO(), &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "myconfigmap"}}, metav1.CreateOptions{}); err != nil { 108 t.Fatal(err) 109 } 110 if _, err := superuserClient.ResourceV1alpha2().ResourceClaims("ns").Create(context.TODO(), &v1alpha2.ResourceClaim{ObjectMeta: metav1.ObjectMeta{Name: "mynamedresourceclaim"}, Spec: v1alpha2.ResourceClaimSpec{ResourceClassName: "example.com"}}, metav1.CreateOptions{}); err != nil { 111 t.Fatal(err) 112 } 113 if _, err := superuserClient.ResourceV1alpha2().ResourceClaims("ns").Create(context.TODO(), &v1alpha2.ResourceClaim{ObjectMeta: metav1.ObjectMeta{Name: "mytemplatizedresourceclaim"}, Spec: v1alpha2.ResourceClaimSpec{ResourceClassName: "example.com"}}, metav1.CreateOptions{}); err != nil { 114 t.Fatal(err) 115 } 116 117 pvName := "mypv" 118 if _, err := superuserClientExternal.StorageV1().VolumeAttachments().Create(context.TODO(), &storagev1.VolumeAttachment{ 119 ObjectMeta: metav1.ObjectMeta{Name: "myattachment"}, 120 Spec: storagev1.VolumeAttachmentSpec{ 121 Attacher: "foo", 122 Source: storagev1.VolumeAttachmentSource{PersistentVolumeName: &pvName}, 123 NodeName: "node2", 124 }, 125 }, metav1.CreateOptions{}); err != nil { 126 t.Fatal(err) 127 } 128 if _, err := superuserClient.CoreV1().PersistentVolumeClaims("ns").Create(context.TODO(), &corev1.PersistentVolumeClaim{ 129 ObjectMeta: metav1.ObjectMeta{Name: "mypvc"}, 130 Spec: corev1.PersistentVolumeClaimSpec{ 131 AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadOnlyMany}, 132 Resources: corev1.VolumeResourceRequirements{Requests: corev1.ResourceList{corev1.ResourceStorage: resource.MustParse("1")}}, 133 }, 134 }, metav1.CreateOptions{}); err != nil { 135 t.Fatal(err) 136 } 137 138 if _, err := superuserClient.CoreV1().PersistentVolumes().Create(context.TODO(), &corev1.PersistentVolume{ 139 ObjectMeta: metav1.ObjectMeta{Name: "mypv"}, 140 Spec: corev1.PersistentVolumeSpec{ 141 AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadOnlyMany}, 142 Capacity: corev1.ResourceList{corev1.ResourceStorage: resource.MustParse("1")}, 143 ClaimRef: &corev1.ObjectReference{Namespace: "ns", Name: "mypvc"}, 144 PersistentVolumeSource: corev1.PersistentVolumeSource{AzureFile: &corev1.AzureFilePersistentVolumeSource{ShareName: "default", SecretName: "mypvsecret"}}, 145 }, 146 }, metav1.CreateOptions{}); err != nil { 147 t.Fatal(err) 148 } 149 150 getSecret := func(client clientset.Interface) func() error { 151 return func() error { 152 _, err := client.CoreV1().Secrets("ns").Get(context.TODO(), "mysecret", metav1.GetOptions{}) 153 return err 154 } 155 } 156 getPVSecret := func(client clientset.Interface) func() error { 157 return func() error { 158 _, err := client.CoreV1().Secrets("ns").Get(context.TODO(), "mypvsecret", metav1.GetOptions{}) 159 return err 160 } 161 } 162 getConfigMap := func(client clientset.Interface) func() error { 163 return func() error { 164 _, err := client.CoreV1().ConfigMaps("ns").Get(context.TODO(), "myconfigmap", metav1.GetOptions{}) 165 return err 166 } 167 } 168 getPVC := func(client clientset.Interface) func() error { 169 return func() error { 170 _, err := client.CoreV1().PersistentVolumeClaims("ns").Get(context.TODO(), "mypvc", metav1.GetOptions{}) 171 return err 172 } 173 } 174 getPV := func(client clientset.Interface) func() error { 175 return func() error { 176 _, err := client.CoreV1().PersistentVolumes().Get(context.TODO(), "mypv", metav1.GetOptions{}) 177 return err 178 } 179 } 180 getVolumeAttachment := func(client clientset.Interface) func() error { 181 return func() error { 182 _, err := client.StorageV1().VolumeAttachments().Get(context.TODO(), "myattachment", metav1.GetOptions{}) 183 return err 184 } 185 } 186 getResourceClaim := func(client clientset.Interface) func() error { 187 return func() error { 188 _, err := client.ResourceV1alpha2().ResourceClaims("ns").Get(context.TODO(), "mynamedresourceclaim", metav1.GetOptions{}) 189 return err 190 } 191 } 192 getResourceClaimTemplate := func(client clientset.Interface) func() error { 193 return func() error { 194 _, err := client.ResourceV1alpha2().ResourceClaims("ns").Get(context.TODO(), "mytemplatizedresourceclaim", metav1.GetOptions{}) 195 return err 196 } 197 } 198 addResourceClaimTemplateReference := func(client clientset.Interface) func() error { 199 return func() error { 200 _, err := client.CoreV1().Pods("ns").Patch(context.TODO(), "node2normalpod", types.MergePatchType, 201 []byte(`{"status":{"resourceClaimStatuses":[{"name":"templateclaim","resourceClaimName":"mytemplatizedresourceclaim"}]}}`), 202 metav1.PatchOptions{}, "status") 203 return err 204 } 205 } 206 removeResourceClaimReference := func(client clientset.Interface) func() error { 207 return func() error { 208 _, err := client.CoreV1().Pods("ns").Patch(context.TODO(), "node2normalpod", types.MergePatchType, 209 []byte(`{"status":{"resourceClaimStatuses":null}}`), 210 metav1.PatchOptions{}, "status") 211 return err 212 } 213 } 214 215 createNode2NormalPod := func(client clientset.Interface) func() error { 216 return func() error { 217 _, err := client.CoreV1().Pods("ns").Create(context.TODO(), &corev1.Pod{ 218 ObjectMeta: metav1.ObjectMeta{Name: "node2normalpod"}, 219 Spec: corev1.PodSpec{ 220 NodeName: "node2", 221 Containers: []corev1.Container{{Name: "image", Image: "busybox"}}, 222 Volumes: []corev1.Volume{ 223 {Name: "secret", VolumeSource: corev1.VolumeSource{Secret: &corev1.SecretVolumeSource{SecretName: "mysecret"}}}, 224 {Name: "cm", VolumeSource: corev1.VolumeSource{ConfigMap: &corev1.ConfigMapVolumeSource{LocalObjectReference: corev1.LocalObjectReference{Name: "myconfigmap"}}}}, 225 {Name: "pvc", VolumeSource: corev1.VolumeSource{PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ClaimName: "mypvc"}}}, 226 }, 227 ResourceClaims: []corev1.PodResourceClaim{ 228 {Name: "namedclaim", Source: corev1.ClaimSource{ResourceClaimName: pointer.String("mynamedresourceclaim")}}, 229 {Name: "templateclaim", Source: corev1.ClaimSource{ResourceClaimTemplateName: pointer.String("myresourceclaimtemplate")}}, 230 }, 231 }, 232 }, metav1.CreateOptions{}) 233 return err 234 } 235 } 236 updateNode2NormalPodStatus := func(client clientset.Interface) func() error { 237 return func() error { 238 startTime := metav1.NewTime(time.Now()) 239 _, err := client.CoreV1().Pods("ns").UpdateStatus(context.TODO(), &corev1.Pod{ 240 ObjectMeta: metav1.ObjectMeta{Name: "node2normalpod"}, 241 Status: corev1.PodStatus{StartTime: &startTime}, 242 }, metav1.UpdateOptions{}) 243 return err 244 } 245 } 246 deleteNode2NormalPod := func(client clientset.Interface) func() error { 247 return func() error { 248 zero := int64(0) 249 return client.CoreV1().Pods("ns").Delete(context.TODO(), "node2normalpod", metav1.DeleteOptions{GracePeriodSeconds: &zero}) 250 } 251 } 252 253 createNode2MirrorPod := func(client clientset.Interface) func() error { 254 return func() error { 255 const nodeName = "node2" 256 node, err := client.CoreV1().Nodes().Get(context.TODO(), nodeName, metav1.GetOptions{}) 257 if err != nil { 258 return err 259 } 260 controller := true 261 _, err = client.CoreV1().Pods("ns").Create(context.TODO(), &corev1.Pod{ 262 ObjectMeta: metav1.ObjectMeta{ 263 Name: "node2mirrorpod", 264 Annotations: map[string]string{corev1.MirrorPodAnnotationKey: "true"}, 265 OwnerReferences: []metav1.OwnerReference{{ 266 APIVersion: corev1.SchemeGroupVersion.String(), 267 Kind: "Node", 268 Name: nodeName, 269 UID: node.UID, 270 Controller: &controller, 271 }}, 272 }, 273 Spec: corev1.PodSpec{ 274 NodeName: nodeName, 275 Containers: []corev1.Container{{Name: "image", Image: "busybox"}}, 276 }, 277 }, metav1.CreateOptions{}) 278 return err 279 } 280 } 281 deleteNode2MirrorPod := func(client clientset.Interface) func() error { 282 return func() error { 283 zero := int64(0) 284 return client.CoreV1().Pods("ns").Delete(context.TODO(), "node2mirrorpod", metav1.DeleteOptions{GracePeriodSeconds: &zero}) 285 } 286 } 287 288 createNode2 := func(client clientset.Interface) func() error { 289 return func() error { 290 _, err := client.CoreV1().Nodes().Create(context.TODO(), &corev1.Node{ObjectMeta: metav1.ObjectMeta{Name: "node2"}}, metav1.CreateOptions{}) 291 return err 292 } 293 } 294 updateNode2Status := func(client clientset.Interface) func() error { 295 return func() error { 296 _, err := client.CoreV1().Nodes().UpdateStatus(context.TODO(), &corev1.Node{ 297 ObjectMeta: metav1.ObjectMeta{Name: "node2"}, 298 Status: corev1.NodeStatus{}, 299 }, metav1.UpdateOptions{}) 300 return err 301 } 302 } 303 deleteNode2 := func(client clientset.Interface) func() error { 304 return func() error { 305 return client.CoreV1().Nodes().Delete(context.TODO(), "node2", metav1.DeleteOptions{}) 306 } 307 } 308 createNode2NormalPodEviction := func(client clientset.Interface) func() error { 309 return func() error { 310 zero := int64(0) 311 return client.PolicyV1().Evictions("ns").Evict(context.TODO(), &policy.Eviction{ 312 TypeMeta: metav1.TypeMeta{ 313 APIVersion: "policy/v1", 314 Kind: "Eviction", 315 }, 316 ObjectMeta: metav1.ObjectMeta{ 317 Name: "node2normalpod", 318 Namespace: "ns", 319 }, 320 DeleteOptions: &metav1.DeleteOptions{GracePeriodSeconds: &zero}, 321 }) 322 } 323 } 324 createNode2MirrorPodEviction := func(client clientset.Interface) func() error { 325 return func() error { 326 zero := int64(0) 327 return client.PolicyV1().Evictions("ns").Evict(context.TODO(), &policy.Eviction{ 328 TypeMeta: metav1.TypeMeta{ 329 APIVersion: "policy/v1", 330 Kind: "Eviction", 331 }, 332 ObjectMeta: metav1.ObjectMeta{ 333 Name: "node2mirrorpod", 334 Namespace: "ns", 335 }, 336 DeleteOptions: &metav1.DeleteOptions{GracePeriodSeconds: &zero}, 337 }) 338 } 339 } 340 341 capacity := 50 342 updatePVCCapacity := func(client clientset.Interface) func() error { 343 return func() error { 344 capacity++ 345 statusString := fmt.Sprintf("{\"status\": {\"capacity\": {\"storage\": \"%dG\"}}}", capacity) 346 patchBytes := []byte(statusString) 347 _, err := client.CoreV1().PersistentVolumeClaims("ns").Patch(context.TODO(), "mypvc", types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{}, "status") 348 return err 349 } 350 } 351 352 updatePVCPhase := func(client clientset.Interface) func() error { 353 return func() error { 354 patchBytes := []byte(`{"status":{"phase": "Bound"}}`) 355 _, err := client.CoreV1().PersistentVolumeClaims("ns").Patch(context.TODO(), "mypvc", types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{}, "status") 356 return err 357 } 358 } 359 360 getNode1Lease := func(client clientset.Interface) func() error { 361 return func() error { 362 _, err := client.CoordinationV1().Leases(corev1.NamespaceNodeLease).Get(context.TODO(), "node1", metav1.GetOptions{}) 363 return err 364 } 365 } 366 node1LeaseDurationSeconds := int32(40) 367 createNode1Lease := func(client clientset.Interface) func() error { 368 return func() error { 369 lease := &coordination.Lease{ 370 ObjectMeta: metav1.ObjectMeta{ 371 Name: "node1", 372 }, 373 Spec: coordination.LeaseSpec{ 374 HolderIdentity: pointer.String("node1"), 375 LeaseDurationSeconds: pointer.Int32(node1LeaseDurationSeconds), 376 RenewTime: &metav1.MicroTime{Time: time.Now()}, 377 }, 378 } 379 _, err := client.CoordinationV1().Leases(corev1.NamespaceNodeLease).Create(context.TODO(), lease, metav1.CreateOptions{}) 380 return err 381 } 382 } 383 updateNode1Lease := func(client clientset.Interface) func() error { 384 return func() error { 385 lease, err := client.CoordinationV1().Leases(corev1.NamespaceNodeLease).Get(context.TODO(), "node1", metav1.GetOptions{}) 386 if err != nil { 387 return err 388 } 389 lease.Spec.RenewTime = &metav1.MicroTime{Time: time.Now()} 390 _, err = client.CoordinationV1().Leases(corev1.NamespaceNodeLease).Update(context.TODO(), lease, metav1.UpdateOptions{}) 391 return err 392 } 393 } 394 patchNode1Lease := func(client clientset.Interface) func() error { 395 return func() error { 396 node1LeaseDurationSeconds++ 397 bs := []byte(fmt.Sprintf(`{"spec": {"leaseDurationSeconds": %d}}`, node1LeaseDurationSeconds)) 398 _, err := client.CoordinationV1().Leases(corev1.NamespaceNodeLease).Patch(context.TODO(), "node1", types.StrategicMergePatchType, bs, metav1.PatchOptions{}) 399 return err 400 } 401 } 402 deleteNode1Lease := func(client clientset.Interface) func() error { 403 return func() error { 404 return client.CoordinationV1().Leases(corev1.NamespaceNodeLease).Delete(context.TODO(), "node1", metav1.DeleteOptions{}) 405 } 406 } 407 408 getNode1CSINode := func(client clientset.Interface) func() error { 409 return func() error { 410 _, err := client.StorageV1().CSINodes().Get(context.TODO(), "node1", metav1.GetOptions{}) 411 return err 412 } 413 } 414 createNode1CSINode := func(client clientset.Interface) func() error { 415 return func() error { 416 nodeInfo := &storagev1.CSINode{ 417 ObjectMeta: metav1.ObjectMeta{ 418 Name: "node1", 419 }, 420 Spec: storagev1.CSINodeSpec{ 421 Drivers: []storagev1.CSINodeDriver{ 422 { 423 Name: "com.example.csi.driver1", 424 NodeID: "com.example.csi/node1", 425 TopologyKeys: []string{"com.example.csi/zone"}, 426 }, 427 }, 428 }, 429 } 430 _, err := client.StorageV1().CSINodes().Create(context.TODO(), nodeInfo, metav1.CreateOptions{}) 431 return err 432 } 433 } 434 updateNode1CSINode := func(client clientset.Interface) func() error { 435 return func() error { 436 nodeInfo, err := client.StorageV1().CSINodes().Get(context.TODO(), "node1", metav1.GetOptions{}) 437 if err != nil { 438 return err 439 } 440 nodeInfo.Spec.Drivers = []storagev1.CSINodeDriver{ 441 { 442 Name: "com.example.csi.driver2", 443 NodeID: "com.example.csi/node1", 444 TopologyKeys: []string{"com.example.csi/rack"}, 445 }, 446 } 447 _, err = client.StorageV1().CSINodes().Update(context.TODO(), nodeInfo, metav1.UpdateOptions{}) 448 return err 449 } 450 } 451 patchNode1CSINode := func(client clientset.Interface) func() error { 452 return func() error { 453 bs := []byte(fmt.Sprintf(`{"csiDrivers": [ { "driver": "net.example.storage.driver2", "nodeID": "net.example.storage/node1", "topologyKeys": [ "net.example.storage/region" ] } ] }`)) 454 // StrategicMergePatch is unsupported by CRs. Falling back to MergePatch 455 _, err := client.StorageV1().CSINodes().Patch(context.TODO(), "node1", types.MergePatchType, bs, metav1.PatchOptions{}) 456 return err 457 } 458 } 459 deleteNode1CSINode := func(client clientset.Interface) func() error { 460 return func() error { 461 return client.StorageV1().CSINodes().Delete(context.TODO(), "node1", metav1.DeleteOptions{}) 462 } 463 } 464 465 nodeanonClient, _ := clientsetForToken(tokenNodeUnknown, clientConfig) 466 node1Client, node1ClientExternal := clientsetForToken(tokenNode1, clientConfig) 467 node2Client, node2ClientExternal := clientsetForToken(tokenNode2, clientConfig) 468 _, csiNode1Client := clientsetForToken(tokenNode1, clientConfig) 469 _, csiNode2Client := clientsetForToken(tokenNode2, clientConfig) 470 471 // all node requests from node1 and unknown node fail 472 expectForbidden(t, getSecret(nodeanonClient)) 473 expectForbidden(t, getPVSecret(nodeanonClient)) 474 expectForbidden(t, getConfigMap(nodeanonClient)) 475 expectForbidden(t, getPVC(nodeanonClient)) 476 expectForbidden(t, getPV(nodeanonClient)) 477 expectForbidden(t, getResourceClaim(nodeanonClient)) 478 expectForbidden(t, getResourceClaimTemplate(nodeanonClient)) 479 expectForbidden(t, createNode2NormalPod(nodeanonClient)) 480 expectForbidden(t, deleteNode2NormalPod(nodeanonClient)) 481 expectForbidden(t, createNode2MirrorPodEviction(nodeanonClient)) 482 expectForbidden(t, createNode2(nodeanonClient)) 483 expectForbidden(t, updateNode2Status(nodeanonClient)) 484 expectForbidden(t, deleteNode2(nodeanonClient)) 485 486 expectForbidden(t, getSecret(node1Client)) 487 expectForbidden(t, getPVSecret(node1Client)) 488 expectForbidden(t, getConfigMap(node1Client)) 489 expectForbidden(t, getPVC(node1Client)) 490 expectForbidden(t, getPV(node1Client)) 491 expectForbidden(t, getResourceClaim(node1Client)) 492 expectForbidden(t, getResourceClaimTemplate(node1Client)) 493 expectForbidden(t, createNode2NormalPod(nodeanonClient)) 494 expectNotFound(t, createNode2MirrorPodEviction(node1Client)) 495 expectForbidden(t, createNode2(node1Client)) 496 expectNotFound(t, updateNode2Status(node1Client)) 497 expectForbidden(t, deleteNode2(node1Client)) 498 499 // related object requests from node2 fail 500 expectForbidden(t, getSecret(node2Client)) 501 expectForbidden(t, getPVSecret(node2Client)) 502 expectForbidden(t, getConfigMap(node2Client)) 503 expectForbidden(t, getPVC(node2Client)) 504 expectForbidden(t, getPV(node2Client)) 505 expectForbidden(t, getResourceClaim(node2Client)) 506 expectForbidden(t, getResourceClaimTemplate(node2Client)) 507 508 expectForbidden(t, createNode2NormalPod(nodeanonClient)) 509 // mirror pod and self node lifecycle is allowed 510 expectAllowed(t, createNode2(node2Client)) 511 expectAllowed(t, updateNode2Status(node2Client)) 512 expectForbidden(t, createNode2MirrorPod(nodeanonClient)) 513 expectForbidden(t, deleteNode2MirrorPod(nodeanonClient)) 514 expectForbidden(t, createNode2MirrorPod(node1Client)) 515 expectNotFound(t, deleteNode2MirrorPod(node1Client)) 516 // create a pod as an admin to add object references 517 expectAllowed(t, createNode2NormalPod(superuserClient)) 518 519 expectAllowed(t, createNode2MirrorPod(node2Client)) 520 expectAllowed(t, deleteNode2MirrorPod(node2Client)) 521 expectAllowed(t, createNode2MirrorPod(node2Client)) 522 expectAllowed(t, createNode2MirrorPodEviction(node2Client)) 523 // self deletion is not allowed 524 expectForbidden(t, deleteNode2(node2Client)) 525 // modification of another node's status is not allowed 526 expectForbidden(t, updateNode2Status(node1Client)) 527 528 // unidentifiable node and node1 are still forbidden 529 expectForbidden(t, getSecret(nodeanonClient)) 530 expectForbidden(t, getPVSecret(nodeanonClient)) 531 expectForbidden(t, getConfigMap(nodeanonClient)) 532 expectForbidden(t, getPVC(nodeanonClient)) 533 expectForbidden(t, getPV(nodeanonClient)) 534 expectForbidden(t, getResourceClaim(nodeanonClient)) 535 expectForbidden(t, getResourceClaimTemplate(nodeanonClient)) 536 expectForbidden(t, createNode2NormalPod(nodeanonClient)) 537 expectForbidden(t, updateNode2NormalPodStatus(nodeanonClient)) 538 expectForbidden(t, deleteNode2NormalPod(nodeanonClient)) 539 expectForbidden(t, createNode2NormalPodEviction(nodeanonClient)) 540 expectForbidden(t, createNode2MirrorPod(nodeanonClient)) 541 expectForbidden(t, deleteNode2MirrorPod(nodeanonClient)) 542 expectForbidden(t, createNode2MirrorPodEviction(nodeanonClient)) 543 544 expectForbidden(t, getSecret(node1Client)) 545 expectForbidden(t, getPVSecret(node1Client)) 546 expectForbidden(t, getConfigMap(node1Client)) 547 expectForbidden(t, getPVC(node1Client)) 548 expectForbidden(t, getPV(node1Client)) 549 expectForbidden(t, getResourceClaim(node1Client)) 550 expectForbidden(t, getResourceClaimTemplate(node1Client)) 551 expectForbidden(t, createNode2NormalPod(node1Client)) 552 expectForbidden(t, updateNode2NormalPodStatus(node1Client)) 553 expectForbidden(t, deleteNode2NormalPod(node1Client)) 554 expectForbidden(t, createNode2NormalPodEviction(node1Client)) 555 expectForbidden(t, createNode2MirrorPod(node1Client)) 556 expectNotFound(t, deleteNode2MirrorPod(node1Client)) 557 expectNotFound(t, createNode2MirrorPodEviction(node1Client)) 558 559 // node2 can get referenced objects now 560 expectAllowed(t, getSecret(node2Client)) 561 expectAllowed(t, getPVSecret(node2Client)) 562 expectAllowed(t, getConfigMap(node2Client)) 563 expectAllowed(t, getPVC(node2Client)) 564 expectAllowed(t, getPV(node2Client)) 565 566 // node2 can only get direct claim references 567 expectAllowed(t, getResourceClaim(node2Client)) 568 expectForbidden(t, getResourceClaimTemplate(node2Client)) 569 570 // node cannot add a claim reference 571 expectForbidden(t, addResourceClaimTemplateReference(node2Client)) 572 // superuser can add a claim reference 573 expectAllowed(t, addResourceClaimTemplateReference(superuserClient)) 574 // node can get direct and template claim references 575 expectAllowed(t, getResourceClaim(node2Client)) 576 expectAllowed(t, getResourceClaimTemplate(node2Client)) 577 578 // node cannot remove a claim reference 579 expectForbidden(t, removeResourceClaimReference(node2Client)) 580 // superuser can remove a claim reference 581 expectAllowed(t, removeResourceClaimReference(superuserClient)) 582 // node2 can only get direct claim references 583 expectAllowed(t, getResourceClaim(node2Client)) 584 expectForbidden(t, getResourceClaimTemplate(node2Client)) 585 586 expectForbidden(t, createNode2NormalPod(node2Client)) 587 expectAllowed(t, updateNode2NormalPodStatus(node2Client)) 588 expectAllowed(t, deleteNode2NormalPod(node2Client)) 589 expectAllowed(t, createNode2MirrorPod(node2Client)) 590 expectAllowed(t, deleteNode2MirrorPod(node2Client)) 591 592 // recreate as an admin to test eviction 593 expectAllowed(t, createNode2NormalPod(superuserClient)) 594 expectAllowed(t, createNode2MirrorPod(superuserClient)) 595 expectAllowed(t, createNode2NormalPodEviction(node2Client)) 596 expectAllowed(t, createNode2MirrorPodEviction(node2Client)) 597 // clean up node2 598 expectAllowed(t, deleteNode2(superuserClient)) 599 600 // re-create a pod as an admin to add object references 601 expectAllowed(t, createNode2NormalPod(superuserClient)) 602 603 expectForbidden(t, updatePVCCapacity(node1Client)) 604 expectAllowed(t, updatePVCCapacity(node2Client)) 605 expectForbidden(t, updatePVCPhase(node2Client)) 606 607 // Enabled CSIPersistentVolume feature 608 expectForbidden(t, getVolumeAttachment(node1ClientExternal)) 609 expectAllowed(t, getVolumeAttachment(node2ClientExternal)) 610 611 // create node2 again 612 expectAllowed(t, createNode2(node2Client)) 613 // clean up node2 614 expectAllowed(t, deleteNode2(superuserClient)) 615 616 //TODO(mikedanese): integration test node restriction of TokenRequest 617 618 // node1 allowed to operate on its own lease 619 expectAllowed(t, createNode1Lease(node1Client)) 620 expectAllowed(t, getNode1Lease(node1Client)) 621 expectAllowed(t, updateNode1Lease(node1Client)) 622 expectAllowed(t, patchNode1Lease(node1Client)) 623 expectAllowed(t, deleteNode1Lease(node1Client)) 624 // node2 not allowed to operate on another node's lease 625 expectForbidden(t, createNode1Lease(node2Client)) 626 expectForbidden(t, getNode1Lease(node2Client)) 627 expectForbidden(t, updateNode1Lease(node2Client)) 628 expectForbidden(t, patchNode1Lease(node2Client)) 629 expectForbidden(t, deleteNode1Lease(node2Client)) 630 631 // node1 allowed to operate on its own CSINode 632 expectAllowed(t, createNode1CSINode(csiNode1Client)) 633 expectAllowed(t, getNode1CSINode(csiNode1Client)) 634 expectAllowed(t, updateNode1CSINode(csiNode1Client)) 635 expectAllowed(t, patchNode1CSINode(csiNode1Client)) 636 expectAllowed(t, deleteNode1CSINode(csiNode1Client)) 637 // node2 not allowed to operate on another node's CSINode 638 expectForbidden(t, createNode1CSINode(csiNode2Client)) 639 expectForbidden(t, getNode1CSINode(csiNode2Client)) 640 expectForbidden(t, updateNode1CSINode(csiNode2Client)) 641 expectForbidden(t, patchNode1CSINode(csiNode2Client)) 642 expectForbidden(t, deleteNode1CSINode(csiNode2Client)) 643 } 644 645 // expect executes a function a set number of times until it either returns the 646 // expected error or executes too many times. It returns if the retries timed 647 // out and the last error returned by the method. 648 func expect(t *testing.T, f func() error, wantErr func(error) bool) (timeout bool, lastErr error) { 649 t.Helper() 650 err := wait.PollImmediate(time.Second, 30*time.Second, func() (bool, error) { 651 t.Helper() 652 lastErr = f() 653 if wantErr(lastErr) { 654 return true, nil 655 } 656 t.Logf("unexpected response, will retry: %v", lastErr) 657 return false, nil 658 }) 659 return err == nil, lastErr 660 } 661 662 func expectForbidden(t *testing.T, f func() error) { 663 t.Helper() 664 if ok, err := expect(t, f, apierrors.IsForbidden); !ok { 665 t.Errorf("Expected forbidden error, got %v", err) 666 } 667 } 668 669 func expectNotFound(t *testing.T, f func() error) { 670 t.Helper() 671 if ok, err := expect(t, f, apierrors.IsNotFound); !ok { 672 t.Errorf("Expected notfound error, got %v", err) 673 } 674 } 675 676 func expectAllowed(t *testing.T, f func() error) { 677 t.Helper() 678 if ok, err := expect(t, f, func(e error) bool { return e == nil }); !ok { 679 t.Errorf("Expected no error, got %v", err) 680 } 681 }