From 5edc23a5ec3518580bd28e898fad8e8465f73f24 Mon Sep 17 00:00:00 2001
From: Pavol Loffay
Date: Tue, 25 Feb 2025 16:22:41 +0100
Subject: [PATCH] Add support for query RBAC to tempomonolithic (#1131)
Signed-off-by: Pavol Loffay
---
.chloggen/rbac-monolithic.yaml | 26 ++
.../v1alpha1/tempomonolithic_defaults.go | 3 +
.../v1alpha1/tempomonolithic_defaults_test.go | 62 ++++
api/tempo/v1alpha1/tempomonolithic_types.go | 17 ++
api/tempo/v1alpha1/tempostack_types.go | 2 +-
api/tempo/v1alpha1/zz_generated.deepcopy.go | 21 ++
.../tempo-operator.clusterserviceversion.yaml | 17 +-
.../tempo.grafana.com_tempomonolithics.yaml | 13 +
.../tempo.grafana.com_tempostacks.yaml | 2 +-
.../tempo-operator.clusterserviceversion.yaml | 17 +-
.../tempo.grafana.com_tempomonolithics.yaml | 13 +
.../tempo.grafana.com_tempostacks.yaml | 2 +-
.../tempo.grafana.com_tempomonolithics.yaml | 13 +
.../bases/tempo.grafana.com_tempostacks.yaml | 2 +-
.../tempo-operator.clusterserviceversion.yaml | 15 +-
.../tempo-operator.clusterserviceversion.yaml | 15 +-
.../tempo.grafana.com_tempomonolithics.yaml | 3 +
docs/spec/tempo.grafana.com_tempostacks.yaml | 2 +-
internal/manifests/monolithic/statefulset.go | 4 +
.../manifests/monolithic/statefulset_test.go | 286 ++++++++++++++++++
internal/webhooks/tempomonolithic_webhook.go | 13 +
.../webhooks/tempomonolithic_webhook_test.go | 64 ++++
22 files changed, 601 insertions(+), 11 deletions(-)
create mode 100755 .chloggen/rbac-monolithic.yaml
diff --git a/.chloggen/rbac-monolithic.yaml b/.chloggen/rbac-monolithic.yaml
new file mode 100755
index 000000000..1acc78db3
--- /dev/null
+++ b/.chloggen/rbac-monolithic.yaml
@@ -0,0 +1,26 @@
+# 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. tempostack, tempomonolithic, github action)
+component: tempomonolithic
+
+# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
+note: Add support for query RBAC
+
+# One or more tracking issues related to the change
+issues: [1131]
+
+# (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: |
+ This feature allows users to apply query RBAC in the multitenancy mode.
+ The RBAC allows filtering span/resource/scope attributes and events based on the namespaces which a user querying the data can access.
+ For instance, a user can only see attributes from namespaces it can access.
+
+ ```yaml
+ spec:
+ query:
+ rbac:
+ enabled: true
+ ```
diff --git a/api/tempo/v1alpha1/tempomonolithic_defaults.go b/api/tempo/v1alpha1/tempomonolithic_defaults.go
index bf04eb36c..aa81df192 100644
--- a/api/tempo/v1alpha1/tempomonolithic_defaults.go
+++ b/api/tempo/v1alpha1/tempomonolithic_defaults.go
@@ -102,4 +102,7 @@ func (r *TempoMonolithic) Default(ctrlConfig configv1alpha1.ProjectConfig) {
if r.Spec.Timeout.Duration == 0 {
r.Spec.Timeout = defaultTimeout
}
+ if r.Spec.Query == nil {
+ r.Spec.Query = &MonolithicQuerySpec{}
+ }
}
diff --git a/api/tempo/v1alpha1/tempomonolithic_defaults_test.go b/api/tempo/v1alpha1/tempomonolithic_defaults_test.go
index edf831e97..33b0c7208 100644
--- a/api/tempo/v1alpha1/tempomonolithic_defaults_test.go
+++ b/api/tempo/v1alpha1/tempomonolithic_defaults_test.go
@@ -49,6 +49,7 @@ func TestMonolithicDefault(t *testing.T) {
},
Management: "Managed",
Timeout: metav1.Duration{Duration: time.Second * 30},
+ Query: &MonolithicQuerySpec{},
},
},
},
@@ -83,6 +84,7 @@ func TestMonolithicDefault(t *testing.T) {
},
Management: "Managed",
Timeout: metav1.Duration{Duration: time.Second * 30},
+ Query: &MonolithicQuerySpec{},
},
},
},
@@ -109,6 +111,7 @@ func TestMonolithicDefault(t *testing.T) {
},
Management: "Unmanaged",
Timeout: metav1.Duration{Duration: time.Second * 30},
+ Query: &MonolithicQuerySpec{},
},
},
expected: &TempoMonolithic{
@@ -131,6 +134,7 @@ func TestMonolithicDefault(t *testing.T) {
},
Management: "Unmanaged",
Timeout: metav1.Duration{Duration: time.Second * 30},
+ Query: &MonolithicQuerySpec{},
},
},
},
@@ -203,6 +207,7 @@ func TestMonolithicDefault(t *testing.T) {
},
Management: "Managed",
Timeout: metav1.Duration{Duration: time.Second * 30},
+ Query: &MonolithicQuerySpec{},
},
},
},
@@ -278,6 +283,7 @@ func TestMonolithicDefault(t *testing.T) {
},
Management: "Managed",
Timeout: metav1.Duration{Duration: time.Second * 30},
+ Query: &MonolithicQuerySpec{},
},
},
},
@@ -345,6 +351,7 @@ func TestMonolithicDefault(t *testing.T) {
},
Management: "Managed",
Timeout: metav1.Duration{Duration: time.Second * 30},
+ Query: &MonolithicQuerySpec{},
},
},
},
@@ -412,6 +419,7 @@ func TestMonolithicDefault(t *testing.T) {
},
Management: "Managed",
Timeout: metav1.Duration{Duration: time.Second * 30},
+ Query: &MonolithicQuerySpec{},
},
},
},
@@ -478,6 +486,60 @@ func TestMonolithicDefault(t *testing.T) {
},
Management: "Managed",
Timeout: metav1.Duration{Duration: time.Hour},
+ Query: &MonolithicQuerySpec{},
+ },
+ },
+ },
+ {
+ name: "query defined",
+ input: &TempoMonolithic{
+ ObjectMeta: v1.ObjectMeta{
+ Name: "test",
+ Namespace: "testns",
+ },
+ Spec: TempoMonolithicSpec{
+ Storage: &MonolithicStorageSpec{
+ Traces: MonolithicTracesStorageSpec{
+ Backend: "memory",
+ Size: &twoGBQuantity,
+ },
+ },
+ Query: &MonolithicQuerySpec{
+ RBAC: RBACSpec{
+ Enabled: true,
+ },
+ },
+ },
+ },
+ expected: &TempoMonolithic{
+ ObjectMeta: v1.ObjectMeta{
+ Name: "test",
+ Namespace: "testns",
+ },
+ Spec: TempoMonolithicSpec{
+ Ingestion: &MonolithicIngestionSpec{
+ OTLP: &MonolithicIngestionOTLPSpec{
+ GRPC: &MonolithicIngestionOTLPProtocolsGRPCSpec{
+ Enabled: true,
+ },
+ HTTP: &MonolithicIngestionOTLPProtocolsHTTPSpec{
+ Enabled: true,
+ },
+ },
+ },
+ Storage: &MonolithicStorageSpec{
+ Traces: MonolithicTracesStorageSpec{
+ Backend: "memory",
+ Size: &twoGBQuantity,
+ },
+ },
+ Management: "Managed",
+ Timeout: metav1.Duration{Duration: time.Second * 30},
+ Query: &MonolithicQuerySpec{
+ RBAC: RBACSpec{
+ Enabled: true,
+ },
+ },
},
},
},
diff --git a/api/tempo/v1alpha1/tempomonolithic_types.go b/api/tempo/v1alpha1/tempomonolithic_types.go
index b6db8fe0a..55d22fc2c 100644
--- a/api/tempo/v1alpha1/tempomonolithic_types.go
+++ b/api/tempo/v1alpha1/tempomonolithic_types.go
@@ -68,9 +68,26 @@ type TempoMonolithicSpec struct {
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Extra Configuration",xDescriptors="urn:alm:descriptor:com.tectonic.ui:advanced"
ExtraConfig *ExtraConfigSpec `json:"extraConfig,omitempty"`
+ // Query defines query configuration.
+ //
+ // +kubebuilder:validation:Optional
+ // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Query Configuration",xDescriptors="urn:alm:descriptor:com.tectonic.ui:advanced"
+ Query *MonolithicQuerySpec `json:"query,omitempty"`
+
MonolithicSchedulerSpec `json:",inline"`
}
+// MonolithicQuerySpec defines the query configuration.
+type MonolithicQuerySpec struct {
+ // RBAC defines query RBAC options.
+ // This option can be used only with multi-tenancy.
+ //
+ // +optional
+ // +kubebuilder:validation:Optional
+ // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Query RBAC Settings"
+ RBAC RBACSpec `json:"rbac,omitempty"`
+}
+
// MonolithicStorageSpec defines the storage for the Tempo deployment.
type MonolithicStorageSpec struct {
// Traces defines the storage configuration for traces.
diff --git a/api/tempo/v1alpha1/tempostack_types.go b/api/tempo/v1alpha1/tempostack_types.go
index 97b1c4f91..4b4fce313 100644
--- a/api/tempo/v1alpha1/tempostack_types.go
+++ b/api/tempo/v1alpha1/tempostack_types.go
@@ -592,7 +592,7 @@ type TempoGatewaySpec struct {
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Gateway Ingress Settings"
Ingress IngressSpec `json:"ingress,omitempty"`
- // RBAC defines RBAC options.
+ // RBAC defines query RBAC options.
//
// +optional
// +kubebuilder:validation:Optional
diff --git a/api/tempo/v1alpha1/zz_generated.deepcopy.go b/api/tempo/v1alpha1/zz_generated.deepcopy.go
index 033ffd25a..5f9008e42 100644
--- a/api/tempo/v1alpha1/zz_generated.deepcopy.go
+++ b/api/tempo/v1alpha1/zz_generated.deepcopy.go
@@ -758,6 +758,22 @@ func (in *MonolithicObservabilitySpec) DeepCopy() *MonolithicObservabilitySpec {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MonolithicQuerySpec) DeepCopyInto(out *MonolithicQuerySpec) {
+ *out = *in
+ out.RBAC = in.RBAC
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonolithicQuerySpec.
+func (in *MonolithicQuerySpec) DeepCopy() *MonolithicQuerySpec {
+ if in == nil {
+ return nil
+ }
+ out := new(MonolithicQuerySpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MonolithicSchedulerSpec) DeepCopyInto(out *MonolithicSchedulerSpec) {
*out = *in
@@ -1394,6 +1410,11 @@ func (in *TempoMonolithicSpec) DeepCopyInto(out *TempoMonolithicSpec) {
*out = new(ExtraConfigSpec)
(*in).DeepCopyInto(*out)
}
+ if in.Query != nil {
+ in, out := &in.Query, &out.Query
+ *out = new(MonolithicQuerySpec)
+ **out = **in
+ }
in.MonolithicSchedulerSpec.DeepCopyInto(&out.MonolithicSchedulerSpec)
}
diff --git a/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml b/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
index 0af213ad1..afdb839cd 100644
--- a/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
+++ b/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
@@ -74,7 +74,7 @@ metadata:
capabilities: Deep Insights
categories: Logging & Tracing,Monitoring
containerImage: ghcr.io/grafana/tempo-operator/tempo-operator:v0.15.2
- createdAt: "2025-02-24T14:25:33Z"
+ createdAt: "2025-02-25T15:15:23Z"
description: Create and manage deployments of Tempo, a high-scale distributed
tracing backend.
operatorframework.io/cluster-monitoring: "true"
@@ -459,6 +459,19 @@ spec:
- description: ServiceMonitors defines the ServiceMonitor configuration.
displayName: Service Monitors
path: observability.metrics.serviceMonitors
+ - description: Query defines query configuration.
+ displayName: Query Configuration
+ path: query
+ x-descriptors:
+ - urn:alm:descriptor:com.tectonic.ui:advanced
+ - description: |-
+ RBAC defines query RBAC options.
+ This option can be used only with multi-tenancy.
+ displayName: Query RBAC Settings
+ path: query.rbac
+ - description: Enabled defines if the query RBAC should be enabled.
+ displayName: Query RBAC Enabled
+ path: query.rbac.enabled
- description: ServiceAccount defines the Service Account to use for all Tempo
components.
displayName: Service Account
@@ -995,7 +1008,7 @@ spec:
all pods of this component.
displayName: PodSecurityContext
path: template.gateway.podSecurityContext
- - description: RBAC defines RBAC options.
+ - description: RBAC defines query RBAC options.
displayName: Query RBAC Settings
path: template.gateway.rbac
- description: Enabled defines if the query RBAC should be enabled.
diff --git a/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml b/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml
index 68dc52397..ef6f30243 100644
--- a/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml
+++ b/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml
@@ -1531,6 +1531,19 @@ spec:
type: object
type: object
type: object
+ query:
+ description: Query defines query configuration.
+ properties:
+ rbac:
+ description: |-
+ RBAC defines query RBAC options.
+ This option can be used only with multi-tenancy.
+ properties:
+ enabled:
+ description: Enabled defines if the query RBAC should be enabled.
+ type: boolean
+ type: object
+ type: object
resources:
description: Resources defines the compute resource requirements of
the Tempo container.
diff --git a/bundle/community/manifests/tempo.grafana.com_tempostacks.yaml b/bundle/community/manifests/tempo.grafana.com_tempostacks.yaml
index 62e18a445..cf1355afe 100644
--- a/bundle/community/manifests/tempo.grafana.com_tempostacks.yaml
+++ b/bundle/community/manifests/tempo.grafana.com_tempostacks.yaml
@@ -1435,7 +1435,7 @@ spec:
type: string
type: object
rbac:
- description: RBAC defines RBAC options.
+ description: RBAC defines query RBAC options.
properties:
enabled:
description: Enabled defines if the query RBAC should
diff --git a/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml b/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
index 63ef6ecb4..ad98ec923 100644
--- a/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
+++ b/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
@@ -74,7 +74,7 @@ metadata:
capabilities: Deep Insights
categories: Logging & Tracing,Monitoring
containerImage: ghcr.io/grafana/tempo-operator/tempo-operator:v0.15.2
- createdAt: "2025-02-24T14:25:31Z"
+ createdAt: "2025-02-25T15:15:22Z"
description: Create and manage deployments of Tempo, a high-scale distributed
tracing backend.
operatorframework.io/cluster-monitoring: "true"
@@ -459,6 +459,19 @@ spec:
- description: ServiceMonitors defines the ServiceMonitor configuration.
displayName: Service Monitors
path: observability.metrics.serviceMonitors
+ - description: Query defines query configuration.
+ displayName: Query Configuration
+ path: query
+ x-descriptors:
+ - urn:alm:descriptor:com.tectonic.ui:advanced
+ - description: |-
+ RBAC defines query RBAC options.
+ This option can be used only with multi-tenancy.
+ displayName: Query RBAC Settings
+ path: query.rbac
+ - description: Enabled defines if the query RBAC should be enabled.
+ displayName: Query RBAC Enabled
+ path: query.rbac.enabled
- description: ServiceAccount defines the Service Account to use for all Tempo
components.
displayName: Service Account
@@ -995,7 +1008,7 @@ spec:
all pods of this component.
displayName: PodSecurityContext
path: template.gateway.podSecurityContext
- - description: RBAC defines RBAC options.
+ - description: RBAC defines query RBAC options.
displayName: Query RBAC Settings
path: template.gateway.rbac
- description: Enabled defines if the query RBAC should be enabled.
diff --git a/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml b/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml
index 68dc52397..ef6f30243 100644
--- a/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml
+++ b/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml
@@ -1531,6 +1531,19 @@ spec:
type: object
type: object
type: object
+ query:
+ description: Query defines query configuration.
+ properties:
+ rbac:
+ description: |-
+ RBAC defines query RBAC options.
+ This option can be used only with multi-tenancy.
+ properties:
+ enabled:
+ description: Enabled defines if the query RBAC should be enabled.
+ type: boolean
+ type: object
+ type: object
resources:
description: Resources defines the compute resource requirements of
the Tempo container.
diff --git a/bundle/openshift/manifests/tempo.grafana.com_tempostacks.yaml b/bundle/openshift/manifests/tempo.grafana.com_tempostacks.yaml
index 62e18a445..cf1355afe 100644
--- a/bundle/openshift/manifests/tempo.grafana.com_tempostacks.yaml
+++ b/bundle/openshift/manifests/tempo.grafana.com_tempostacks.yaml
@@ -1435,7 +1435,7 @@ spec:
type: string
type: object
rbac:
- description: RBAC defines RBAC options.
+ description: RBAC defines query RBAC options.
properties:
enabled:
description: Enabled defines if the query RBAC should
diff --git a/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml b/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml
index ebf73af55..fbf7f3390 100644
--- a/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml
+++ b/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml
@@ -1527,6 +1527,19 @@ spec:
type: object
type: object
type: object
+ query:
+ description: Query defines query configuration.
+ properties:
+ rbac:
+ description: |-
+ RBAC defines query RBAC options.
+ This option can be used only with multi-tenancy.
+ properties:
+ enabled:
+ description: Enabled defines if the query RBAC should be enabled.
+ type: boolean
+ type: object
+ type: object
resources:
description: Resources defines the compute resource requirements of
the Tempo container.
diff --git a/config/crd/bases/tempo.grafana.com_tempostacks.yaml b/config/crd/bases/tempo.grafana.com_tempostacks.yaml
index a0d8b7da1..049920047 100644
--- a/config/crd/bases/tempo.grafana.com_tempostacks.yaml
+++ b/config/crd/bases/tempo.grafana.com_tempostacks.yaml
@@ -1431,7 +1431,7 @@ spec:
type: string
type: object
rbac:
- description: RBAC defines RBAC options.
+ description: RBAC defines query RBAC options.
properties:
enabled:
description: Enabled defines if the query RBAC should
diff --git a/config/manifests/community/bases/tempo-operator.clusterserviceversion.yaml b/config/manifests/community/bases/tempo-operator.clusterserviceversion.yaml
index f9d46281e..f26ac76a0 100644
--- a/config/manifests/community/bases/tempo-operator.clusterserviceversion.yaml
+++ b/config/manifests/community/bases/tempo-operator.clusterserviceversion.yaml
@@ -388,6 +388,19 @@ spec:
- description: ServiceMonitors defines the ServiceMonitor configuration.
displayName: Service Monitors
path: observability.metrics.serviceMonitors
+ - description: Query defines query configuration.
+ displayName: Query Configuration
+ path: query
+ x-descriptors:
+ - urn:alm:descriptor:com.tectonic.ui:advanced
+ - description: |-
+ RBAC defines query RBAC options.
+ This option can be used only with multi-tenancy.
+ displayName: Query RBAC Settings
+ path: query.rbac
+ - description: Enabled defines if the query RBAC should be enabled.
+ displayName: Query RBAC Enabled
+ path: query.rbac.enabled
- description: ServiceAccount defines the Service Account to use for all Tempo
components.
displayName: Service Account
@@ -924,7 +937,7 @@ spec:
all pods of this component.
displayName: PodSecurityContext
path: template.gateway.podSecurityContext
- - description: RBAC defines RBAC options.
+ - description: RBAC defines query RBAC options.
displayName: Query RBAC Settings
path: template.gateway.rbac
- description: Enabled defines if the query RBAC should be enabled.
diff --git a/config/manifests/openshift/bases/tempo-operator.clusterserviceversion.yaml b/config/manifests/openshift/bases/tempo-operator.clusterserviceversion.yaml
index 07b510280..df11474a0 100644
--- a/config/manifests/openshift/bases/tempo-operator.clusterserviceversion.yaml
+++ b/config/manifests/openshift/bases/tempo-operator.clusterserviceversion.yaml
@@ -388,6 +388,19 @@ spec:
- description: ServiceMonitors defines the ServiceMonitor configuration.
displayName: Service Monitors
path: observability.metrics.serviceMonitors
+ - description: Query defines query configuration.
+ displayName: Query Configuration
+ path: query
+ x-descriptors:
+ - urn:alm:descriptor:com.tectonic.ui:advanced
+ - description: |-
+ RBAC defines query RBAC options.
+ This option can be used only with multi-tenancy.
+ displayName: Query RBAC Settings
+ path: query.rbac
+ - description: Enabled defines if the query RBAC should be enabled.
+ displayName: Query RBAC Enabled
+ path: query.rbac.enabled
- description: ServiceAccount defines the Service Account to use for all Tempo
components.
displayName: Service Account
@@ -924,7 +937,7 @@ spec:
all pods of this component.
displayName: PodSecurityContext
path: template.gateway.podSecurityContext
- - description: RBAC defines RBAC options.
+ - description: RBAC defines query RBAC options.
displayName: Query RBAC Settings
path: template.gateway.rbac
- description: Enabled defines if the query RBAC should be enabled.
diff --git a/docs/spec/tempo.grafana.com_tempomonolithics.yaml b/docs/spec/tempo.grafana.com_tempomonolithics.yaml
index 87c39b640..ae9e2c528 100644
--- a/docs/spec/tempo.grafana.com_tempomonolithics.yaml
+++ b/docs/spec/tempo.grafana.com_tempomonolithics.yaml
@@ -111,6 +111,9 @@ spec: # TempoMonolithicSpec defines the desir
enabled: false # Enabled defines if PrometheusRule objects should be created for this Tempo deployment.
serviceMonitors: # ServiceMonitors defines the ServiceMonitor configuration.
enabled: false # Enabled defines if ServiceMonitor objects should be created for this Tempo deployment.
+ query: # Query defines query configuration.
+ rbac: # RBAC defines query RBAC options. This option can be used only with multi-tenancy.
+ enabled: false # Enabled defines if the query RBAC should be enabled.
serviceAccount: "" # ServiceAccount defines the Service Account to use for all Tempo components.
storage: # Storage defines the storage configuration.
traces: # Traces defines the storage configuration for traces.
diff --git a/docs/spec/tempo.grafana.com_tempostacks.yaml b/docs/spec/tempo.grafana.com_tempostacks.yaml
index 7811f68b9..f1ead0f08 100644
--- a/docs/spec/tempo.grafana.com_tempostacks.yaml
+++ b/docs/spec/tempo.grafana.com_tempostacks.yaml
@@ -206,7 +206,7 @@ spec: # TempoStackSpec defines the desired st
route: # Route defines the options for the OpenShift route.
termination: "" # Termination defines the termination type. The default is "edge".
type: "" # Type defines the type of Ingress for the Jaeger Query UI. Currently ingress, route and none are supported.
- rbac: # RBAC defines RBAC options.
+ rbac: # RBAC defines query RBAC options.
enabled: false # Enabled defines if the query RBAC should be enabled.
ingester: # Ingester defines the ingester component spec.
podSecurityContext: # PodSecurityContext defines security context will be applied to all pods of this component.
diff --git a/internal/manifests/monolithic/statefulset.go b/internal/manifests/monolithic/statefulset.go
index 7d2a7e315..5f0cb9fd8 100644
--- a/internal/manifests/monolithic/statefulset.go
+++ b/internal/manifests/monolithic/statefulset.go
@@ -431,6 +431,10 @@ func configureGateway(opts Options, sts *appsv1.StatefulSet) error {
args = append(args, fmt.Sprintf("--traces.read.endpoint=http://localhost:%d", manifestutils.PortJaegerQuery)) // Jaeger UI upstream
}
+ if tempo.Spec.Query != nil && tempo.Spec.Query.RBAC.Enabled {
+ args = append(args, "--traces.query-rbac=true")
+ }
+
if opts.CtrlConfig.Gates.OpenShift.ServingCertsService {
args = append(args, []string{
fmt.Sprintf("--tls.server.cert-file=%s", path.Join(servingCertDir, "tls.crt")), // TLS of public HTTP (8080) and gRPC (8090) server
diff --git a/internal/manifests/monolithic/statefulset_test.go b/internal/manifests/monolithic/statefulset_test.go
index 3de1df570..1c79f6d5e 100644
--- a/internal/manifests/monolithic/statefulset_test.go
+++ b/internal/manifests/monolithic/statefulset_test.go
@@ -994,3 +994,289 @@ func TestStatefulsetGateway(t *testing.T) {
},
}, sts.Spec.Template.Spec.Containers[4])
}
+
+func TestStatefulsetGatewayRBAC(t *testing.T) {
+ opts := Options{
+ CtrlConfig: configv1alpha1.ProjectConfig{
+ DefaultImages: configv1alpha1.ImagesSpec{
+ TempoGateway: "quay.io/observatorium/api:x.y.z",
+ TempoGatewayOpa: "quay.io/observatorium/opa-openshift:x.y.z",
+ },
+ Gates: configv1alpha1.FeatureGates{
+ OpenShift: configv1alpha1.OpenShiftFeatureGates{
+ ServingCertsService: true,
+ },
+ },
+ },
+ Tempo: v1alpha1.TempoMonolithic{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "sample",
+ Namespace: "default",
+ },
+ Spec: v1alpha1.TempoMonolithicSpec{
+ Timeout: metav1.Duration{Duration: time.Second * 5},
+ Storage: &v1alpha1.MonolithicStorageSpec{
+ Traces: v1alpha1.MonolithicTracesStorageSpec{
+ Backend: "memory",
+ },
+ },
+ Ingestion: &v1alpha1.MonolithicIngestionSpec{
+ OTLP: &v1alpha1.MonolithicIngestionOTLPSpec{
+ GRPC: &v1alpha1.MonolithicIngestionOTLPProtocolsGRPCSpec{
+ Enabled: true,
+ },
+ },
+ },
+ JaegerUI: &v1alpha1.MonolithicJaegerUISpec{
+ Enabled: false,
+ },
+ Query: &v1alpha1.MonolithicQuerySpec{
+ RBAC: v1alpha1.RBACSpec{
+ Enabled: true,
+ },
+ },
+ Multitenancy: &v1alpha1.MonolithicMultitenancySpec{
+ Enabled: true,
+ TenantsSpec: v1alpha1.TenantsSpec{
+ Mode: v1alpha1.ModeOpenShift,
+ Authentication: []v1alpha1.AuthenticationSpec{
+ {
+ TenantName: "dev",
+ TenantID: "1610b0c3-c509-4592-a256-a1871353dbfa",
+ },
+ {
+ TenantName: "prod",
+ TenantID: "1610b0c3-c509-4592-a256-a1871353dbfb",
+ },
+ },
+ },
+ Resources: &corev1.ResourceRequirements{
+ Requests: corev1.ResourceList{
+ corev1.ResourceCPU: resource.MustParse("1Gi"),
+ corev1.ResourceMemory: resource.MustParse("2Gi"),
+ },
+ Limits: corev1.ResourceList{
+ corev1.ResourceCPU: resource.MustParse("3Gi"),
+ corev1.ResourceMemory: resource.MustParse("4Gi"),
+ },
+ },
+ },
+ },
+ },
+ }
+ sts, err := BuildTempoStatefulset(opts, map[string]string{})
+ require.NoError(t, err)
+
+ require.Equal(t, corev1.Container{
+ Name: "tempo-gateway",
+ Image: "quay.io/observatorium/api:x.y.z",
+ Env: proxy.ReadProxyVarsFromEnv(),
+ Args: []string{
+ "--web.listen=0.0.0.0:8080",
+ "--web.internal.listen=0.0.0.0:8081",
+ "--traces.tenant-header=x-scope-orgid",
+ "--traces.tempo.endpoint=http://localhost:3200",
+ "--traces.write-timeout=5s",
+ "--rbac.config=/etc/tempo-gateway/rbac/rbac.yaml",
+ "--tenants.config=/etc/tempo-gateway/tenants/tenants.yaml",
+ "--log.level=info",
+ "--grpc.listen=0.0.0.0:8090",
+ "--traces.write.otlpgrpc.endpoint=localhost:4317",
+ "--traces.write.otlphttp.endpoint=http://localhost:4318",
+ "--traces.query-rbac=true",
+ "--tls.server.cert-file=/etc/tempo-gateway/serving-cert/tls.crt",
+ "--tls.server.key-file=/etc/tempo-gateway/serving-cert/tls.key",
+ "--tls.healthchecks.server-ca-file=/etc/tempo-gateway/serving-ca/service-ca.crt",
+ "--tls.healthchecks.server-name=tempo-sample-gateway.default.svc.cluster.local",
+ "--web.healthchecks.url=https://localhost:8080",
+ "--tls.client-auth-type=NoClientCert",
+ },
+ Ports: []corev1.ContainerPort{
+ {
+ Name: "public",
+ ContainerPort: 8080,
+ Protocol: corev1.ProtocolTCP,
+ },
+ {
+ Name: "internal",
+ ContainerPort: 8081,
+ Protocol: corev1.ProtocolTCP,
+ },
+ {
+ Name: "grpc-public",
+ ContainerPort: 8090,
+ Protocol: corev1.ProtocolTCP,
+ },
+ },
+ LivenessProbe: &corev1.Probe{
+ ProbeHandler: corev1.ProbeHandler{
+ HTTPGet: &corev1.HTTPGetAction{
+ Path: "/live",
+ Port: intstr.FromString("internal"),
+ Scheme: corev1.URISchemeHTTP,
+ },
+ },
+ TimeoutSeconds: 2,
+ PeriodSeconds: 30,
+ FailureThreshold: 10,
+ },
+ ReadinessProbe: &corev1.Probe{
+ ProbeHandler: corev1.ProbeHandler{
+ HTTPGet: &corev1.HTTPGetAction{
+ Path: "/ready",
+ Port: intstr.FromString("internal"),
+ Scheme: corev1.URISchemeHTTP,
+ },
+ },
+ TimeoutSeconds: 1,
+ PeriodSeconds: 5,
+ FailureThreshold: 12,
+ },
+ VolumeMounts: []corev1.VolumeMount{
+ {
+ Name: "gateway-rbac",
+ ReadOnly: true,
+ MountPath: "/etc/tempo-gateway/rbac",
+ },
+ {
+ Name: "gateway-tenants",
+ ReadOnly: true,
+ MountPath: "/etc/tempo-gateway/tenants",
+ },
+ {
+ Name: "tempo-sample-serving-cabundle",
+ ReadOnly: true,
+ MountPath: "/etc/tempo-gateway/serving-ca",
+ },
+ {
+ Name: "tempo-sample-gateway-serving-cert",
+ ReadOnly: true,
+ MountPath: "/etc/tempo-gateway/serving-cert",
+ },
+ },
+ Resources: corev1.ResourceRequirements{
+ Requests: corev1.ResourceList{
+ corev1.ResourceCPU: resource.MustParse("1Gi"),
+ corev1.ResourceMemory: resource.MustParse("2Gi"),
+ },
+ Limits: corev1.ResourceList{
+ corev1.ResourceCPU: resource.MustParse("3Gi"),
+ corev1.ResourceMemory: resource.MustParse("4Gi"),
+ },
+ },
+ SecurityContext: manifestutils.TempoContainerSecurityContext(),
+ }, sts.Spec.Template.Spec.Containers[1])
+
+ require.Equal(t, []corev1.Volume{
+ {
+ Name: "gateway-rbac",
+ VolumeSource: corev1.VolumeSource{
+ ConfigMap: &corev1.ConfigMapVolumeSource{
+ LocalObjectReference: corev1.LocalObjectReference{
+ Name: "tempo-sample-gateway",
+ },
+ Items: []corev1.KeyToPath{
+ {
+ Key: "rbac.yaml",
+ Path: "rbac.yaml",
+ },
+ },
+ },
+ },
+ },
+ {
+ Name: "gateway-tenants",
+ VolumeSource: corev1.VolumeSource{
+ Secret: &corev1.SecretVolumeSource{
+ SecretName: "tempo-sample-gateway",
+ Items: []corev1.KeyToPath{
+ {
+ Key: "tenants.yaml",
+ Path: "tenants.yaml",
+ },
+ },
+ },
+ },
+ },
+ {
+ Name: "tempo-sample-serving-cabundle",
+ VolumeSource: corev1.VolumeSource{
+ ConfigMap: &corev1.ConfigMapVolumeSource{
+ LocalObjectReference: corev1.LocalObjectReference{
+ Name: "tempo-sample-serving-cabundle",
+ },
+ },
+ },
+ },
+ {
+ Name: "tempo-sample-gateway-serving-cert",
+ VolumeSource: corev1.VolumeSource{
+ Secret: &corev1.SecretVolumeSource{
+ SecretName: "tempo-sample-gateway-serving-cert",
+ },
+ },
+ },
+ }, sts.Spec.Template.Spec.Volumes[2:])
+
+ require.Equal(t, corev1.Container{
+ Name: "tempo-gateway-opa",
+ Image: "quay.io/observatorium/opa-openshift:x.y.z",
+ Args: []string{
+ "--log.level=warn",
+ "--opa.admin-groups=system:cluster-admins,cluster-admin,dedicated-admin",
+ "--opa.matcher=kubernetes_namespace_name",
+ "--web.listen=:8082",
+ "--web.internal.listen=:8083",
+ "--web.healthchecks.url=http://localhost:8082",
+ "--opa.package=tempomonolithic",
+ "--openshift.mappings=dev=tempo.grafana.com",
+ "--openshift.mappings=prod=tempo.grafana.com",
+ },
+ Ports: []corev1.ContainerPort{
+ {
+ Name: "public",
+ ContainerPort: 8082,
+ Protocol: corev1.ProtocolTCP,
+ },
+ {
+ Name: "opa-metrics",
+ ContainerPort: 8083,
+ Protocol: corev1.ProtocolTCP,
+ },
+ },
+ LivenessProbe: &corev1.Probe{
+ ProbeHandler: corev1.ProbeHandler{
+ HTTPGet: &corev1.HTTPGetAction{
+ Path: "/live",
+ Port: intstr.FromInt(8083),
+ Scheme: corev1.URISchemeHTTP,
+ },
+ },
+ TimeoutSeconds: 2,
+ PeriodSeconds: 30,
+ FailureThreshold: 10,
+ },
+ ReadinessProbe: &corev1.Probe{
+ ProbeHandler: corev1.ProbeHandler{
+ HTTPGet: &corev1.HTTPGetAction{
+ Path: "/ready",
+ Port: intstr.FromInt(8083),
+ Scheme: corev1.URISchemeHTTP,
+ },
+ },
+ TimeoutSeconds: 1,
+ PeriodSeconds: 5,
+ FailureThreshold: 12,
+ },
+ Resources: corev1.ResourceRequirements{
+ Requests: corev1.ResourceList{
+ corev1.ResourceCPU: resource.MustParse("1Gi"),
+ corev1.ResourceMemory: resource.MustParse("2Gi"),
+ },
+ Limits: corev1.ResourceList{
+ corev1.ResourceCPU: resource.MustParse("3Gi"),
+ corev1.ResourceMemory: resource.MustParse("4Gi"),
+ },
+ },
+ }, sts.Spec.Template.Spec.Containers[2])
+}
diff --git a/internal/webhooks/tempomonolithic_webhook.go b/internal/webhooks/tempomonolithic_webhook.go
index 8c260c858..8bd5cb4b2 100644
--- a/internal/webhooks/tempomonolithic_webhook.go
+++ b/internal/webhooks/tempomonolithic_webhook.go
@@ -141,11 +141,24 @@ func (v *monolithicValidator) validateJaegerUI(tempo tempov1alpha1.TempoMonolith
"the openshiftRoute feature gate must be enabled to create a route for Jaeger UI",
)}
}
+ if tempo.Spec.Query != nil && tempo.Spec.Query.RBAC.Enabled && tempo.Spec.JaegerUI.Enabled {
+ return field.ErrorList{
+ field.Invalid(field.NewPath("spec", "rbac", "enabled"), tempo.Spec.Query.RBAC.Enabled,
+ "cannot enable RBAC and jaeger query at the same time. The Jaeger UI does not support query RBAC",
+ )}
+ }
return nil
}
func (v *monolithicValidator) validateMultitenancy(tempo tempov1alpha1.TempoMonolithic) field.ErrorList {
+ if tempo.Spec.Query != nil && tempo.Spec.Query.RBAC.Enabled && (tempo.Spec.Multitenancy == nil || !tempo.Spec.Multitenancy.Enabled) {
+ return field.ErrorList{
+ field.Invalid(field.NewPath("spec", "rbac", "enabled"), tempo.Spec.Query.RBAC.Enabled,
+ "RBAC can only be enabled if multi-tenancy is enabled",
+ )}
+ }
+
if !tempo.Spec.Multitenancy.IsGatewayEnabled() {
return nil
}
diff --git a/internal/webhooks/tempomonolithic_webhook_test.go b/internal/webhooks/tempomonolithic_webhook_test.go
index 61fdc5e08..54110c0e3 100644
--- a/internal/webhooks/tempomonolithic_webhook_test.go
+++ b/internal/webhooks/tempomonolithic_webhook_test.go
@@ -148,6 +148,70 @@ func TestMonolithicValidate(t *testing.T) {
"spec.tenants.authorization should not be defined in openshift mode",
)},
},
+ {
+ name: "RBAC and jaeger UI enabled",
+ tempo: v1alpha1.TempoMonolithic{
+ Spec: v1alpha1.TempoMonolithicSpec{
+ Query: &v1alpha1.MonolithicQuerySpec{
+ RBAC: v1alpha1.RBACSpec{
+ Enabled: true,
+ },
+ },
+ JaegerUI: &v1alpha1.MonolithicJaegerUISpec{
+ Enabled: true,
+ },
+ Multitenancy: &v1alpha1.MonolithicMultitenancySpec{
+ Enabled: true,
+ },
+ },
+ },
+ warnings: admission.Warnings{},
+ errors: field.ErrorList{field.Invalid(
+ field.NewPath("spec", "rbac", "enabled"),
+ true,
+ "cannot enable RBAC and jaeger query at the same time. The Jaeger UI does not support query RBAC",
+ )},
+ },
+
+ {
+ name: "RBAC and multitenancy disabled",
+ tempo: v1alpha1.TempoMonolithic{
+ Spec: v1alpha1.TempoMonolithicSpec{
+ Query: &v1alpha1.MonolithicQuerySpec{
+ RBAC: v1alpha1.RBACSpec{
+ Enabled: true,
+ },
+ },
+ Multitenancy: &v1alpha1.MonolithicMultitenancySpec{
+ Enabled: false,
+ },
+ },
+ },
+ warnings: admission.Warnings{},
+ errors: field.ErrorList{field.Invalid(
+ field.NewPath("spec", "rbac", "enabled"),
+ true,
+ "RBAC can only be enabled if multi-tenancy is enabled",
+ )},
+ },
+ {
+ name: "RBAC and multitenancy nil",
+ tempo: v1alpha1.TempoMonolithic{
+ Spec: v1alpha1.TempoMonolithicSpec{
+ Query: &v1alpha1.MonolithicQuerySpec{
+ RBAC: v1alpha1.RBACSpec{
+ Enabled: true,
+ },
+ },
+ },
+ },
+ warnings: admission.Warnings{},
+ errors: field.ErrorList{field.Invalid(
+ field.NewPath("spec", "rbac", "enabled"),
+ true,
+ "RBAC can only be enabled if multi-tenancy is enabled",
+ )},
+ },
// observability
{