@@ -17,9 +17,12 @@ package v1alpha1
17
17
import (
18
18
"context"
19
19
"fmt"
20
+ "strings"
20
21
21
22
"github.com/go-logr/logr"
23
+ v1 "k8s.io/api/authorization/v1"
22
24
autoscalingv2 "k8s.io/api/autoscaling/v2"
25
+ rbacv1 "k8s.io/api/rbac/v1"
23
26
"k8s.io/apimachinery/pkg/runtime"
24
27
"k8s.io/apimachinery/pkg/util/intstr"
25
28
"k8s.io/apimachinery/pkg/util/validation"
@@ -28,12 +31,41 @@ import (
28
31
29
32
"github.com/open-telemetry/opentelemetry-operator/internal/config"
30
33
ta "github.com/open-telemetry/opentelemetry-operator/internal/manifests/targetallocator/adapters"
34
+ "github.com/open-telemetry/opentelemetry-operator/internal/rbac"
31
35
"github.com/open-telemetry/opentelemetry-operator/pkg/featuregate"
32
36
)
33
37
34
38
var (
35
39
_ admission.CustomValidator = & CollectorWebhook {}
36
40
_ admission.CustomDefaulter = & CollectorWebhook {}
41
+
42
+ // targetAllocatorCRPolicyRules are the policy rules required for the CR functionality.
43
+ targetAllocatorCRPolicyRules = []* rbacv1.PolicyRule {
44
+ {
45
+ APIGroups : []string {"monitoring.coreos.com" },
46
+ Resources : []string {"servicemonitors" , "podmonitors" },
47
+ Verbs : []string {"*" },
48
+ }, {
49
+ APIGroups : []string {"" },
50
+ Resources : []string {"nodes" , "nodes/metrics" , "services" , "endpoints" , "pods" },
51
+ Verbs : []string {"get" , "list" , "watch" },
52
+ }, {
53
+ APIGroups : []string {"" },
54
+ Resources : []string {"configmaps" },
55
+ Verbs : []string {"get" },
56
+ }, {
57
+ APIGroups : []string {"discovery.k8s.io" },
58
+ Resources : []string {"endpointslices" },
59
+ Verbs : []string {"get" , "list" , "watch" },
60
+ }, {
61
+ APIGroups : []string {"networking.k8s.io" },
62
+ Resources : []string {"ingresses" },
63
+ Verbs : []string {"get" , "list" , "watch" },
64
+ }, {
65
+ NonResourceURLs : []string {"/metrics" },
66
+ Verbs : []string {"get" },
67
+ },
68
+ }
37
69
)
38
70
39
71
// +kubebuilder:webhook:path=/mutate-opentelemetry-io-v1alpha1-opentelemetrycollector,mutating=true,failurePolicy=fail,groups=opentelemetry.io,resources=opentelemetrycollectors,verbs=create;update,versions=v1alpha1,name=mopentelemetrycollector.kb.io,sideEffects=none,admissionReviewVersions=v1
42
74
// +kubebuilder:object:generate=false
43
75
44
76
type CollectorWebhook struct {
45
- logger logr.Logger
46
- cfg config.Config
47
- scheme * runtime.Scheme
77
+ logger logr.Logger
78
+ cfg config.Config
79
+ scheme * runtime.Scheme
80
+ reviewer * rbac.Reviewer
48
81
}
49
82
50
83
func (c CollectorWebhook ) Default (ctx context.Context , obj runtime.Object ) error {
@@ -60,23 +93,23 @@ func (c CollectorWebhook) ValidateCreate(ctx context.Context, obj runtime.Object
60
93
if ! ok {
61
94
return nil , fmt .Errorf ("expected an OpenTelemetryCollector, received %T" , obj )
62
95
}
63
- return c .validate (otelcol )
96
+ return c .validate (ctx , otelcol )
64
97
}
65
98
66
99
func (c CollectorWebhook ) ValidateUpdate (ctx context.Context , oldObj , newObj runtime.Object ) (admission.Warnings , error ) {
67
100
otelcol , ok := newObj .(* OpenTelemetryCollector )
68
101
if ! ok {
69
102
return nil , fmt .Errorf ("expected an OpenTelemetryCollector, received %T" , newObj )
70
103
}
71
- return c .validate (otelcol )
104
+ return c .validate (ctx , otelcol )
72
105
}
73
106
74
107
func (c CollectorWebhook ) ValidateDelete (ctx context.Context , obj runtime.Object ) (admission.Warnings , error ) {
75
108
otelcol , ok := obj .(* OpenTelemetryCollector )
76
109
if ! ok || otelcol == nil {
77
110
return nil , fmt .Errorf ("expected an OpenTelemetryCollector, received %T" , obj )
78
111
}
79
- return c .validate (otelcol )
112
+ return c .validate (ctx , otelcol )
80
113
}
81
114
82
115
func (c CollectorWebhook ) defaulter (r * OpenTelemetryCollector ) error {
@@ -169,7 +202,7 @@ func (c CollectorWebhook) defaulter(r *OpenTelemetryCollector) error {
169
202
return nil
170
203
}
171
204
172
- func (c CollectorWebhook ) validate (r * OpenTelemetryCollector ) (admission.Warnings , error ) {
205
+ func (c CollectorWebhook ) validate (ctx context. Context , r * OpenTelemetryCollector ) (admission.Warnings , error ) {
173
206
warnings := admission.Warnings {}
174
207
// validate volumeClaimTemplates
175
208
if r .Spec .Mode != ModeStatefulSet && len (r .Spec .VolumeClaimTemplates ) > 0 {
@@ -214,6 +247,14 @@ func (c CollectorWebhook) validate(r *OpenTelemetryCollector) (admission.Warning
214
247
if err != nil {
215
248
return warnings , fmt .Errorf ("the OpenTelemetry Spec Prometheus configuration is incorrect, %w" , err )
216
249
}
250
+ // if the prometheusCR is enabled, it needs a suite of permissions to function
251
+ if r .Spec .TargetAllocator .PrometheusCR .Enabled {
252
+ if subjectAccessReviews , err := c .reviewer .CheckPolicyRules (ctx , r .GetNamespace (), r .Spec .TargetAllocator .ServiceAccount , targetAllocatorCRPolicyRules ... ); err != nil {
253
+ return warnings , fmt .Errorf ("unable to check rbac rules %w" , err )
254
+ } else if allowed , deniedReviews := rbac .AllSubjectAccessReviewsAllowed (subjectAccessReviews ); ! allowed {
255
+ warnings = append (warnings , warningsGroupedByResource (deniedReviews )... )
256
+ }
257
+ }
217
258
}
218
259
219
260
// validator port config
@@ -360,11 +401,34 @@ func checkAutoscalerSpec(autoscaler *AutoscalerSpec) error {
360
401
return nil
361
402
}
362
403
363
- func SetupCollectorWebhook (mgr ctrl.Manager , cfg config.Config ) error {
404
+ // warningsGroupedByResource is a helper to take the missing permissions and format them as warnings.
405
+ func warningsGroupedByResource (reviews []* v1.SubjectAccessReview ) []string {
406
+ fullResourceToVerbs := make (map [string ][]string )
407
+ for _ , review := range reviews {
408
+ if review .Spec .ResourceAttributes != nil {
409
+ key := fmt .Sprintf ("%s/%s" , review .Spec .ResourceAttributes .Group , review .Spec .ResourceAttributes .Resource )
410
+ if len (review .Spec .ResourceAttributes .Group ) == 0 {
411
+ key = review .Spec .ResourceAttributes .Resource
412
+ }
413
+ fullResourceToVerbs [key ] = append (fullResourceToVerbs [key ], review .Spec .ResourceAttributes .Verb )
414
+ } else if review .Spec .NonResourceAttributes != nil {
415
+ key := fmt .Sprintf ("nonResourceURL: %s" , review .Spec .NonResourceAttributes .Path )
416
+ fullResourceToVerbs [key ] = append (fullResourceToVerbs [key ], review .Spec .NonResourceAttributes .Verb )
417
+ }
418
+ }
419
+ var warnings []string
420
+ for fullResource , verbs := range fullResourceToVerbs {
421
+ warnings = append (warnings , fmt .Sprintf ("missing the following rules for %s: [%s]" , fullResource , strings .Join (verbs , "," )))
422
+ }
423
+ return warnings
424
+ }
425
+
426
+ func SetupCollectorWebhook (mgr ctrl.Manager , cfg config.Config , reviewer * rbac.Reviewer ) error {
364
427
cvw := & CollectorWebhook {
365
- logger : mgr .GetLogger ().WithValues ("handler" , "CollectorWebhook" ),
366
- scheme : mgr .GetScheme (),
367
- cfg : cfg ,
428
+ reviewer : reviewer ,
429
+ logger : mgr .GetLogger ().WithValues ("handler" , "CollectorWebhook" ),
430
+ scheme : mgr .GetScheme (),
431
+ cfg : cfg ,
368
432
}
369
433
return ctrl .NewWebhookManagedBy (mgr ).
370
434
For (& OpenTelemetryCollector {}).
0 commit comments