Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ spec:
{{- with .Values.operator.disableComponentControllers }}
- --disable-component-controllers={{ . }}
{{- end }}
{{- with .Values.operator.watchNamespaces }}
- {{ printf "--watch-namespaces=%s" . | quote }}
{{- end }}
{{- with .Values.operator.livenessProbe }}
livenessProbe:
{{- toYaml . | nindent 10 }}
Expand Down
4 changes: 4 additions & 0 deletions charts/fluent-operator/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ operator:
# myExampleLabel: someValue
# -- Disable specific component controllers. Value can be "fluent-bit" or "fluentd" to disable that controller
disableComponentControllers: ""
# -- Comma separated list of namespaces the operator should watch and manage resources in. When set, the
# operator scopes its cache and creates namespaced Roles/RoleBindings (instead of cluster-wide) for the
# agents it manages, allowing the operator's own RBAC to be reduced. Defaults to cluster scope when empty.
watchNamespaces: ""
# -- Extra arguments for the Fluent Operator controller
extraArgs:
[]
Expand Down
14 changes: 8 additions & 6 deletions cmd/fluent-manager/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,10 @@ func main() {
}

if err = (&controllers.CollectorReconciler{
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("Collector"),
Scheme: mgr.GetScheme(),
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("Collector"),
Scheme: mgr.GetScheme(),
Namespaced: namespacedController,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Collector")
os.Exit(1)
Expand Down Expand Up @@ -266,9 +267,10 @@ func main() {
}

if err = (&controllers.FluentdReconciler{
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("Fluentd"),
Scheme: mgr.GetScheme(),
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("Fluentd"),
Scheme: mgr.GetScheme(),
Namespaced: namespacedController,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Fluentd")
os.Exit(1)
Expand Down
2 changes: 1 addition & 1 deletion config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ rules:
resources:
- clusterrolebindings
- clusterroles
- roles
verbs:
- create
- get
Expand All @@ -133,7 +134,6 @@ rules:
- rbac.authorization.k8s.io
resources:
- rolebindings
- roles
verbs:
- create
- delete
Expand Down
56 changes: 46 additions & 10 deletions controllers/collector_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ import (
// CollectorReconciler reconciles a FluentBit object
type CollectorReconciler struct {
client.Client
Log logr.Logger
Scheme *runtime.Scheme
Log logr.Logger
Scheme *runtime.Scheme
Namespaced bool
}

// +kubebuilder:rbac:groups=fluentbit.fluent.io,resources=collectors,verbs=get;list;watch;update
Expand All @@ -49,6 +50,8 @@ type CollectorReconciler struct {
// +kubebuilder:rbac:groups=core,resources=services,verbs=get;list;watch;create;patch;delete
// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=clusterroles,verbs=create;get;list;watch;patch
// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=clusterrolebindings,verbs=create;get;list;watch;patch
// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=roles,verbs=create;get;list;watch;patch
// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=rolebindings,verbs=create;delete;get;list;watch;patch
// +kubebuilder:rbac:groups=core,resources=pods,verbs=get

// Reconcile is part of the main kubernetes reconciliation loop which aims to
Expand Down Expand Up @@ -95,23 +98,21 @@ func (r *CollectorReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
return ctrl.Result{}, err
}

// Install RBAC resources for the filter plugin kubernetes
cr, sa, crb := operator.MakeRBACObjects(
// Reconcile the RBAC the agent needs, scoped to a namespace or the cluster.
role, sa, binding := operator.MakeRBACObjectsForScope(
r.Namespaced,
co.Name,
co.Namespace,
"collector",
co.Spec.RBACRules,
co.Spec.ServiceAccountAnnotations,
)
// Deploy Fluent Bit Collector ClusterRole
if _, err := controllerutil.CreateOrPatch(ctx, r.Client, cr, r.mutate(cr, &co)); err != nil {
if _, err := controllerutil.CreateOrPatch(ctx, r.Client, role, r.mutate(role, &co)); err != nil {
return ctrl.Result{}, err
}
// Deploy Fluent Bit Collector ClusterRoleBinding
if _, err := controllerutil.CreateOrPatch(ctx, r.Client, crb, r.mutate(crb, &co)); err != nil {
if _, err := controllerutil.CreateOrPatch(ctx, r.Client, binding, r.mutate(binding, &co)); err != nil {
return ctrl.Result{}, err
}
// Deploy Fluent Bit Collector ServiceAccount
if _, err := controllerutil.CreateOrPatch(ctx, r.Client, sa, r.mutate(sa, &co)); err != nil {
return ctrl.Result{}, err
}
Expand Down Expand Up @@ -175,6 +176,36 @@ func (r *CollectorReconciler) mutate(obj client.Object, co *fluentbitv1alpha2.Co
o.Subjects = expected.Subjects
return nil
}
case *rbacv1.Role:
// The Role is shared across all Collector instances in the namespace, so
// no per-instance controller reference is set on it.
expected, _, _ := operator.MakeScopedRBACObjects(co.Name,
co.Namespace,
"collector",
co.Spec.RBACRules,
co.Spec.ServiceAccountAnnotations,
)

return func() error {
o.Rules = expected.Rules
return nil
}
case *rbacv1.RoleBinding:
_, _, expected := operator.MakeScopedRBACObjects(co.Name,
co.Namespace,
"collector",
co.Spec.RBACRules,
co.Spec.ServiceAccountAnnotations,
)

return func() error {
o.RoleRef = expected.RoleRef
o.Subjects = expected.Subjects
if err := ctrl.SetControllerReference(co, o, r.Scheme); err != nil {
return err
}
return nil
}
case *appsv1.StatefulSet:
expected := operator.MakefbStatefulset(*co)

Expand Down Expand Up @@ -214,7 +245,12 @@ func (r *CollectorReconciler) delete(ctx context.Context, co *fluentbitv1alpha2.
if err := r.Delete(ctx, &sa); err != nil && !errors.IsNotFound(err) {
return err
}
// TODO: clusterrole, clusterrolebinding

if err := operator.DeletePerInstanceBinding(
ctx, r.Client, r.Namespaced, co.Name, co.Namespace, "collector",
); err != nil {
return err
}

sts := appsv1.StatefulSet{
ObjectMeta: metav1.ObjectMeta{
Expand Down
39 changes: 38 additions & 1 deletion controllers/fluent_controller_finalizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,12 @@ func (r *FluentdReconciler) delete(ctx context.Context, fd *fluentdv1alpha1.Flue
if err := r.Delete(ctx, &sa); err != nil && !errors.IsNotFound(err) {
return err
}
// TODO: clusterrole, clusterrolebinding

if err := operator.DeletePerInstanceBinding(
ctx, r.Client, r.Namespaced, fd.Name, fd.Namespace, "fluentd",
); err != nil {
return err
}

sts := appsv1.StatefulSet{
ObjectMeta: metav1.ObjectMeta{
Expand Down Expand Up @@ -157,6 +162,38 @@ func (r *FluentdReconciler) mutate(obj client.Object, fd *fluentdv1alpha1.Fluent
o.Subjects = expected.Subjects
return nil
}
case *rbacv1.Role:
// The Role is shared across all Fluentd instances in the namespace, so
// no per-instance controller reference is set on it.
expected, _, _ := operator.MakeScopedRBACObjects(
fd.Name,
fd.Namespace,
"fluentd",
fd.Spec.RBACRules,
fd.Spec.ServiceAccountAnnotations,
)

return func() error {
o.Rules = expected.Rules
return nil
}
case *rbacv1.RoleBinding:
_, _, expected := operator.MakeScopedRBACObjects(
fd.Name,
fd.Namespace,
"fluentd",
fd.Spec.RBACRules,
fd.Spec.ServiceAccountAnnotations,
)

return func() error {
o.RoleRef = expected.RoleRef
o.Subjects = expected.Subjects
if err := ctrl.SetControllerReference(fd, o, r.Scheme); err != nil {
return err
}
return nil
}
case *appsv1.StatefulSet:
expected := operator.MakeStatefulSet(*fd)

Expand Down
83 changes: 37 additions & 46 deletions controllers/fluentbit_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ type FluentBitReconciler struct {
// +kubebuilder:rbac:groups=core,resources=services,verbs=get;list;watch;create;patch;delete
// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=clusterroles,verbs=create;get;list;watch;patch
// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=clusterrolebindings,verbs=create;get;list;watch;patch
// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=roles,verbs=create;delete;get;list;watch;patch
// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=roles,verbs=create;get;list;watch;patch
// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=rolebindings,verbs=create;delete;get;list;watch;patch
// +kubebuilder:rbac:groups=core,resources=pods,verbs=get

Expand Down Expand Up @@ -100,23 +100,15 @@ func (r *FluentBitReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
return ctrl.Result{}, err
}

// Install RBAC resources for the filter plugin kubernetes
var role, sa, binding client.Object
if r.Namespaced {
role, sa, binding = operator.MakeScopedRBACObjects(
fb.Name,
fb.Namespace,
fb.Spec.ServiceAccountAnnotations,
)
} else {
role, sa, binding = operator.MakeRBACObjects(
fb.Name,
fb.Namespace,
"fluent-bit",
fb.Spec.RBACRules,
fb.Spec.ServiceAccountAnnotations,
)
}
// Reconcile the RBAC the agent needs, scoped to a namespace or the cluster.
role, sa, binding := operator.MakeRBACObjectsForScope(
r.Namespaced,
fb.Name,
fb.Namespace,
"fluent-bit",
fb.Spec.RBACRules,
fb.Spec.ServiceAccountAnnotations,
)
if _, err := controllerutil.CreateOrPatch(ctx, r.Client, role, r.mutate(role, &fb)); err != nil {
return ctrl.Result{}, err
}
Expand Down Expand Up @@ -197,13 +189,18 @@ func (r *FluentBitReconciler) mutate(obj client.Object, fb *fluentbitv1alpha2.Fl
return nil
}
case *rbacv1.Role:
expected, _, _ := operator.MakeScopedRBACObjects(fb.Name, fb.Namespace, fb.Spec.ServiceAccountAnnotations)
// The Role is shared across all FluentBit instances in the namespace, so
// no per-instance controller reference is set on it.
expected, _, _ := operator.MakeScopedRBACObjects(
fb.Name,
fb.Namespace,
"fluent-bit",
fb.Spec.RBACRules,
fb.Spec.ServiceAccountAnnotations,
)

return func() error {
o.Rules = expected.Rules
if err := ctrl.SetControllerReference(fb, o, r.Scheme); err != nil {
return err
}
return nil
}
case *rbacv1.ClusterRole:
Expand All @@ -218,7 +215,13 @@ func (r *FluentBitReconciler) mutate(obj client.Object, fb *fluentbitv1alpha2.Fl
return nil
}
case *corev1.ServiceAccount:
_, expected, _ := operator.MakeScopedRBACObjects(fb.Name, fb.Namespace, fb.Spec.ServiceAccountAnnotations)
_, expected, _ := operator.MakeScopedRBACObjects(
fb.Name,
fb.Namespace,
"fluent-bit",
fb.Spec.RBACRules,
fb.Spec.ServiceAccountAnnotations,
)

return func() error {
o.Annotations = expected.Annotations
Expand All @@ -228,7 +231,13 @@ func (r *FluentBitReconciler) mutate(obj client.Object, fb *fluentbitv1alpha2.Fl
return nil
}
case *rbacv1.RoleBinding:
_, _, expected := operator.MakeScopedRBACObjects(fb.Name, fb.Namespace, fb.Spec.ServiceAccountAnnotations)
_, _, expected := operator.MakeScopedRBACObjects(
fb.Name,
fb.Namespace,
"fluent-bit",
fb.Spec.RBACRules,
fb.Spec.ServiceAccountAnnotations,
)
return func() error {
o.Subjects = expected.Subjects
o.RoleRef = expected.RoleRef
Expand Down Expand Up @@ -267,29 +276,11 @@ func (r *FluentBitReconciler) delete(ctx context.Context, fb *fluentbitv1alpha2.
return err
}

if r.Namespaced {
roleName, _, roleBindingName := operator.MakeScopedRBACNames(fb.Name)
role := rbacv1.Role{
ObjectMeta: metav1.ObjectMeta{
Name: roleName,
Namespace: fb.Namespace,
},
}
if err := r.Delete(ctx, &role); err != nil && !errors.IsNotFound(err) {
return err
}

rolebinding := rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: roleBindingName,
Namespace: fb.Namespace,
},
}
if err := r.Delete(ctx, &rolebinding); err != nil && !errors.IsNotFound(err) {
return err
}
if err := operator.DeletePerInstanceBinding(
ctx, r.Client, r.Namespaced, fb.Name, fb.Namespace, "fluent-bit",
); err != nil {
return err
}
// TODO: clusterrole, clusterrolebinding

ds := appsv1.DaemonSet{
ObjectMeta: metav1.ObjectMeta{
Expand Down
19 changes: 10 additions & 9 deletions controllers/fluentd_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ const (
// FluentdReconciler reconciles a Fluentd object
type FluentdReconciler struct {
client.Client
Log logr.Logger
Scheme *runtime.Scheme
Log logr.Logger
Scheme *runtime.Scheme
Namespaced bool
}

// +kubebuilder:rbac:groups=fluentd.fluent.io,resources=fluentds,verbs=get;list;watch;update
Expand All @@ -54,6 +55,8 @@ type FluentdReconciler struct {
// +kubebuilder:rbac:groups=core,resources=secrets,verbs=get
// +kubebuilder:rbac:groups=core,resources=serviceaccounts;services,verbs=get;list;watch;create;patch;delete
// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=clusterroles;clusterrolebindings,verbs=create;get;list;watch;patch
// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=roles,verbs=create;get;list;watch;patch
// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=rolebindings,verbs=create;delete;get;list;watch;patch

// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
Expand Down Expand Up @@ -99,23 +102,21 @@ func (r *FluentdReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
return ctrl.Result{}, err
}

// Install RBAC resources for the filter plugin kubernetes
cr, sa, crb := operator.MakeRBACObjects(
// Reconcile the RBAC the agent needs, scoped to a namespace or the cluster.
role, sa, binding := operator.MakeRBACObjectsForScope(
r.Namespaced,
fd.Name,
fd.Namespace,
fluentdLowercase,
fd.Spec.RBACRules,
fd.Spec.ServiceAccountAnnotations,
)
// Deploy Fluentd ClusterRole
if _, err := controllerutil.CreateOrPatch(ctx, r.Client, cr, r.mutate(cr, &fd)); err != nil {
if _, err := controllerutil.CreateOrPatch(ctx, r.Client, role, r.mutate(role, &fd)); err != nil {
return ctrl.Result{}, err
}
// Deploy Fluentd ClusterRoleBinding
if _, err := controllerutil.CreateOrPatch(ctx, r.Client, crb, r.mutate(crb, &fd)); err != nil {
if _, err := controllerutil.CreateOrPatch(ctx, r.Client, binding, r.mutate(binding, &fd)); err != nil {
return ctrl.Result{}, err
}
// Deploy Fluentd ServiceAccount
if _, err := controllerutil.CreateOrPatch(ctx, r.Client, sa, r.mutate(sa, &fd)); err != nil {
return ctrl.Result{}, err
}
Expand Down
Loading
Loading