Skip to content

Commit

Permalink
Add ClusterRole/ClusterRoleBinding to service-agent (#243)
Browse files Browse the repository at this point in the history
In addition we needed to add some missing RBAC permissions that
are required for the instana-agent and were in the v1 version of the
the helm charts to the instana-agent-operator account since it cannot
grant RBAC permissions (to instana-agent) that itself doesn't have.

Also refactored the list of "reading verbs" from a ClusterRole
perspective i.e: "get", "list", "watch" into a function that can be used
by all rbac clusterroles.

Signed-off-by: Antonio Gutierrez <antonio.gutierrez1@ibm.com>
Co-authored-by: Antonio Gutierrez <antonio.gutierrez1@ibm.com>
  • Loading branch information
chibby0ne and Antonio Gutierrez authored Feb 4, 2025
1 parent 702528f commit adb1ab9
Show file tree
Hide file tree
Showing 10 changed files with 453 additions and 12 deletions.
9 changes: 9 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ metadata:
rules:
- nonResourceURLs:
- /healthz
- /metrics
- /metrics/cadvisor
- /stats/summary
- /version
verbs:
- get
Expand Down Expand Up @@ -146,6 +149,12 @@ rules:
- get
- list
- watch
- apiGroups:
- policy
resources:
- podsecuritypolicies
verbs:
- use
- apiGroups:
- policy
resourceNames:
Expand Down
3 changes: 3 additions & 0 deletions controllers/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
instanav1 "github.com/instana/instana-agent-operator/api/v1"
agentdaemonset "github.com/instana/instana-agent-operator/pkg/k8s/object/builders/agent/daemonset"
headlessservice "github.com/instana/instana-agent-operator/pkg/k8s/object/builders/agent/headless-service"
agentrbac "github.com/instana/instana-agent-operator/pkg/k8s/object/builders/agent/rbac"
agentsecrets "github.com/instana/instana-agent-operator/pkg/k8s/object/builders/agent/secrets"
keyssecret "github.com/instana/instana-agent-operator/pkg/k8s/object/builders/agent/secrets/keys-secret"
tlssecret "github.com/instana/instana-agent-operator/pkg/k8s/object/builders/agent/secrets/tls-secret"
Expand Down Expand Up @@ -98,6 +99,8 @@ func (r *InstanaAgentReconciler) applyResources(
agentsecrets.NewContainerBuilder(agent, keysSecret),
tlssecret.NewSecretBuilder(agent),
service.NewServiceBuilder(agent),
agentrbac.NewClusterRoleBuilder(agent),
agentrbac.NewClusterRoleBindingBuilder(agent),
agentserviceaccount.NewServiceAccountBuilder(agent),
k8ssensorpoddisruptionbudget.NewPodDisruptionBudgetBuilder(agent),
k8ssensorrbac.NewClusterRoleBuilder(agent),
Expand Down
3 changes: 2 additions & 1 deletion controllers/instanaagent_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,10 @@ func (r *InstanaAgentReconciler) reconcile(
// +kubebuilder:rbac:groups=apiextensions.k8s.io,resources=customresourcedefinitions,verbs=get;list;watch
// +kubebuilder:rbac:groups=instana.io,resources=agents/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=instana.io,resources=agents/finalizers,verbs=update
// +kubebuilder:rbac:groups=policy,resources=podsecuritypolicies,verbs=use

// adding role property required to manage instana-agent-k8sensor ClusterRole
// +kubebuilder:rbac:urls=/version;/healthz,verbs=get
// +kubebuilder:rbac:urls=/version;/healthz;/metrics;/metrics/cadvisor;/stats/summary,verbs=get
// +kubebuilder:rbac:groups=extensions,resources=deployments;replicasets;ingresses,verbs=get;list;watch
// +kubebuilder:rbac:groups=core,resources=configmaps;events;services;endpoints;namespaces;nodes;pods;pods/log;replicationcontrollers;resourcequotas;persistentvolumes;persistentvolumeclaims;nodes/metrics;nodes/stats,verbs=get;list;watch
// +kubebuilder:rbac:groups=apps,resources=daemonsets;deployments;replicasets;statefulsets,verbs=get;list;watch
Expand Down
104 changes: 104 additions & 0 deletions pkg/k8s/object/builders/agent/rbac/clusterrole.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
(c) Copyright IBM Corp. 2025
(c) Copyright Instana Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package rbac

import (
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/instana/instana-agent-operator/pkg/k8s/object/builders/common/builder"
"github.com/instana/instana-agent-operator/pkg/k8s/object/builders/common/constants"
"github.com/instana/instana-agent-operator/pkg/k8s/object/builders/common/helpers"
"github.com/instana/instana-agent-operator/pkg/optional"
"sigs.k8s.io/controller-runtime/pkg/client"

instanav1 "github.com/instana/instana-agent-operator/api/v1"
)

type clusterRoleBuilder struct {
*instanav1.InstanaAgent
helpers.Helpers
}

func (c *clusterRoleBuilder) ComponentName() string {
return constants.ComponentInstanaAgent
}

func (c *clusterRoleBuilder) IsNamespaced() bool {
return false
}

func (c *clusterRoleBuilder) Build() optional.Optional[client.Object] {
return optional.Of[client.Object](
&rbacv1.ClusterRole{
TypeMeta: metav1.TypeMeta{
APIVersion: rbacApiVersion,
Kind: roleKind,
},
ObjectMeta: metav1.ObjectMeta{
Name: c.ServiceAccountName(),
},
Rules: []rbacv1.PolicyRule{
{
NonResourceURLs: []string{
"/version",
"/healthz",
"/metrics",
"/stats/summary",
"/metrics/cadvisor",
},
Verbs: []string{"get"},
APIGroups: []string{},
Resources: []string{},
},
{
APIGroups: []string{""},
Resources: []string{
"nodes",
"nodes/stats",
"nodes/metrics",
"pods",
},
Verbs: constants.ReaderVerbs(),
},
{
APIGroups: []string{"security.openshift.io"},
ResourceNames: []string{"privileged"},
Resources: []string{
"securitycontextconstraints",
},
Verbs: []string{"use"},
},
{
APIGroups: []string{"policy"},
Resources: []string{
"podsecuritypolicies",
},
Verbs: []string{"use"},
},
},
},
)
}

func NewClusterRoleBuilder(agent *instanav1.InstanaAgent) builder.ObjectBuilder {
return &clusterRoleBuilder{
InstanaAgent: agent,
Helpers: helpers.NewHelpers(agent),
}
}
111 changes: 111 additions & 0 deletions pkg/k8s/object/builders/agent/rbac/clusterrole_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
(c) Copyright IBM Corp. 2025
(c) Copyright Instana Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package rbac

import (
"testing"

"github.com/stretchr/testify/require"
gomock "go.uber.org/mock/gomock"
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/rand"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/instana/instana-agent-operator/mocks"
"github.com/instana/instana-agent-operator/pkg/k8s/object/builders/common/constants"
"github.com/instana/instana-agent-operator/pkg/optional"
)

func TestClusterRoleBuilder_IsNamespaced_ComponentName(t *testing.T) {
assertions := require.New(t)

cb := NewClusterRoleBuilder(nil)

assertions.False(cb.IsNamespaced())
assertions.Equal(constants.ComponentInstanaAgent, cb.ComponentName())
}

func TestClusterRoleBuilder_Build(t *testing.T) {
assertions := require.New(t)
ctrl := gomock.NewController(t)

sensorResourcesName := rand.String(10)

expected := optional.Of[client.Object](
&rbacv1.ClusterRole{
TypeMeta: metav1.TypeMeta{
APIVersion: rbacApiVersion,
Kind: roleKind,
},
ObjectMeta: metav1.ObjectMeta{
Name: sensorResourcesName,
},
Rules: []rbacv1.PolicyRule{
{
NonResourceURLs: []string{
"/version",
"/healthz",
"/metrics",
"/stats/summary",
"/metrics/cadvisor",
},
Verbs: []string{"get"},
APIGroups: []string{},
Resources: []string{},
},
{
APIGroups: []string{""},
Resources: []string{
"nodes",
"nodes/stats",
"nodes/metrics",
"pods",
},
Verbs: constants.ReaderVerbs(),
},
{
APIGroups: []string{"security.openshift.io"},
ResourceNames: []string{"privileged"},
Resources: []string{
"securitycontextconstraints",
},
Verbs: []string{"use"},
},
{
APIGroups: []string{"policy"},
Resources: []string{
"podsecuritypolicies",
},
Verbs: []string{"use"},
},
},
},
)

helpers := mocks.NewMockHelpers(ctrl)
helpers.EXPECT().ServiceAccountName().Times(1).Return(sensorResourcesName)

cb := &clusterRoleBuilder{
Helpers: helpers,
}

actual := cb.Build()

assertions.Equal(expected, actual)
}
77 changes: 77 additions & 0 deletions pkg/k8s/object/builders/agent/rbac/clusterrolebinding.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
(c) Copyright IBM Corp. 2025
(c) Copyright Instana Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package rbac

import (
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/instana/instana-agent-operator/pkg/k8s/object/builders/common/builder"
"github.com/instana/instana-agent-operator/pkg/k8s/object/builders/common/constants"
"github.com/instana/instana-agent-operator/pkg/k8s/object/builders/common/helpers"
"github.com/instana/instana-agent-operator/pkg/optional"
"sigs.k8s.io/controller-runtime/pkg/client"

instanav1 "github.com/instana/instana-agent-operator/api/v1"
)

type clusterRoleBindingBuilder struct {
*instanav1.InstanaAgent
helpers.Helpers
}

func (c *clusterRoleBindingBuilder) IsNamespaced() bool {
return false
}

func (c *clusterRoleBindingBuilder) ComponentName() string {
return constants.ComponentInstanaAgent
}

func (c *clusterRoleBindingBuilder) Build() optional.Optional[client.Object] {
return optional.Of[client.Object](
&rbacv1.ClusterRoleBinding{
TypeMeta: metav1.TypeMeta{
APIVersion: rbacApiVersion,
Kind: "ClusterRoleBinding",
},
ObjectMeta: metav1.ObjectMeta{
Name: c.ServiceAccountName(),
},
RoleRef: rbacv1.RoleRef{
APIGroup: rbacApiGroup,
Kind: roleKind,
Name: c.ServiceAccountName(),
},
Subjects: []rbacv1.Subject{
{
Kind: subjectKind,
Name: c.ServiceAccountName(),
Namespace: c.Namespace,
},
},
},
)
}

func NewClusterRoleBindingBuilder(agent *instanav1.InstanaAgent) builder.ObjectBuilder {
return &clusterRoleBindingBuilder{
InstanaAgent: agent,
Helpers: helpers.NewHelpers(agent),
}
}
Loading

0 comments on commit adb1ab9

Please sign in to comment.