@@ -37,13 +37,23 @@ func (authz *FeastAuthorization) deployKubernetesAuth() error {
3737 if authz .isKubernetesAuth () {
3838 authz .removeOrphanedRoles ()
3939
40+ // Create namespace-scoped RBAC resources
4041 if err := authz .createFeastRole (); err != nil {
4142 return authz .setFeastKubernetesAuthCondition (err )
4243 }
4344 if err := authz .createFeastRoleBinding (); err != nil {
4445 return authz .setFeastKubernetesAuthCondition (err )
4546 }
4647
48+ // Create cluster-scoped RBAC resources (separate from namespace resources)
49+ if err := authz .createFeastClusterRole (); err != nil {
50+ return authz .setFeastKubernetesAuthCondition (err )
51+ }
52+ if err := authz .createFeastClusterRoleBinding (); err != nil {
53+ return authz .setFeastKubernetesAuthCondition (err )
54+ }
55+
56+ // Create custom auth roles
4757 for _ , roleName := range authz .Handler .FeatureStore .Status .Applied .AuthzConfig .KubernetesAuthz .Roles {
4858 if err := authz .createAuthRole (roleName ); err != nil {
4959 return authz .setFeastKubernetesAuthCondition (err )
@@ -89,6 +99,80 @@ func (authz *FeastAuthorization) createFeastRole() error {
8999 return nil
90100}
91101
102+ func (authz * FeastAuthorization ) createFeastClusterRole () error {
103+ logger := log .FromContext (authz .Handler .Context )
104+ clusterRole := authz .initFeastClusterRole ()
105+ if op , err := controllerutil .CreateOrUpdate (authz .Handler .Context , authz .Handler .Client , clusterRole , controllerutil .MutateFn (func () error {
106+ return authz .setFeastClusterRole (clusterRole )
107+ })); err != nil {
108+ return err
109+ } else if op == controllerutil .OperationResultCreated || op == controllerutil .OperationResultUpdated {
110+ logger .Info ("Successfully reconciled" , "ClusterRole" , clusterRole .Name , "operation" , op )
111+ }
112+
113+ return nil
114+ }
115+
116+ func (authz * FeastAuthorization ) initFeastClusterRole () * rbacv1.ClusterRole {
117+ clusterRole := & rbacv1.ClusterRole {
118+ ObjectMeta : metav1.ObjectMeta {Name : authz .getFeastClusterRoleName ()},
119+ }
120+ clusterRole .SetGroupVersionKind (rbacv1 .SchemeGroupVersion .WithKind ("ClusterRole" ))
121+ return clusterRole
122+ }
123+
124+ func (authz * FeastAuthorization ) setFeastClusterRole (clusterRole * rbacv1.ClusterRole ) error {
125+ clusterRole .Labels = authz .getLabels ()
126+ clusterRole .Rules = []rbacv1.PolicyRule {
127+ {
128+ APIGroups : []string {rbacv1 .GroupName },
129+ Resources : []string {"rolebindings" },
130+ Verbs : []string {"list" },
131+ },
132+ }
133+ return nil
134+ }
135+
136+ func (authz * FeastAuthorization ) initFeastClusterRoleBinding () * rbacv1.ClusterRoleBinding {
137+ clusterRoleBinding := & rbacv1.ClusterRoleBinding {
138+ ObjectMeta : metav1.ObjectMeta {Name : authz .getFeastClusterRoleBindingName ()},
139+ }
140+ clusterRoleBinding .SetGroupVersionKind (rbacv1 .SchemeGroupVersion .WithKind ("ClusterRoleBinding" ))
141+ return clusterRoleBinding
142+ }
143+
144+ func (authz * FeastAuthorization ) setFeastClusterRoleBinding (clusterRoleBinding * rbacv1.ClusterRoleBinding ) error {
145+ clusterRoleBinding .Labels = authz .getLabels ()
146+ clusterRoleBinding .Subjects = []rbacv1.Subject {
147+ {
148+ Kind : "ServiceAccount" ,
149+ Name : authz .getFeastServiceAccountName (),
150+ Namespace : authz .Handler .FeatureStore .Namespace ,
151+ },
152+ }
153+ clusterRoleBinding .RoleRef = rbacv1.RoleRef {
154+ APIGroup : rbacv1 .GroupName ,
155+ Kind : "ClusterRole" ,
156+ Name : authz .getFeastClusterRoleName (),
157+ }
158+ return nil
159+ }
160+
161+ // Create ClusterRoleBinding
162+ func (authz * FeastAuthorization ) createFeastClusterRoleBinding () error {
163+ logger := log .FromContext (authz .Handler .Context )
164+ clusterRoleBinding := authz .initFeastClusterRoleBinding ()
165+ if op , err := controllerutil .CreateOrUpdate (authz .Handler .Context , authz .Handler .Client , clusterRoleBinding , controllerutil .MutateFn (func () error {
166+ return authz .setFeastClusterRoleBinding (clusterRoleBinding )
167+ })); err != nil {
168+ return err
169+ } else if op == controllerutil .OperationResultCreated || op == controllerutil .OperationResultUpdated {
170+ logger .Info ("Successfully reconciled" , "ClusterRoleBinding" , clusterRoleBinding .Name , "operation" , op )
171+ }
172+
173+ return nil
174+ }
175+
92176func (authz * FeastAuthorization ) initFeastRole () * rbacv1.Role {
93177 role := & rbacv1.Role {
94178 ObjectMeta : metav1.ObjectMeta {Name : authz .getFeastRoleName (), Namespace : authz .Handler .FeatureStore .Namespace },
@@ -230,3 +314,23 @@ func (authz *FeastAuthorization) getFeastRoleName() string {
230314func GetFeastRoleName (featureStore * feastdevv1alpha1.FeatureStore ) string {
231315 return services .GetFeastName (featureStore )
232316}
317+
318+ func (authz * FeastAuthorization ) getFeastClusterRoleName () string {
319+ return GetFeastClusterRoleName (authz .Handler .FeatureStore )
320+ }
321+
322+ func GetFeastClusterRoleName (featureStore * feastdevv1alpha1.FeatureStore ) string {
323+ return services .GetFeastName (featureStore ) + "-cluster"
324+ }
325+
326+ func (authz * FeastAuthorization ) getFeastClusterRoleBindingName () string {
327+ return GetFeastClusterRoleBindingName (authz .Handler .FeatureStore )
328+ }
329+
330+ func GetFeastClusterRoleBindingName (featureStore * feastdevv1alpha1.FeatureStore ) string {
331+ return services .GetFeastName (featureStore ) + "-cluster-binding"
332+ }
333+
334+ func (authz * FeastAuthorization ) getFeastServiceAccountName () string {
335+ return services .GetFeastName (authz .Handler .FeatureStore )
336+ }
0 commit comments