1
16
17 package auth
18
19 import (
20 "context"
21 "fmt"
22 "sync"
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 v1authorization "k8s.io/client-go/kubernetes/typed/authorization/v1"
31 v1rbac "k8s.io/client-go/kubernetes/typed/rbac/v1"
32 "k8s.io/kubernetes/test/e2e/framework"
33 )
34
35 const (
36 policyCachePollInterval = 100 * time.Millisecond
37 policyCachePollTimeout = 5 * time.Second
38 )
39
40 type bindingsGetter interface {
41 v1rbac.RoleBindingsGetter
42 v1rbac.ClusterRoleBindingsGetter
43 v1rbac.ClusterRolesGetter
44 }
45
46
47
48 func WaitForAuthorizationUpdate(ctx context.Context, c v1authorization.SubjectAccessReviewsGetter, user, namespace, verb string, resource schema.GroupResource, allowed bool) error {
49 return WaitForNamedAuthorizationUpdate(ctx, c, user, namespace, verb, "", resource, allowed)
50 }
51
52
53
54 func WaitForNamedAuthorizationUpdate(ctx context.Context, c v1authorization.SubjectAccessReviewsGetter, user, namespace, verb, resourceName string, resource schema.GroupResource, allowed bool) error {
55 review := &authorizationv1.SubjectAccessReview{
56 Spec: authorizationv1.SubjectAccessReviewSpec{
57 ResourceAttributes: &authorizationv1.ResourceAttributes{
58 Group: resource.Group,
59 Verb: verb,
60 Resource: resource.Resource,
61 Namespace: namespace,
62 Name: resourceName,
63 },
64 User: user,
65 },
66 }
67
68 err := wait.PollWithContext(ctx, policyCachePollInterval, policyCachePollTimeout, func(ctx context.Context) (bool, error) {
69 response, err := c.SubjectAccessReviews().Create(ctx, review, metav1.CreateOptions{})
70 if err != nil {
71 return false, err
72 }
73 if response.Status.Allowed != allowed {
74 return false, nil
75 }
76 return true, nil
77 })
78 return err
79 }
80
81
82
83 func BindClusterRole(ctx context.Context, c bindingsGetter, clusterRole, ns string, subjects ...rbacv1.Subject) error {
84 if !IsRBACEnabled(ctx, c) {
85 return nil
86 }
87
88
89 _, err := c.ClusterRoleBindings().Create(ctx, &rbacv1.ClusterRoleBinding{
90 ObjectMeta: metav1.ObjectMeta{
91 Name: ns + "--" + clusterRole,
92 },
93 RoleRef: rbacv1.RoleRef{
94 APIGroup: "rbac.authorization.k8s.io",
95 Kind: "ClusterRole",
96 Name: clusterRole,
97 },
98 Subjects: subjects,
99 }, metav1.CreateOptions{})
100
101 if err != nil {
102 return fmt.Errorf("binding clusterrole/%s for %q for %v: %w", clusterRole, ns, subjects, err)
103 }
104
105 return nil
106 }
107
108
109
110 func BindClusterRoleInNamespace(ctx context.Context, c bindingsGetter, clusterRole, ns string, subjects ...rbacv1.Subject) error {
111 return bindInNamespace(ctx, c, "ClusterRole", clusterRole, ns, subjects...)
112 }
113
114
115
116 func BindRoleInNamespace(ctx context.Context, c bindingsGetter, role, ns string, subjects ...rbacv1.Subject) error {
117 return bindInNamespace(ctx, c, "Role", role, ns, subjects...)
118 }
119
120 func bindInNamespace(ctx context.Context, c bindingsGetter, roleType, role, ns string, subjects ...rbacv1.Subject) error {
121 if !IsRBACEnabled(ctx, c) {
122 return nil
123 }
124
125
126 _, err := c.RoleBindings(ns).Create(ctx, &rbacv1.RoleBinding{
127 ObjectMeta: metav1.ObjectMeta{
128 Name: ns + "--" + role,
129 },
130 RoleRef: rbacv1.RoleRef{
131 APIGroup: "rbac.authorization.k8s.io",
132 Kind: roleType,
133 Name: role,
134 },
135 Subjects: subjects,
136 }, metav1.CreateOptions{})
137
138 if err != nil {
139 return fmt.Errorf("binding %s/%s into %q for %v: %w", roleType, role, ns, subjects, err)
140 }
141
142 return nil
143 }
144
145 var (
146 isRBACEnabledOnce sync.Once
147 isRBACEnabled bool
148 )
149
150
151 func IsRBACEnabled(ctx context.Context, crGetter v1rbac.ClusterRolesGetter) bool {
152 isRBACEnabledOnce.Do(func() {
153 crs, err := crGetter.ClusterRoles().List(ctx, metav1.ListOptions{})
154 if err != nil {
155 framework.Logf("Error listing ClusterRoles; assuming RBAC is disabled: %v", err)
156 isRBACEnabled = false
157 } else if crs == nil || len(crs.Items) == 0 {
158 framework.Logf("No ClusterRoles found; assuming RBAC is disabled.")
159 isRBACEnabled = false
160 } else {
161 framework.Logf("Found ClusterRoles; assuming RBAC is enabled.")
162 isRBACEnabled = true
163 }
164 })
165
166 return isRBACEnabled
167 }
168
View as plain text