Skip to content

Commit

Permalink
Add automatic RBAC creation for kubeletstats receiver (#3388)
Browse files Browse the repository at this point in the history
* Add automatic RBAC creation for kubeletstats receiver

Signed-off-by: Israel Blancas <[email protected]>

* Revert change

Signed-off-by: Israel Blancas <[email protected]>

---------

Signed-off-by: Israel Blancas <[email protected]>
  • Loading branch information
iblancasa authored Oct 28, 2024
1 parent 3ab821e commit bea432e
Show file tree
Hide file tree
Showing 16 changed files with 427 additions and 2 deletions.
16 changes: 16 additions & 0 deletions .chloggen/kubeletstats.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. collector, target allocator, auto-instrumentation, opamp, github action)
component: collector

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: "Add automatic RBAC creation for the `kubeletstats` receiver."

# One or more tracking issues related to the change
issues: [3155]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,12 @@ add-image-opampbridge:
add-rbac-permissions-to-operator: manifests kustomize
# Kustomize only allows patches in the folder where the kustomization is located
# This folder is ignored by .gitignore
cp -r tests/e2e-automatic-rbac/extra-permissions-operator/ config/rbac/extra-permissions-operator
mkdir -p config/rbac/extra-permissions-operator
cp -r tests/e2e-automatic-rbac/extra-permissions-operator/* config/rbac/extra-permissions-operator
cd config/rbac && $(KUSTOMIZE) edit add patch --kind ClusterRole --name manager-role --path extra-permissions-operator/namespaces.yaml
cd config/rbac && $(KUSTOMIZE) edit add patch --kind ClusterRole --name manager-role --path extra-permissions-operator/nodes.yaml
cd config/rbac && $(KUSTOMIZE) edit add patch --kind ClusterRole --name manager-role --path extra-permissions-operator/nodes-stats.yaml
cd config/rbac && $(KUSTOMIZE) edit add patch --kind ClusterRole --name manager-role --path extra-permissions-operator/nodes-proxy.yaml
cd config/rbac && $(KUSTOMIZE) edit add patch --kind ClusterRole --name manager-role --path extra-permissions-operator/rbac.yaml
cd config/rbac && $(KUSTOMIZE) edit add patch --kind ClusterRole --name manager-role --path extra-permissions-operator/replicaset.yaml

Expand Down
4 changes: 3 additions & 1 deletion internal/components/receivers/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,10 @@ var (
WithProtocol(corev1.ProtocolTCP).
WithTargetPort(3100).
MustBuild(),
components.NewBuilder[kubeletStatsConfig]().WithName("kubeletstats").
WithRbacGen(generateKubeletStatsRbacRules).
MustBuild(),
NewScraperParser("prometheus"),
NewScraperParser("kubeletstats"),
NewScraperParser("sshcheck"),
NewScraperParser("cloudfoundry"),
NewScraperParser("vcenter"),
Expand Down
85 changes: 85 additions & 0 deletions internal/components/receivers/kubeletstats.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright The OpenTelemetry Authors
//
// 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 receivers

import (
"github.com/go-logr/logr"
rbacv1 "k8s.io/api/rbac/v1"
)

type metricConfig struct {
Enabled bool `mapstructure:"enabled"`
}

type metrics struct {
K8sContainerCPULimitUtilization metricConfig `mapstructure:"k8s.container.cpu_limit_utilization"`
K8sContainerCPURequestUtilization metricConfig `mapstructure:"k8s.container.cpu_request_utilization"`
K8sContainerMemoryLimitUtilization metricConfig `mapstructure:"k8s.container.memory_limit_utilization"`
K8sContainerMemoryRequestUtilization metricConfig `mapstructure:"k8s.container.memory_request_utilization"`
K8sPodCPULimitUtilization metricConfig `mapstructure:"k8s.pod.cpu_limit_utilization"`
K8sPodCPURequestUtilization metricConfig `mapstructure:"k8s.pod.cpu_request_utilization"`
K8sPodMemoryLimitUtilization metricConfig `mapstructure:"k8s.pod.memory_limit_utilization"`
K8sPodMemoryRequestUtilization metricConfig `mapstructure:"k8s.pod.memory_request_utilization"`
}

// KubeletStatsConfig is a minimal struct needed for parsing a valid kubeletstats receiver configuration
// This only contains the fields necessary for parsing, other fields can be added in the future.
type kubeletStatsConfig struct {
ExtraMetadataLabels []string `mapstructure:"extra_metadata_labels"`
Metrics metrics `mapstructure:"metrics"`
AuthType string `mapstructure:"auth_type"`
}

func generateKubeletStatsRbacRules(_ logr.Logger, config kubeletStatsConfig) ([]rbacv1.PolicyRule, error) {
// The Kubelet Stats Receiver needs get permissions on the nodes/stats resources always.
prs := []rbacv1.PolicyRule{
{
APIGroups: []string{""},
Resources: []string{"nodes/stats"},
Verbs: []string{"get"},
},
}

// Additionally, when using extra_metadata_labels or any of the {request|limit}_utilization metrics
// the processor also needs get permissions for nodes/proxy resources.
nodesProxyPr := rbacv1.PolicyRule{
APIGroups: []string{""},
Resources: []string{"nodes/proxy"},
Verbs: []string{"get"},
}

if len(config.ExtraMetadataLabels) > 0 {
prs = append(prs, nodesProxyPr)
return prs, nil
}

metrics := []bool{
config.Metrics.K8sContainerCPULimitUtilization.Enabled,
config.Metrics.K8sContainerCPURequestUtilization.Enabled,
config.Metrics.K8sContainerMemoryLimitUtilization.Enabled,
config.Metrics.K8sContainerMemoryRequestUtilization.Enabled,
config.Metrics.K8sPodCPULimitUtilization.Enabled,
config.Metrics.K8sPodCPURequestUtilization.Enabled,
config.Metrics.K8sPodMemoryLimitUtilization.Enabled,
config.Metrics.K8sPodMemoryRequestUtilization.Enabled,
}
for _, metric := range metrics {
if metric {
prs = append(prs, nodesProxyPr)
return prs, nil
}
}
return prs, nil
}
99 changes: 99 additions & 0 deletions internal/components/receivers/kubeletstats_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright The OpenTelemetry Authors
//
// 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 receivers

import (
"testing"

"github.com/go-logr/logr"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
rbacv1 "k8s.io/api/rbac/v1"
)

func TestGenerateKubeletStatsRbacRules(t *testing.T) {
baseRule := rbacv1.PolicyRule{
APIGroups: []string{""},
Resources: []string{"nodes/stats"},
Verbs: []string{"get"},
}

proxyRule := rbacv1.PolicyRule{
APIGroups: []string{""},
Resources: []string{"nodes/proxy"},
Verbs: []string{"get"},
}

tests := []struct {
name string
config kubeletStatsConfig
expectedRules []rbacv1.PolicyRule
expectedErrMsg string
}{
{
name: "Default config",
config: kubeletStatsConfig{},
expectedRules: []rbacv1.PolicyRule{baseRule},
},
{
name: "Extra metadata labels",
config: kubeletStatsConfig{
ExtraMetadataLabels: []string{"label1", "label2"},
},
expectedRules: []rbacv1.PolicyRule{baseRule, proxyRule},
},
{
name: "CPU limit utilization enabled",
config: kubeletStatsConfig{
Metrics: metrics{
K8sContainerCPULimitUtilization: metricConfig{Enabled: true},
},
},
expectedRules: []rbacv1.PolicyRule{baseRule, proxyRule},
},
{
name: "Memory request utilization enabled",
config: kubeletStatsConfig{
Metrics: metrics{
K8sPodMemoryRequestUtilization: metricConfig{Enabled: true},
},
},
expectedRules: []rbacv1.PolicyRule{baseRule, proxyRule},
},
{
name: "No extra permissions needed",
config: kubeletStatsConfig{
Metrics: metrics{
K8sContainerCPULimitUtilization: metricConfig{Enabled: false},
},
},
expectedRules: []rbacv1.PolicyRule{baseRule},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
rules, err := generateKubeletStatsRbacRules(logr.Logger{}, tt.config)

if tt.expectedErrMsg != "" {
require.Error(t, err)
assert.Contains(t, err.Error(), tt.expectedErrMsg)
} else {
require.NoError(t, err)
assert.Equal(t, tt.expectedRules, rules)
}
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
- op: add
path: /rules/-
value:
apiGroups:
- ""
resources:
- nodes/proxy
verbs:
- get
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
- op: add
path: /rules/-
value:
apiGroups:
- ""
resources:
- nodes/stats
verbs:
- get
20 changes: 20 additions & 0 deletions tests/e2e-automatic-rbac/extra-permissions-operator/nodes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,23 @@
- get
- list
- watch
---
- op: add
path: /rules/-
value:
apiGroups:
- ""
resources:
- nodes/proxy
verbs:
- get
---
- op: add
path: /rules/-
value:
apiGroups:
- ""
resources:
- nodes/stats
verbs:
- get
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: chainsaw-kubeletstats
27 changes: 27 additions & 0 deletions tests/e2e-automatic-rbac/receiver-kubeletstats/01-assert.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: simplest-chainsaw-kubeletstats-cluster-role
rules:
- apiGroups: [""]
resources: ["nodes/stats"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/component: opentelemetry-collector
app.kubernetes.io/instance: chainsaw-kubeletstats.simplest
app.kubernetes.io/managed-by: opentelemetry-operator
app.kubernetes.io/name: simplest-chainsaw-kubeletstats-collector
app.kubernetes.io/part-of: opentelemetry
name: simplest-chainsaw-kubeletstats-collector
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: simplest-chainsaw-kubeletstats-cluster-role
subjects:
- kind: ServiceAccount
name: simplest-collector
namespace: chainsaw-kubeletstats
19 changes: 19 additions & 0 deletions tests/e2e-automatic-rbac/receiver-kubeletstats/01-install.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:
name: simplest
namespace: chainsaw-kubeletstats
spec:
config: |
receivers:
kubeletstats:
auth_type: ""
processors:
exporters:
debug:
service:
pipelines:
traces:
receivers: [kubeletstats]
processors: []
exporters: [debug]
30 changes: 30 additions & 0 deletions tests/e2e-automatic-rbac/receiver-kubeletstats/02-assert.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: simplest-chainsaw-kubeletstats-cluster-role
rules:
- apiGroups: [""]
resources: ["nodes/stats"]
verbs: ["get"]
- apiGroups: [""]
resources: ["nodes/proxy"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/component: opentelemetry-collector
app.kubernetes.io/instance: chainsaw-kubeletstats.simplest
app.kubernetes.io/managed-by: opentelemetry-operator
app.kubernetes.io/name: simplest-chainsaw-kubeletstats-collector
app.kubernetes.io/part-of: opentelemetry
name: simplest-chainsaw-kubeletstats-collector
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: simplest-chainsaw-kubeletstats-cluster-role
subjects:
- kind: ServiceAccount
name: simplest-collector
namespace: chainsaw-kubeletstats
20 changes: 20 additions & 0 deletions tests/e2e-automatic-rbac/receiver-kubeletstats/02-install.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:
name: simplest
namespace: chainsaw-kubeletstats
spec:
config: |
receivers:
kubeletstats:
extra_metadata_labels:
- container.id
processors:
exporters:
debug:
service:
pipelines:
traces:
receivers: [kubeletstats]
processors: []
exporters: [debug]
Loading

0 comments on commit bea432e

Please sign in to comment.