k8s.io/kubernetes@v1.29.3/test/e2e/auth/subjectreviews.go (about) 1 /* 2 Copyright 2022 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 23 authorizationv1 "k8s.io/api/authorization/v1" 24 v1 "k8s.io/api/core/v1" 25 apierrors "k8s.io/apimachinery/pkg/api/errors" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apiserver/pkg/authentication/serviceaccount" 28 "k8s.io/client-go/kubernetes" 29 "k8s.io/client-go/rest" 30 "k8s.io/kubernetes/test/e2e/framework" 31 32 "github.com/onsi/ginkgo/v2" 33 ) 34 35 var _ = SIGDescribe("SubjectReview", func() { 36 f := framework.NewDefaultFramework("subjectreview") 37 38 /* 39 Release: v1.27 40 Testname: SubjectReview, API Operations 41 Description: A ServiceAccount is created which MUST succeed. 42 A clientset is created to impersonate the ServiceAccount. 43 A SubjectAccessReview is created for the ServiceAccount which 44 MUST succeed. The allowed status for the SubjectAccessReview 45 MUST match the expected allowed for the impersonated client 46 call. A LocalSubjectAccessReviews is created for the ServiceAccount 47 which MUST succeed. The allowed status for the LocalSubjectAccessReview 48 MUST match the expected allowed for the impersonated client call. 49 */ 50 framework.ConformanceIt("should support SubjectReview API operations", func() { 51 52 AuthClient := f.ClientSet.AuthorizationV1() 53 ns := f.Namespace.Name 54 saName := "e2e" 55 56 ginkgo.By(fmt.Sprintf("Creating a Serviceaccount %q in namespace %q", saName, ns)) 57 58 sa, err := f.ClientSet.CoreV1().ServiceAccounts(ns).Create(context.TODO(), &v1.ServiceAccount{ 59 ObjectMeta: metav1.ObjectMeta{ 60 Name: saName, 61 }, 62 }, metav1.CreateOptions{}) 63 framework.ExpectNoError(err, "Unable to create serviceaccount %q", saName) 64 65 saUsername := serviceaccount.MakeUsername(sa.Namespace, sa.Name) 66 framework.Logf("saUsername: %q", saUsername) 67 saGroups := []string{"system:authenticated"} 68 saGroups = append(saGroups, serviceaccount.MakeGroupNames(sa.Namespace)...) 69 framework.Logf("saGroups: %#v", saGroups) 70 saUID := string(sa.UID) 71 framework.Logf("saUID: %q", saUID) 72 73 ginkgo.By(fmt.Sprintf("Creating clientset to impersonate %q", saUsername)) 74 config := rest.CopyConfig(f.ClientConfig()) 75 config.Impersonate = rest.ImpersonationConfig{ 76 UserName: saUsername, 77 UID: saUID, 78 Groups: saGroups, 79 } 80 81 impersonatedClientSet, err := kubernetes.NewForConfig(config) 82 framework.ExpectNoError(err, "Could not load config, %v", err) 83 84 ginkgo.By(fmt.Sprintf("Creating SubjectAccessReview for %q", saUsername)) 85 86 sar := &authorizationv1.SubjectAccessReview{ 87 Spec: authorizationv1.SubjectAccessReviewSpec{ 88 ResourceAttributes: &authorizationv1.ResourceAttributes{ 89 Verb: "list", 90 Resource: "configmaps", 91 Namespace: ns, 92 Version: "v1", 93 }, 94 User: saUsername, 95 Groups: saGroups, 96 UID: saUID, 97 }, 98 } 99 100 sarResponse, err := AuthClient.SubjectAccessReviews().Create(context.TODO(), sar, metav1.CreateOptions{}) 101 framework.ExpectNoError(err, "Unable to create a SubjectAccessReview, %#v", err) 102 framework.Logf("sarResponse Status: %#v", sarResponse.Status) 103 expectedAllowed := sarResponse.Status.Allowed 104 105 ginkgo.By(fmt.Sprintf("Verifying as %q api 'list' configmaps in %q namespace", saUsername, ns)) 106 _, requestErr := impersonatedClientSet.CoreV1().ConfigMaps(ns).List(context.TODO(), metav1.ListOptions{}) 107 108 actuallyAllowed := false 109 switch { 110 case apierrors.IsForbidden(requestErr): 111 actuallyAllowed = false 112 case requestErr != nil: 113 framework.Fail("Unexpected error") 114 default: 115 actuallyAllowed = true 116 } 117 118 if actuallyAllowed != expectedAllowed { 119 framework.Fail(fmt.Sprintf("Could not verify SubjectAccessReview for %q in namespace %q: SubjectAccessReview allowed: %v, request allowed: %v, request error: %v", saUsername, ns, expectedAllowed, actuallyAllowed, requestErr)) 120 } 121 framework.Logf("SubjectAccessReview has been verified") 122 123 ginkgo.By(fmt.Sprintf("Creating a LocalSubjectAccessReview for %q", saUsername)) 124 125 lsar := &authorizationv1.LocalSubjectAccessReview{ 126 ObjectMeta: metav1.ObjectMeta{ 127 Namespace: ns, 128 }, 129 Spec: authorizationv1.SubjectAccessReviewSpec{ 130 ResourceAttributes: &authorizationv1.ResourceAttributes{ 131 Verb: "list", 132 Resource: "configmaps", 133 Namespace: ns, 134 Version: "v1", 135 }, 136 User: saName, 137 Groups: saGroups, 138 UID: saUID, 139 }, 140 } 141 142 lsarResponse, err := AuthClient.LocalSubjectAccessReviews(ns).Create(context.TODO(), lsar, metav1.CreateOptions{}) 143 framework.ExpectNoError(err, "Unable to create a LocalSubjectAccessReview, %#v", err) 144 framework.Logf("lsarResponse Status: %#v", lsarResponse.Status) 145 expectedAllowed = lsarResponse.Status.Allowed 146 147 if actuallyAllowed != expectedAllowed { 148 framework.Fail(fmt.Sprintf("Could not verify LocalSubjectAccessReview for %q in namespace %q: LocalSubjectAccessReview allowed: %v, request allowed: %v, request error: %v", saUsername, ns, expectedAllowed, actuallyAllowed, requestErr)) 149 } 150 framework.Logf("LocalSubjectAccessReview has been verified") 151 }) 152 })