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

Allow for scoping TA to watch namespace #3763

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
19 changes: 19 additions & 0 deletions .chloggen/namespace-ta.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# 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: target allocator

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: |
Add support for setting the allowNamespaces and denyNamespaces in the target allocator.

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

# (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: |
allowNamespaces can be set to an empty string to watch all namespaces (default) or to a comma-separated list of namespaces to watch.
denyNamespaces can be set to an empty string to deny watching any namespaces (default) or to a comma-separated list of namespaces to deny watching.
6 changes: 6 additions & 0 deletions apis/v1beta1/targetallocator_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ type TargetAllocatorPrometheusCR struct {
// Enabled indicates whether to use a PrometheusOperator custom resources as targets or not.
// +optional
Enabled bool `json:"enabled,omitempty"`
// AllowNamespaces Namespaces to scope the interaction of the Target Allocator and the apiserver (allow list). This is mutually exclusive with DenyNamespaces.
// +optional
AllowNamespaces string `json:"allowNamespaces,omitempty"`
// DenyNamespaces Namespaces to scope the interaction of the Target Allocator and the apiserver (allow list). This is mutually exclusive with AllowNamespaces.
// +optional
DenyNamespaces string `json:"denyNamespaces,omitempty"`
// Default interval between consecutive scrapes. Intervals set in ServiceMonitors and PodMonitors override it.
//Equivalent to the same setting on the Prometheus CR.
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7889,6 +7889,10 @@ spec:
type: object
prometheusCR:
properties:
allowNamespaces:
type: string
denyNamespaces:
type: string
enabled:
type: boolean
podMonitorSelector:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2257,6 +2257,10 @@ spec:
type: string
prometheusCR:
properties:
allowNamespaces:
type: string
denyNamespaces:
type: string
enabled:
type: boolean
podMonitorSelector:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7889,6 +7889,10 @@ spec:
type: object
prometheusCR:
properties:
allowNamespaces:
type: string
denyNamespaces:
type: string
enabled:
type: boolean
podMonitorSelector:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2257,6 +2257,10 @@ spec:
type: string
prometheusCR:
properties:
allowNamespaces:
type: string
denyNamespaces:
type: string
enabled:
type: boolean
podMonitorSelector:
Expand Down
90 changes: 82 additions & 8 deletions cmd/otel-allocator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,9 +191,11 @@ Upstream documentation here: [PrometheusReceiver](https://github.com/open-teleme

### RBAC

Before the TargetAllocator can start scraping, you need to set up Kubernetes RBAC (role-based access controls) resources. This means that you need to have a `ServiceAccount` and corresponding cluster roles so that the TargetAllocator has access to all of the necessary resources to pull metrics from.
Before the TargetAllocator can start scraping, you need to set up Kubernetes RBAC (role-based access controls) resources. This means that you need to have a `ServiceAccount` and corresponding ClusterRoles/Roles so that the TargetAllocator has access to all the necessary resources to pull metrics from.

You can create your own `ServiceAccount`, and reference it in `spec.targetAllocator.serviceAccount` in your `OpenTelemetryCollector` CR. You’ll then need to configure the `ClusterRole` and `ClusterRoleBinding` for this `ServiceAccount`, as per below.
You can create your own `ServiceAccount`, and reference it in `spec.targetAllocator.serviceAccount` in your `OpenTelemetryCollector` CR. You’ll then need to configure the `ClusterRole` and `ClusterRoleBinding` or `Role` and `RoleBinding` for this `ServiceAccount`, as per below.

#### Cluster-scoped RBAC

```yaml
targetAllocator:
Expand All @@ -204,11 +206,11 @@ You can create your own `ServiceAccount`, and reference it in `spec.targetAlloca
```

> 🚨 **Note**: The Collector part of this same CR *also* has a serviceAccount key which only affects the collector and *not*
the TargetAllocator.
> the TargetAllocator.

If you omit the `ServiceAccount` name, the TargetAllocator creates a `ServiceAccount` for you. The `ServiceAccount`’s default name is a concatenation of the Collector name and the `-targetallocator` suffix. By default, this `ServiceAccount` has no defined policy, so you’ll need to create your own `ClusterRole` and `ClusterRoleBinding` for it, as per below.
If you omit the `ServiceAccount` name, the TargetAllocator creates a `ServiceAccount` for you. The `ServiceAccount`’s default name is a concatenation of the Collector name and the `-targetallocator` suffix. By default, this `ServiceAccount` has no defined policy, so you’ll need to create your own `ClusterRole` and `ClusterRoleBinding` or `Role` and `RoleBinding` for it, as per below.

The role below will provide the minimum access required for the Target Allocator to query all the targets it needs based on any Prometheus configurations:
The ClusterRole below will provide the minimum access required for the Target Allocator to query all the targets it needs based on any Prometheus configurations:

```yaml
apiVersion: rbac.authorization.k8s.io/v1
Expand Down Expand Up @@ -242,7 +244,7 @@ rules:
verbs: ["get"]
```

If you enable the the `prometheusCR` (set `spec.targetAllocator.prometheusCR.enabled` to `true`) in the `OpenTelemetryCollector` CR, you will also need to define the following roles. These give the TargetAllocator access to the `PodMonitor` and `ServiceMonitor` CRs. It also gives namespace access to the `PodMonitor` and `ServiceMonitor`.
If you enable the `prometheusCR` (set `spec.targetAllocator.prometheusCR.enabled` to `true`) in the `OpenTelemetryCollector` CR, you will also need to define the following ClusterRoles. These give the TargetAllocator access to the `PodMonitor` and `ServiceMonitor` CRs. It also gives namespace access to the `PodMonitor` and `ServiceMonitor`.

```yaml
apiVersion: rbac.authorization.k8s.io/v1
Expand All @@ -263,8 +265,81 @@ rules:
verbs: ["get", "list", "watch"]
```

> ✨ The above roles can be combined into a single role.
> ✨ The above ClusterRoles can be combined into a single ClusterRole.

#### Namespace-scoped RBAC

If you want to have the TargetAllocator watch a specific namespace, you can set the allowNamespaces field
in the TargetAllocator's prometheusCR configuration. This is useful if you want to restrict the TargetAllocator to only watch Prometheus
CRs in a specific namespace, and not have cluster-wide access.

```yaml
targetAllocator:
enabled: true
serviceAccount: opentelemetry-targetallocator-sa
prometheusCR:
enabled: true
allowNamespaces: foo
```

In this case, you will need to create a Role and RoleBinding instead of a ClusterRole and ClusterRoleBinding. The Role
and RoleBinding should be created in the namespace specified by the allowNamespaces field.

```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: opentelemetry-targetallocator-role
rules:
- apiGroups:
- ""
resources:
- pods
- services
- endpoints
- configmaps
- secrets
- namespaces
verbs:
- get
- watch
- list
- apiGroups:
- apps
resources:
- statefulsets
verbs:
- get
- watch
- list
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- get
- watch
- list
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- watch
- list
- apiGroups:
- monitoring.coreos.com
resources:
- servicemonitors
- podmonitors
- scrapeconfigs
- probes
verbs:
- get
- watch
- list
```

### Service / Pod monitor endpoint credentials

Expand Down Expand Up @@ -420,4 +495,3 @@ Shards the received targets based on the discovered Collector instances

### Collector
Client to watch for deployed Collector instances which will then provided to the Allocator.

2 changes: 2 additions & 0 deletions cmd/otel-allocator/internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ type Config struct {

type PrometheusCRConfig struct {
Enabled bool `yaml:"enabled,omitempty"`
AllowNamespaces string `yaml:"allow_namespaces,omitempty"`
DenyNamespaces string `yaml:"deny_namespaces,omitempty"`
PodMonitorSelector *metav1.LabelSelector `yaml:"pod_monitor_selector,omitempty"`
PodMonitorNamespaceSelector *metav1.LabelSelector `yaml:"pod_monitor_namespace_selector,omitempty"`
ServiceMonitorSelector *metav1.LabelSelector `yaml:"service_monitor_selector,omitempty"`
Expand Down
32 changes: 28 additions & 4 deletions cmd/otel-allocator/internal/watcher/promOperator.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"fmt"
"log/slog"
"os"
"strings"
"time"

"github.com/blang/semver/v4"
Expand Down Expand Up @@ -53,7 +54,30 @@ func NewPrometheusCRWatcher(ctx context.Context, logger logr.Logger, cfg allocat
return nil, err
}

factory := informers.NewMonitoringInformerFactories(map[string]struct{}{v1.NamespaceAll: {}}, map[string]struct{}{}, mClient, allocatorconfig.DefaultResyncTime, nil) //TODO decide what strategy to use regarding namespaces
if cfg.PrometheusCR.AllowNamespaces != "" && cfg.PrometheusCR.DenyNamespaces != "" {
return nil, fmt.Errorf("both allow and deny namespaces are set, only one should be set")
}

allowList := map[string]struct{}{}
if cfg.PrometheusCR.AllowNamespaces != "" {
logger.Info("watching namespace(s)", "namespaces", cfg.PrometheusCR.AllowNamespaces)
for _, ns := range strings.Split(cfg.PrometheusCR.AllowNamespaces, ",") {
allowList[ns] = struct{}{}
}
} else {
logger.Info("cfg.PrometheusCR.AllowNamespaces is unset, watching all namespaces")
allowList = map[string]struct{}{v1.NamespaceAll: {}}
}

denyList := map[string]struct{}{}
if cfg.PrometheusCR.DenyNamespaces != "" {
logger.Info("excluding namespace(s)", "namespaces", cfg.PrometheusCR.DenyNamespaces)
for _, ns := range strings.Split(cfg.PrometheusCR.DenyNamespaces, ",") {
denyList[ns] = struct{}{}
}
}

factory := informers.NewMonitoringInformerFactories(allowList, denyList, mClient, allocatorconfig.DefaultResyncTime, nil)

monitoringInformers, err := getInformers(factory)
if err != nil {
Expand Down Expand Up @@ -99,7 +123,7 @@ func NewPrometheusCRWatcher(ctx context.Context, logger logr.Logger, cfg allocat
logger.Error(err, "Retrying namespace informer creation in promOperator CRD watcher")
return true
}, func() error {
nsMonInf, err = getNamespaceInformer(ctx, map[string]struct{}{v1.NamespaceAll: {}}, promLogger, clientset, operatorMetrics)
nsMonInf, err = getNamespaceInformer(ctx, allowList, denyList, promLogger, clientset, operatorMetrics)
return err
})
if getNamespaceInformerErr != nil {
Expand Down Expand Up @@ -149,7 +173,7 @@ type PrometheusCRWatcher struct {
store *assets.StoreBuilder
}

func getNamespaceInformer(ctx context.Context, allowList map[string]struct{}, promOperatorLogger *slog.Logger, clientset kubernetes.Interface, operatorMetrics *operator.Metrics) (cache.SharedIndexInformer, error) {
func getNamespaceInformer(ctx context.Context, allowList, denyList map[string]struct{}, promOperatorLogger *slog.Logger, clientset kubernetes.Interface, operatorMetrics *operator.Metrics) (cache.SharedIndexInformer, error) {
kubernetesVersion, err := clientset.Discovery().ServerVersion()
if err != nil {
return nil, err
Expand All @@ -165,7 +189,7 @@ func getNamespaceInformer(ctx context.Context, allowList map[string]struct{}, pr
clientset.CoreV1(),
clientset.AuthorizationV1().SelfSubjectAccessReviews(),
allowList,
map[string]struct{}{},
denyList,
)
if err != nil {
return nil, err
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7875,6 +7875,10 @@ spec:
type: object
prometheusCR:
properties:
allowNamespaces:
type: string
denyNamespaces:
type: string
enabled:
type: boolean
podMonitorSelector:
Expand Down
4 changes: 4 additions & 0 deletions config/crd/bases/opentelemetry.io_targetallocators.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2254,6 +2254,10 @@ spec:
type: string
prometheusCR:
properties:
allowNamespaces:
type: string
denyNamespaces:
type: string
enabled:
type: boolean
podMonitorSelector:
Expand Down
Loading
Loading