Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check for the permissions instead of using a CLI flag #2787

Merged
merged 43 commits into from
May 6, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
de651f3
Check for the permissions instead of using a CLI flag. #2588
iblancasa Apr 8, 2024
e0bcbd7
Fix bundle
iblancasa Apr 8, 2024
0dd7c54
Fix log message
iblancasa Apr 8, 2024
07545f5
Add E2E tests and fix #2833
iblancasa Apr 9, 2024
e53bd6a
Merge branch 'main' of github.com:open-telemetry/opentelemetry-operat…
iblancasa Apr 9, 2024
14b737c
Fix tests
iblancasa Apr 9, 2024
730e71f
Apply changes requested in code review
iblancasa Apr 9, 2024
a51d162
Fix changelog
iblancasa Apr 9, 2024
9e764e9
Fix yaml
iblancasa Apr 9, 2024
18e2fe6
Merge branch 'main' of github.com:open-telemetry/opentelemetry-operat…
iblancasa Apr 10, 2024
a12aade
Apply changes requested in code review
iblancasa Apr 10, 2024
4fc2724
Fix k8sattributes processor
iblancasa Apr 11, 2024
856440a
Fix test
iblancasa Apr 11, 2024
7347aed
Apply changes requested in code review
iblancasa Apr 11, 2024
85123b3
Merge branch 'main' of github.com:open-telemetry/opentelemetry-operat…
iblancasa Apr 11, 2024
f276b03
Apply changes requested in code review
iblancasa Apr 11, 2024
fb2d5be
Remove checked error
iblancasa Apr 11, 2024
e457ea3
Merge branch 'main' into feature/2588
iblancasa Apr 11, 2024
1116be4
Revert change
iblancasa Apr 11, 2024
9c8a246
Merge branch 'feature/2588' of github.com:iblancasa/opentelemetry-ope…
iblancasa Apr 11, 2024
73afa80
Fix workflow
iblancasa Apr 11, 2024
bd2716c
Fix E2E test
iblancasa Apr 11, 2024
7fc13fb
Merge branch 'main' of github.com:open-telemetry/opentelemetry-operat…
iblancasa Apr 12, 2024
0558a69
Fix bundle
iblancasa Apr 12, 2024
f8ca274
Merge branch 'main' into feature/2588
iblancasa Apr 15, 2024
1213cd9
Merge branch 'main' into feature/2588
iblancasa Apr 15, 2024
b548a41
Apply changes requested in code review
iblancasa Apr 16, 2024
019c516
Fix docs
iblancasa Apr 16, 2024
f0bcc60
Merge branch 'main' of github.com:open-telemetry/opentelemetry-operat…
iblancasa Apr 16, 2024
3852840
Fixes #2862
iblancasa Apr 16, 2024
9b7e653
Fix E2E tests
iblancasa Apr 16, 2024
338eb62
Merge branch 'main' of github.com:open-telemetry/opentelemetry-operat…
iblancasa Apr 17, 2024
08915d2
Apply changes requested in code review
iblancasa Apr 17, 2024
71c0b0a
Merge branch 'main' into feature/2588
iblancasa Apr 18, 2024
df654f2
Merge branch 'main' into feature/2588
iblancasa Apr 18, 2024
83a31eb
Merge branch 'main' of github.com:open-telemetry/opentelemetry-operat…
iblancasa Apr 25, 2024
4bbefe9
Remove kustomization
iblancasa Apr 25, 2024
f1ff151
Merge branch 'main' of github.com:open-telemetry/opentelemetry-operat…
iblancasa Apr 29, 2024
add0827
Merge branch 'main' into feature/2588
iblancasa Apr 29, 2024
6c7640b
Merge branch 'main' of github.com:open-telemetry/opentelemetry-operat…
iblancasa Apr 30, 2024
fafb8c9
Merge branch 'main' of github.com:open-telemetry/opentelemetry-operat…
iblancasa May 3, 2024
26e8830
Update bundle
iblancasa May 3, 2024
603d6d3
Fix typo
iblancasa May 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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: operator

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Check the permissions for the SA running the OpenTelemetry Operator instead of using the create-rbac-permissions flag.
iblancasa marked this conversation as resolved.
Show resolved Hide resolved

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

# (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:
26 changes: 1 addition & 25 deletions apis/v1alpha1/collector_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,8 @@ package v1alpha1
import (
"context"
"fmt"
"strings"

"github.com/go-logr/logr"
v1 "k8s.io/api/authorization/v1"
autoscalingv2 "k8s.io/api/autoscaling/v2"
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/runtime"
Expand Down Expand Up @@ -378,7 +376,7 @@ func (c CollectorWebhook) validateTargetAllocatorConfig(ctx context.Context, r *
if subjectAccessReviews, err := c.reviewer.CheckPolicyRules(ctx, r.GetNamespace(), r.Spec.TargetAllocator.ServiceAccount, targetAllocatorCRPolicyRules...); err != nil {
return nil, fmt.Errorf("unable to check rbac rules %w", err)
} else if allowed, deniedReviews := rbac.AllSubjectAccessReviewsAllowed(subjectAccessReviews); !allowed {
return warningsGroupedByResource(deniedReviews), nil
return rbac.WarningsGroupedByResource(deniedReviews), nil
iblancasa marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down Expand Up @@ -426,28 +424,6 @@ func checkAutoscalerSpec(autoscaler *AutoscalerSpec) error {
return nil
}

// warningsGroupedByResource is a helper to take the missing permissions and format them as warnings.
func warningsGroupedByResource(reviews []*v1.SubjectAccessReview) []string {
fullResourceToVerbs := make(map[string][]string)
for _, review := range reviews {
if review.Spec.ResourceAttributes != nil {
key := fmt.Sprintf("%s/%s", review.Spec.ResourceAttributes.Group, review.Spec.ResourceAttributes.Resource)
if len(review.Spec.ResourceAttributes.Group) == 0 {
key = review.Spec.ResourceAttributes.Resource
}
fullResourceToVerbs[key] = append(fullResourceToVerbs[key], review.Spec.ResourceAttributes.Verb)
} else if review.Spec.NonResourceAttributes != nil {
key := fmt.Sprintf("nonResourceURL: %s", review.Spec.NonResourceAttributes.Path)
fullResourceToVerbs[key] = append(fullResourceToVerbs[key], review.Spec.NonResourceAttributes.Verb)
}
}
var warnings []string
for fullResource, verbs := range fullResourceToVerbs {
warnings = append(warnings, fmt.Sprintf("missing the following rules for %s: [%s]", fullResource, strings.Join(verbs, ",")))
}
return warnings
}

func SetupCollectorWebhook(mgr ctrl.Manager, cfg config.Config, reviewer *rbac.Reviewer) error {
cvw := &CollectorWebhook{
reviewer: reviewer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ metadata:
categories: Logging & Tracing,Monitoring
certified: "false"
containerImage: ghcr.io/open-telemetry/opentelemetry-operator/opentelemetry-operator
createdAt: "2024-04-05T17:37:15Z"
createdAt: "2024-04-08T14:26:03Z"
description: Provides the OpenTelemetry components, including the Collector
operators.operatorframework.io/builder: operator-sdk-v1.29.0
operators.operatorframework.io/project_layout: go.kubebuilder.io/v3
Expand Down Expand Up @@ -413,6 +413,11 @@ spec:
- --zap-time-encoding=rfc3339nano
- --feature-gates=+operator.autoinstrumentation.go
- --enable-nginx-instrumentation=true
env:
- name: SERVICE_ACCOUNT_NAME
valueFrom:
fieldRef:
fieldPath: spec.serviceAccountName
image: ghcr.io/open-telemetry/opentelemetry-operator/opentelemetry-operator:0.97.1
livenessProbe:
httpGet:
Expand Down
5 changes: 5 additions & 0 deletions config/manager/manager.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,10 @@ spec:
requests:
cpu: 100m
memory: 64Mi
env:
- name: SERVICE_ACCOUNT_NAME
valueFrom:
fieldRef:
fieldPath: spec.serviceAccountName
serviceAccountName: controller-manager
terminationGracePeriodSeconds: 10
37 changes: 37 additions & 0 deletions internal/autodetect/operator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// 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 autodetect

import (
"fmt"
"os"
)

func GetOperatorNamespace() (string, error) {
nsBytes, err := os.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace")
if err != nil {
return "", err
}
return string(nsBytes), nil
}

func GetOperatorServiceAccount() (string, error) {
saEnvVar := "SERVICE_ACCOUNT_NAME"
iblancasa marked this conversation as resolved.
Show resolved Hide resolved
sa := os.Getenv(saEnvVar)
if sa == "" {
return sa, fmt.Errorf("%s env variable not found", saEnvVar)
swiatekm marked this conversation as resolved.
Show resolved Hide resolved
}
return sa, nil
}
44 changes: 44 additions & 0 deletions internal/rbac/format.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// 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 rbac

import (
"fmt"
"strings"

v1 "k8s.io/api/authorization/v1"
)

// WarningsGroupedByResource is a helper to take the missing permissions and format them as warnings.
func WarningsGroupedByResource(reviews []*v1.SubjectAccessReview) []string {
iblancasa marked this conversation as resolved.
Show resolved Hide resolved
fullResourceToVerbs := make(map[string][]string)
for _, review := range reviews {
if review.Spec.ResourceAttributes != nil {
key := fmt.Sprintf("%s/%s", review.Spec.ResourceAttributes.Group, review.Spec.ResourceAttributes.Resource)
if len(review.Spec.ResourceAttributes.Group) == 0 {
key = review.Spec.ResourceAttributes.Resource
}
fullResourceToVerbs[key] = append(fullResourceToVerbs[key], review.Spec.ResourceAttributes.Verb)
} else if review.Spec.NonResourceAttributes != nil {
key := fmt.Sprintf("nonResourceURL: %s", review.Spec.NonResourceAttributes.Path)
fullResourceToVerbs[key] = append(fullResourceToVerbs[key], review.Spec.NonResourceAttributes.Verb)
}
}
var warnings []string
for fullResource, verbs := range fullResourceToVerbs {
warnings = append(warnings, fmt.Sprintf("missing the following rules for %s: [%s]", fullResource, strings.Join(verbs, ",")))
}
return warnings
}
154 changes: 100 additions & 54 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/spf13/pflag"
colfeaturegate "go.opentelemetry.io/collector/featuregate"
networkingv1 "k8s.io/api/networking/v1"
rbacv1 "k8s.io/api/rbac/v1"
k8sruntime "k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/kubernetes"
Expand Down Expand Up @@ -134,7 +135,7 @@ func main() {
pflag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
"Enable leader election for controller manager. "+
"Enabling this will ensure there is only one active controller manager.")
pflag.BoolVar(&createRBACPermissions, "create-rbac-permissions", false, "Automatically create RBAC permissions needed by the processors")
pflag.BoolVar(&createRBACPermissions, "create-rbac-permissions", false, "Automatically create RBAC permissions needed by the processors (deprecated)")
swiatekm marked this conversation as resolved.
Show resolved Hide resolved
pflag.BoolVar(&enableMultiInstrumentation, "enable-multi-instrumentation", false, "Controls whether the operator supports multi instrumentation")
pflag.BoolVar(&enableApacheHttpdInstrumentation, constants.FlagApacheHttpd, true, "Controls whether the operator supports Apache HTTPD auto-instrumentation")
pflag.BoolVar(&enableDotNetInstrumentation, constants.FlagDotNet, true, "Controls whether the operator supports dotnet auto-instrumentation")
Expand Down Expand Up @@ -188,54 +189,6 @@ func main() {

restConfig := ctrl.GetConfigOrDie()

// builds the operator's configuration
ad, err := autodetect.New(restConfig)
if err != nil {
setupLog.Error(err, "failed to setup auto-detect routine")
os.Exit(1)
}

cfg := config.New(
config.WithLogger(ctrl.Log.WithName("config")),
config.WithVersion(v),
config.WithCollectorImage(collectorImage),
config.WithCreateRBACPermissions(createRBACPermissions),
config.WithEnableMultiInstrumentation(enableMultiInstrumentation),
config.WithEnableApacheHttpdInstrumentation(enableApacheHttpdInstrumentation),
config.WithEnableDotNetInstrumentation(enableDotNetInstrumentation),
config.WithEnableNginxInstrumentation(enableNginxInstrumentation),
config.WithEnablePythonInstrumentation(enablePythonInstrumentation),
config.WithTargetAllocatorImage(targetAllocatorImage),
config.WithOperatorOpAMPBridgeImage(operatorOpAMPBridgeImage),
config.WithAutoInstrumentationJavaImage(autoInstrumentationJava),
config.WithAutoInstrumentationNodeJSImage(autoInstrumentationNodeJS),
config.WithAutoInstrumentationPythonImage(autoInstrumentationPython),
config.WithAutoInstrumentationDotNetImage(autoInstrumentationDotNet),
config.WithAutoInstrumentationGoImage(autoInstrumentationGo),
config.WithAutoInstrumentationApacheHttpdImage(autoInstrumentationApacheHttpd),
config.WithAutoInstrumentationNginxImage(autoInstrumentationNginx),
config.WithAutoDetect(ad),
config.WithLabelFilters(labelsFilter),
config.WithAnnotationFilters(annotationsFilter),
)
err = cfg.AutoDetect()
if err != nil {
setupLog.Error(err, "failed to autodetect config variables")
}
// Only add these to the scheme if they are available
if cfg.PrometheusCRAvailability() == prometheus.Available {
setupLog.Info("Prometheus CRDs are installed, adding to scheme.")
utilruntime.Must(monitoringv1.AddToScheme(scheme))
} else {
setupLog.Info("Prometheus CRDs are not installed, skipping adding to scheme.")
}
if cfg.OpenShiftRoutesAvailability() == openshift.RoutesAvailable {
setupLog.Info("Openshift CRDs are installed, adding to scheme.")
utilruntime.Must(routev1.Install(scheme))
} else {
setupLog.Info("Openshift CRDs are not installed, skipping adding to scheme.")
}

var namespaces map[string]cache.Config
watchNamespace, found := os.LookupEnv("WATCH_NAMESPACE")
if found {
Expand Down Expand Up @@ -284,17 +237,81 @@ func main() {
os.Exit(1)
}

clientset, clientErr := kubernetes.NewForConfig(mgr.GetConfig())
if err != nil {
setupLog.Error(clientErr, "failed to create kubernetes clientset")
}

reviewer := rbac.NewReviewer(clientset)
createRBACPermissions = true
ctx := ctrl.SetupSignalHandler()
err = addDependencies(ctx, mgr, cfg, v)
w, err := checkRbacPermissions(reviewer, ctx)
if err != nil {
setupLog.Error(err, "failed to add/run bootstrap dependencies to the controller manager")
createRBACPermissions = false
setupLog.Info("the operator has not permissions to create rbac resources", "error", err)
}
if w != nil {
createRBACPermissions = false
setupLog.Info("the operator has not permissions to create rbac resources", "permissions", w)
}

if createRBACPermissions {
setupLog.Info("the operator has permissions to create rbac resources")
}

// builds the operator's configuration
ad, err := autodetect.New(restConfig)
if err != nil {
setupLog.Error(err, "failed to setup auto-detect routine")
os.Exit(1)
}
clientset, clientErr := kubernetes.NewForConfig(mgr.GetConfig())

cfg := config.New(
config.WithLogger(ctrl.Log.WithName("config")),
config.WithVersion(v),
config.WithCollectorImage(collectorImage),
config.WithCreateRBACPermissions(createRBACPermissions),
iblancasa marked this conversation as resolved.
Show resolved Hide resolved
config.WithEnableMultiInstrumentation(enableMultiInstrumentation),
config.WithEnableApacheHttpdInstrumentation(enableApacheHttpdInstrumentation),
config.WithEnableDotNetInstrumentation(enableDotNetInstrumentation),
config.WithEnableNginxInstrumentation(enableNginxInstrumentation),
config.WithEnablePythonInstrumentation(enablePythonInstrumentation),
config.WithTargetAllocatorImage(targetAllocatorImage),
config.WithOperatorOpAMPBridgeImage(operatorOpAMPBridgeImage),
config.WithAutoInstrumentationJavaImage(autoInstrumentationJava),
config.WithAutoInstrumentationNodeJSImage(autoInstrumentationNodeJS),
config.WithAutoInstrumentationPythonImage(autoInstrumentationPython),
config.WithAutoInstrumentationDotNetImage(autoInstrumentationDotNet),
config.WithAutoInstrumentationGoImage(autoInstrumentationGo),
config.WithAutoInstrumentationApacheHttpdImage(autoInstrumentationApacheHttpd),
config.WithAutoInstrumentationNginxImage(autoInstrumentationNginx),
config.WithAutoDetect(ad),
config.WithLabelFilters(labelsFilter),
config.WithAnnotationFilters(annotationsFilter),
)
err = cfg.AutoDetect()
if err != nil {
setupLog.Error(clientErr, "failed to create kubernetes clientset")
setupLog.Error(err, "failed to autodetect config variables")
}
// Only add these to the scheme if they are available
if cfg.PrometheusCRAvailability() == prometheus.Available {
setupLog.Info("Prometheus CRDs are installed, adding to scheme.")
utilruntime.Must(monitoringv1.AddToScheme(scheme))
} else {
setupLog.Info("Prometheus CRDs are not installed, skipping adding to scheme.")
}
if cfg.OpenShiftRoutesAvailability() == openshift.RoutesAvailable {
setupLog.Info("Openshift CRDs are installed, adding to scheme.")
utilruntime.Must(routev1.Install(scheme))
} else {
setupLog.Info("Openshift CRDs are not installed, skipping adding to scheme.")
}

err = addDependencies(ctx, mgr, cfg, v)
if err != nil {
setupLog.Error(err, "failed to add/run bootstrap dependencies to the controller manager")
os.Exit(1)
}
reviewer := rbac.NewReviewer(clientset)

if err = controllers.NewReconciler(controllers.Params{
Client: mgr.GetClient(),
Expand Down Expand Up @@ -410,3 +427,32 @@ func tlsConfigSetting(cfg *tls.Config, tlsOpt tlsConfig) {
}
cfg.CipherSuites = cipherSuiteIDs
}

func checkRbacPermissions(reviewer *rbac.Reviewer, ctx context.Context) (admission.Warnings, error) {
iblancasa marked this conversation as resolved.
Show resolved Hide resolved
notPossibleToCheck := "unable to check rbac rules:"

namespace, err := autodetect.GetOperatorNamespace()
if err != nil {
return nil, fmt.Errorf("%s: %w", notPossibleToCheck, err)
}

serviceAccount, err := autodetect.GetOperatorServiceAccount()
if err != nil {
return nil, fmt.Errorf("%s: %w", notPossibleToCheck, err)
}

rules := []*rbacv1.PolicyRule{
{
APIGroups: []string{"rbac.authorization.k8s.io"},
Resources: []string{"clusterrolebindings", "clusterroles"},
Verbs: []string{"create", "delete", "get", "list", "patch", "update"},
},
}

if subjectAccessReviews, err := reviewer.CheckPolicyRules(ctx, serviceAccount, namespace, rules...); err != nil {
return nil, fmt.Errorf("%s: %w", notPossibleToCheck, err)
} else if allowed, deniedReviews := rbac.AllSubjectAccessReviewsAllowed(subjectAccessReviews); !allowed {
return rbac.WarningsGroupedByResource(deniedReviews), nil
}
return nil, nil
}
Loading