Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .github/workflows/operator_pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,16 @@ jobs:
run: make -C infra/feast-operator test
- name: After code formatting, check for uncommitted differences
run: git diff --exit-code infra/feast-operator
- name: Regenerate bundle and verify CSV is in sync
run: make -C infra/feast-operator bundle
- name: Check for uncommitted bundle differences
run: |
# createdAt and operator-sdk builder version change every run;
# ignore them so only real RBAC / structural drift fails the check.
if ! git diff --exit-code \
-I 'createdAt:' \
-I 'operator-sdk-v' \
infra/feast-operator/bundle/ infra/feast-operator/bundle.Dockerfile; then
echo "::error::Bundle manifests are out of sync. Run 'make bundle' in infra/feast-operator/ and commit the result."
exit 1
fi
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ metadata:
}
]
capabilities: Basic Install
createdAt: "2026-07-31T18:28:04Z"
createdAt: "2026-08-18T16:15:46Z"
operators.operatorframework.io/builder: operator-sdk-v1.41.0
operators.operatorframework.io/project_layout: go.kubebuilder.io/v4
name: feast-operator.v0.65.0
Expand Down Expand Up @@ -342,10 +342,36 @@ spec:
- rbac.authorization.k8s.io
resources:
- clusterrolebindings
verbs:
- create
- delete
- get
- list
- update
- apiGroups:
- rbac.authorization.k8s.io
resources:
- clusterroles
verbs:
- create
- get
- list
- apiGroups:
- rbac.authorization.k8s.io
resourceNames:
- feast-discover-namespaces
- feast-oidc-token-review
- feast-token-review-cluster-role
resources:
- clusterroles
verbs:
- delete
- update
- apiGroups:
- rbac.authorization.k8s.io
resources:
- rolebindings
- roles
- subjectaccessreviews
verbs:
- create
- delete
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@ spec:
type: object
noAuth:
description: NoAuth explicitly disables authentication and authorization.
When set to true, Feast services run without any auth checks.
Use only for development or testing environments.
type: boolean
oidc:
description: |-
Expand Down Expand Up @@ -6458,8 +6456,7 @@ spec:
type: object
noAuth:
description: NoAuth explicitly disables authentication and
authorization. When set to true, Feast services run without
any auth checks. Use only for development or testing environments.
authorization.
type: boolean
oidc:
description: |-
Expand Down Expand Up @@ -13065,8 +13062,6 @@ spec:
type: object
noAuth:
description: NoAuth explicitly disables authentication and authorization.
When set to true, Feast services run without any auth checks.
Use only for development or testing environments.
type: boolean
oidc:
description: |-
Expand Down Expand Up @@ -17581,8 +17576,7 @@ spec:
type: object
noAuth:
description: NoAuth explicitly disables authentication and
authorization. When set to true, Feast services run without
any auth checks. Use only for development or testing environments.
authorization.
type: boolean
oidc:
description: |-
Expand Down
50 changes: 29 additions & 21 deletions infra/feast-operator/internal/controller/authz/authz.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import (
feastdevv1 "github.com/feast-dev/feast/infra/feast-operator/api/v1"
"github.com/feast-dev/feast/infra/feast-operator/internal/controller/services"
rbacv1 "k8s.io/api/rbac/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/util/retry"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/log"
Expand Down Expand Up @@ -146,17 +146,21 @@ func (authz *FeastAuthorization) createFeastRole() error {

func (authz *FeastAuthorization) createFeastClusterRole() error {
logger := log.FromContext(authz.Handler.Context)
return retry.RetryOnConflict(retry.DefaultRetry, func() error {
clusterRole := authz.initFeastClusterRole()
if op, err := controllerutil.CreateOrUpdate(authz.Handler.Context, authz.Handler.Client, clusterRole, controllerutil.MutateFn(func() error {
return authz.setFeastClusterRole(clusterRole)
})); err != nil {
return err
} else if op == controllerutil.OperationResultCreated || op == controllerutil.OperationResultUpdated {
logger.Info("Successfully reconciled", "ClusterRole", clusterRole.Name, "operation", op)
}
clusterRole := authz.initFeastClusterRole()
op, err := controllerutil.CreateOrUpdate(authz.Handler.Context, authz.Handler.Client, clusterRole, controllerutil.MutateFn(func() error {
return authz.setFeastClusterRole(clusterRole)
}))
if apierrors.IsAlreadyExists(err) || apierrors.IsConflict(err) {
logger.Info("ClusterRole conflict or already exists, will reconcile on next cycle", "ClusterRole", clusterRole.Name, "error", err)
return nil
})
}
if err != nil {
return err
}
if op == controllerutil.OperationResultCreated || op == controllerutil.OperationResultUpdated {
logger.Info("Successfully reconciled", "ClusterRole", clusterRole.Name, "operation", op)
}
return nil
}

func (authz *FeastAuthorization) initFeastClusterRole() *rbacv1.ClusterRole {
Expand Down Expand Up @@ -228,17 +232,21 @@ func (authz *FeastAuthorization) setFeastClusterRoleBinding(clusterRoleBinding *
// Create ClusterRoleBinding
func (authz *FeastAuthorization) createFeastClusterRoleBinding() error {
logger := log.FromContext(authz.Handler.Context)
return retry.RetryOnConflict(retry.DefaultRetry, func() error {
clusterRoleBinding := authz.initFeastClusterRoleBinding()
if op, err := controllerutil.CreateOrUpdate(authz.Handler.Context, authz.Handler.Client, clusterRoleBinding, controllerutil.MutateFn(func() error {
return authz.setFeastClusterRoleBinding(clusterRoleBinding)
})); err != nil {
return err
} else if op == controllerutil.OperationResultCreated || op == controllerutil.OperationResultUpdated {
logger.Info("Successfully reconciled", "ClusterRoleBinding", clusterRoleBinding.Name, "operation", op)
}
clusterRoleBinding := authz.initFeastClusterRoleBinding()
op, err := controllerutil.CreateOrUpdate(authz.Handler.Context, authz.Handler.Client, clusterRoleBinding, controllerutil.MutateFn(func() error {
return authz.setFeastClusterRoleBinding(clusterRoleBinding)
}))
if apierrors.IsAlreadyExists(err) || apierrors.IsConflict(err) {
logger.Info("ClusterRoleBinding conflict or already exists, will reconcile on next cycle", "ClusterRoleBinding", clusterRoleBinding.Name, "error", err)
return nil
})
}
if err != nil {
return err
}
if op == controllerutil.OperationResultCreated || op == controllerutil.OperationResultUpdated {
logger.Info("Successfully reconciled", "ClusterRoleBinding", clusterRoleBinding.Name, "operation", op)
}
return nil
}

func (authz *FeastAuthorization) initFeastRole() *rbacv1.Role {
Expand Down
Loading