k8s.io/kubernetes@v1.29.3/test/integration/authutil/authutil.go (about)

     1  /*
     2  Copyright 2021 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 authutil
    18  
    19  import (
    20  	"context"
    21  	"strings"
    22  	"testing"
    23  	"time"
    24  
    25  	authorizationv1 "k8s.io/api/authorization/v1"
    26  	rbacv1 "k8s.io/api/rbac/v1"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	"k8s.io/apimachinery/pkg/runtime/schema"
    29  	"k8s.io/apimachinery/pkg/util/wait"
    30  	clientset "k8s.io/client-go/kubernetes"
    31  	authorizationv1client "k8s.io/client-go/kubernetes/typed/authorization/v1"
    32  )
    33  
    34  // WaitForNamedAuthorizationUpdate checks if the given user can perform the named verb and action on the named resource.
    35  // Copied from k8s.io/kubernetes/test/e2e/framework/auth.
    36  func WaitForNamedAuthorizationUpdate(t *testing.T, ctx context.Context, c authorizationv1client.SubjectAccessReviewsGetter, user, namespace, verb, resourceName string, resource schema.GroupResource, allowed bool) {
    37  	t.Helper()
    38  
    39  	review := &authorizationv1.SubjectAccessReview{
    40  		Spec: authorizationv1.SubjectAccessReviewSpec{
    41  			ResourceAttributes: &authorizationv1.ResourceAttributes{
    42  				Group:     resource.Group,
    43  				Verb:      verb,
    44  				Resource:  resource.Resource,
    45  				Namespace: namespace,
    46  				Name:      resourceName,
    47  			},
    48  			User: user,
    49  		},
    50  	}
    51  
    52  	if err := wait.Poll(200*time.Millisecond, wait.ForeverTestTimeout, func() (bool, error) {
    53  		response, err := c.SubjectAccessReviews().Create(ctx, review, metav1.CreateOptions{})
    54  		if err != nil {
    55  			return false, err
    56  		}
    57  		if response.Status.Allowed != allowed {
    58  			return false, nil
    59  		}
    60  		return true, nil
    61  	}); err != nil {
    62  		t.Fatal(err)
    63  	}
    64  }
    65  
    66  func GrantUserAuthorization(t *testing.T, ctx context.Context, adminClient clientset.Interface, username string, rule rbacv1.PolicyRule) {
    67  	grantAuthorization(t, ctx, adminClient, username, "", rbacv1.UserKind, rule)
    68  }
    69  
    70  func GrantServiceAccountAuthorization(t *testing.T, ctx context.Context, adminClient clientset.Interface, serviceAccountName, serviceAccountNamespace string, rule rbacv1.PolicyRule) {
    71  	grantAuthorization(t, ctx, adminClient, serviceAccountName, serviceAccountNamespace, rbacv1.ServiceAccountKind, rule)
    72  }
    73  
    74  func grantAuthorization(t *testing.T, ctx context.Context, adminClient clientset.Interface, name, namespace, accountKind string, rule rbacv1.PolicyRule) {
    75  	t.Helper()
    76  
    77  	cr, err := adminClient.RbacV1().ClusterRoles().Create(ctx, &rbacv1.ClusterRole{
    78  		ObjectMeta: metav1.ObjectMeta{GenerateName: strings.Replace(t.Name(), "/", "--", -1)},
    79  		Rules: []rbacv1.PolicyRule{
    80  			rule,
    81  		},
    82  	}, metav1.CreateOptions{})
    83  	if err != nil {
    84  		t.Fatal(err)
    85  	}
    86  	t.Cleanup(func() {
    87  		_ = adminClient.RbacV1().ClusterRoles().Delete(ctx, cr.Name, metav1.DeleteOptions{})
    88  	})
    89  
    90  	crb, err := adminClient.RbacV1().ClusterRoleBindings().Create(ctx, &rbacv1.ClusterRoleBinding{
    91  		ObjectMeta: metav1.ObjectMeta{GenerateName: strings.Replace(t.Name(), "/", "--", -1)},
    92  		Subjects: []rbacv1.Subject{
    93  			{
    94  				Kind: accountKind,
    95  				// APIGroup defaults to the appropriate value for both users and service accounts
    96  				Name:      name,
    97  				Namespace: namespace,
    98  			},
    99  		},
   100  		RoleRef: rbacv1.RoleRef{
   101  			APIGroup: rbacv1.GroupName,
   102  			Kind:     "ClusterRole",
   103  			Name:     cr.Name,
   104  		},
   105  	}, metav1.CreateOptions{})
   106  	if err != nil {
   107  		t.Fatal(err)
   108  	}
   109  	t.Cleanup(func() {
   110  		_ = adminClient.RbacV1().ClusterRoleBindings().Delete(ctx, crb.Name, metav1.DeleteOptions{})
   111  	})
   112  
   113  	var resourceName string
   114  	if len(rule.ResourceNames) > 0 {
   115  		resourceName = rule.ResourceNames[0]
   116  	}
   117  
   118  	subjectName := name
   119  	if accountKind == rbacv1.ServiceAccountKind {
   120  		subjectName = "system:serviceaccount:" + namespace + ":" + name
   121  	}
   122  
   123  	WaitForNamedAuthorizationUpdate(
   124  		t,
   125  		ctx,
   126  		adminClient.AuthorizationV1(),
   127  		subjectName,
   128  		namespace,
   129  		rule.Verbs[0],
   130  		resourceName,
   131  		schema.GroupResource{Group: rule.APIGroups[0], Resource: rule.Resources[0]},
   132  		true,
   133  	)
   134  }