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  })