1
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
35
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
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 }
135
View as plain text