diff --git a/pkg/controller/association/controller/apm_es.go b/pkg/controller/association/controller/apm_es.go index aed115b9af..6c564ccabf 100644 --- a/pkg/controller/association/controller/apm_es.go +++ b/pkg/controller/association/controller/apm_es.go @@ -5,15 +5,18 @@ package controller import ( - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/manager" + "strings" apmv1 "github.com/elastic/cloud-on-k8s/pkg/apis/apm/v1" commonv1 "github.com/elastic/cloud-on-k8s/pkg/apis/common/v1" "github.com/elastic/cloud-on-k8s/pkg/controller/association" "github.com/elastic/cloud-on-k8s/pkg/controller/common/operator" - esuser "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/user" + "github.com/elastic/cloud-on-k8s/pkg/controller/common/version" + "github.com/elastic/cloud-on-k8s/pkg/controller/elasticsearch/user" "github.com/elastic/cloud-on-k8s/pkg/utils/rbac" + pkgerrors "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/manager" ) const ( @@ -35,6 +38,47 @@ func AddApmES(mgr manager.Manager, accessReviewer rbac.AccessReviewer, params op } }, UserSecretSuffix: "apm-user", - ESUserRole: esuser.SuperUserBuiltinRole, + ESUserRole: getRoles, }) } + +// getRoles returns for a given version of the APM Server the set of required roles. +func getRoles(associated commonv1.Associated) (string, error) { + apmServer, ok := associated.(*apmv1.ApmServer) + if !ok { + return "", pkgerrors.Errorf( + "ApmServer expected, got %s/%s", + associated.GetObjectKind().GroupVersionKind().Group, + associated.GetObjectKind().GroupVersionKind().Kind, + ) + } + + v, err := version.Parse(apmServer.Spec.Version) + if err != nil { + return "", err + } + + // 7.5.x and above + if v.IsSameOrAfter(version.From(7, 5, 0)) { + return strings.Join([]string{ + user.ApmUserRoleV75, // Retrieve cluster details (e.g. version) and manage apm-* indices + "ingest_admin", // Set up index templates + "apm_system", // To collect metrics about APM Server + }, ","), nil + } + + // 7.1.x to 7.4.x + if v.IsSameOrAfter(version.From(7, 1, 0)) { + return strings.Join([]string{ + user.ApmUserRoleV7, // Retrieve cluster details (e.g. version) and manage apm-* indices + "ingest_admin", // Set up index templates + "apm_system", // To collect metrics about APM Server + }, ","), nil + } + + // 6.8 + return strings.Join([]string{ + user.ApmUserRoleV6, // Retrieve cluster details (e.g. version) and manage apm-* indices + "apm_system", // To collect metrics about APM Server + }, ","), nil +} diff --git a/pkg/controller/association/controller/apm_es_test.go b/pkg/controller/association/controller/apm_es_test.go new file mode 100644 index 0000000000..794b3c857f --- /dev/null +++ b/pkg/controller/association/controller/apm_es_test.go @@ -0,0 +1,91 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package controller + +import ( + "testing" + + apmv1 "github.com/elastic/cloud-on-k8s/pkg/apis/apm/v1" + commonv1 "github.com/elastic/cloud-on-k8s/pkg/apis/common/v1" +) + +func Test_getRoles(t *testing.T) { + type args struct { + associated commonv1.Associated + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "Test roles for APM Server v6.8.0", + args: args{ + associated: &apmv1.ApmServer{ + Spec: apmv1.ApmServerSpec{Version: "6.8.0"}, + }, + }, + want: "eck_apm_user_role_v6,apm_system", + }, + { + name: "Test roles for APM Server v6.8.99", + args: args{ + associated: &apmv1.ApmServer{ + Spec: apmv1.ApmServerSpec{Version: "6.8.99"}, + }, + }, + want: "eck_apm_user_role_v6,apm_system", + }, + { + name: "Test roles for APM Server v7.1.0", + args: args{ + associated: &apmv1.ApmServer{ + Spec: apmv1.ApmServerSpec{Version: "7.1.0"}, + }, + }, + want: "eck_apm_user_role_v7,ingest_admin,apm_system", + }, + { + name: "Test roles for APM Server v7.4.99", + args: args{ + associated: &apmv1.ApmServer{ + Spec: apmv1.ApmServerSpec{Version: "7.4.99"}, + }, + }, + want: "eck_apm_user_role_v7,ingest_admin,apm_system", + }, + { + name: "Test roles for APM Server v7.5.0", + args: args{ + associated: &apmv1.ApmServer{ + Spec: apmv1.ApmServerSpec{Version: "7.5.0"}, + }, + }, + want: "eck_apm_user_role_v75,ingest_admin,apm_system", + }, + { + name: "Test roles for APM Server v7.7.99", + args: args{ + associated: &apmv1.ApmServer{ + Spec: apmv1.ApmServerSpec{Version: "7.7.99"}, + }, + }, + want: "eck_apm_user_role_v75,ingest_admin,apm_system", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := getRoles(tt.args.associated) + if (err != nil) != tt.wantErr { + t.Errorf("getRoles() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("getRoles() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/controller/association/controller/ent_es.go b/pkg/controller/association/controller/ent_es.go index ddd117f429..6c508de889 100644 --- a/pkg/controller/association/controller/ent_es.go +++ b/pkg/controller/association/controller/ent_es.go @@ -35,6 +35,8 @@ func AddEntES(mgr manager.Manager, accessReviewer rbac.AccessReviewer, params op } }, UserSecretSuffix: "ent-user", - ESUserRole: esuser.SuperUserBuiltinRole, + ESUserRole: func(_ commonv1.Associated) (string, error) { + return esuser.SuperUserBuiltinRole, nil + }, }) } diff --git a/pkg/controller/association/controller/kibana_es.go b/pkg/controller/association/controller/kibana_es.go index 191fa7deb9..4a7986634f 100644 --- a/pkg/controller/association/controller/kibana_es.go +++ b/pkg/controller/association/controller/kibana_es.go @@ -37,6 +37,8 @@ func AddKibanaES(mgr manager.Manager, accessReviewer rbac.AccessReviewer, params } }, UserSecretSuffix: "kibana-user", - ESUserRole: KibanaSystemUserBuiltinRole, + ESUserRole: func(associated commonv1.Associated) (string, error) { + return KibanaSystemUserBuiltinRole, nil + }, }) } diff --git a/pkg/controller/association/reconciler.go b/pkg/controller/association/reconciler.go index d9c3d53e8a..27d6c28ed6 100644 --- a/pkg/controller/association/reconciler.go +++ b/pkg/controller/association/reconciler.go @@ -53,7 +53,7 @@ type AssociationInfo struct { // UserSecretSuffix is used as a suffix in the name of the secret holding user data in the associated namespace. UserSecretSuffix string // ESUserRole is the role to use for the Elasticsearch user created by the association. - ESUserRole string + ESUserRole func(commonv1.Associated) (string, error) } // userLabelSelector returns labels selecting the ES user secret, including association labels and user type label. @@ -177,12 +177,17 @@ func (r *Reconciler) doReconcile(ctx context.Context, associated commonv1.Associ return commonv1.AssociationFailed, err } + userRole, err := r.ESUserRole(associated) + if err != nil { + return commonv1.AssociationFailed, err + } + if err := ReconcileEsUser( ctx, r.Client, associated, assocLabels, - r.ESUserRole, + userRole, r.UserSecretSuffix, es, ); err != nil { diff --git a/pkg/controller/association/reconciler_test.go b/pkg/controller/association/reconciler_test.go index 3ac6ac8ea7..e9549158ba 100644 --- a/pkg/controller/association/reconciler_test.go +++ b/pkg/controller/association/reconciler_test.go @@ -48,7 +48,9 @@ var ( } }, UserSecretSuffix: "kibana-user", - ESUserRole: "kibana_system", + ESUserRole: func(associated commonv1.Associated) (string, error) { + return "kibana_system", nil + }, } kibanaNamespace = "kbns"