Skip to content

Commit 5d5a265

Browse files
add validation for otel datasets
1 parent f0e3e02 commit 5d5a265

5 files changed

Lines changed: 51 additions & 16 deletions

File tree

src/handlers/http/datasets.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,24 @@ use actix_web::http::StatusCode;
2222
use actix_web::{HttpRequest, HttpResponse, web};
2323
use serde::{Deserialize, Serialize};
2424

25+
use crate::rbac::{self, Users, role::Action};
26+
use crate::utils::actix::extract_session_key_from_req;
2527
use crate::utils::get_tenant_id_from_request;
2628
use crate::{
2729
handlers::DatasetTag,
2830
parseable::PARSEABLE,
2931
storage::{ObjectStorageError, StreamType},
3032
};
3133

34+
/// Check if the caller is authorized to read a specific stream.
35+
fn can_access_stream(req: &HttpRequest, stream_name: &str) -> bool {
36+
let Ok(key) = extract_session_key_from_req(req) else {
37+
return false;
38+
};
39+
Users.authorize(key, Action::GetStreamInfo, Some(stream_name), None)
40+
== rbac::Response::Authorized
41+
}
42+
3243
#[derive(Debug, Serialize)]
3344
#[serde(rename_all = "camelCase")]
3445
struct CorrelatedDataset {
@@ -39,12 +50,19 @@ struct CorrelatedDataset {
3950

4051
/// GET /api/v1/datasets/{name}/correlated
4152
/// Returns all datasets sharing at least one tag or label with the named dataset.
53+
/// Results are filtered to only include datasets the caller is authorized to read.
4254
pub async fn get_correlated_datasets(
4355
req: HttpRequest,
4456
path: web::Path<String>,
4557
) -> Result<HttpResponse, DatasetsError> {
4658
let dataset_name = path.into_inner();
4759
let tenant_id = get_tenant_id_from_request(&req);
60+
61+
// Authorize caller for the seed dataset
62+
if !can_access_stream(&req, &dataset_name) {
63+
return Err(DatasetsError::DatasetNotFound(dataset_name));
64+
}
65+
4866
let stream = PARSEABLE
4967
.get_stream(&dataset_name, &tenant_id)
5068
.map_err(|_| DatasetsError::DatasetNotFound(dataset_name.clone()))?;
@@ -63,6 +81,10 @@ pub async fn get_correlated_datasets(
6381
if name == dataset_name {
6482
continue;
6583
}
84+
// Filter out datasets the caller cannot read
85+
if !can_access_stream(&req, &name) {
86+
continue;
87+
}
6688
if let Ok(s) = PARSEABLE.get_stream(&name, &tenant_id) {
6789
// Skip internal streams
6890
if s.get_stream_type() == StreamType::Internal {
@@ -91,6 +113,7 @@ pub async fn get_correlated_datasets(
91113

92114
/// GET /api/v1/datasets/tags/{tag}
93115
/// Returns all datasets that have the specified tag.
116+
/// Results are filtered to only include datasets the caller is authorized to read.
94117
pub async fn get_datasets_by_tag(
95118
req: HttpRequest,
96119
path: web::Path<String>,
@@ -104,6 +127,10 @@ pub async fn get_datasets_by_tag(
104127
let mut matching = Vec::new();
105128

106129
for name in all_streams {
130+
// Filter out datasets the caller cannot read
131+
if !can_access_stream(&req, &name) {
132+
continue;
133+
}
107134
if let Ok(s) = PARSEABLE.get_stream(&name, &tenant_id) {
108135
if s.get_stream_type() == StreamType::Internal {
109136
continue;

src/handlers/http/ingest.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use crate::event::format::{self, EventFormat, LogSource, LogSourceEntry};
3232
use crate::event::{self, FORMAT_KEY, USER_AGENT_KEY};
3333
use crate::handlers::http::modal::utils::ingest_utils::validate_stream_for_ingestion;
3434
use crate::handlers::{
35-
CONTENT_TYPE_JSON, CONTENT_TYPE_PROTOBUF, EXTRACT_LOG_KEY, LOG_SOURCE_KEY,
35+
CONTENT_TYPE_JSON, CONTENT_TYPE_PROTOBUF, DatasetTag, EXTRACT_LOG_KEY, LOG_SOURCE_KEY,
3636
STREAM_NAME_HEADER_KEY, TELEMETRY_TYPE_KEY, TelemetryType,
3737
};
3838
use crate::metadata::SchemaVersion;
@@ -207,6 +207,8 @@ pub async fn setup_otel_stream(
207207
expected_log_source: LogSource,
208208
known_fields: &[&str],
209209
telemetry_type: TelemetryType,
210+
dataset_tags: Vec<DatasetTag>,
211+
dataset_labels: Vec<String>,
210212
) -> Result<(String, LogSource, LogSourceEntry, Option<String>), PostError> {
211213
let Some(stream_name) = req.headers().get(STREAM_NAME_HEADER_KEY) else {
212214
return Err(PostError::Header(ParseHeaderError::MissingStreamName));
@@ -240,8 +242,8 @@ pub async fn setup_otel_stream(
240242
vec![log_source_entry.clone()],
241243
telemetry_type,
242244
&tenant_id,
243-
vec![],
244-
vec![],
245+
dataset_tags,
246+
dataset_labels,
245247
)
246248
.await?;
247249
let mut time_partition = None;
@@ -364,6 +366,8 @@ pub async fn handle_otel_logs_ingestion(
364366
LogSource::OtelLogs,
365367
&OTEL_LOG_KNOWN_FIELD_LIST,
366368
TelemetryType::Logs,
369+
vec![],
370+
vec![],
367371
)
368372
.await
369373
.map_err(|e| {
@@ -388,6 +392,8 @@ pub async fn handle_otel_metrics_ingestion(
388392
LogSource::OtelMetrics,
389393
&OTEL_METRICS_KNOWN_FIELD_LIST,
390394
TelemetryType::Metrics,
395+
vec![],
396+
vec![],
391397
)
392398
.await
393399
.map_err(|e| {
@@ -419,6 +425,8 @@ pub async fn handle_otel_traces_ingestion(
419425
LogSource::OtelTraces,
420426
&OTEL_TRACES_KNOWN_FIELD_LIST,
421427
TelemetryType::Traces,
428+
vec![],
429+
vec![],
422430
)
423431
.await
424432
.map_err(|e| {

src/handlers/http/modal/server.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,13 +213,13 @@ impl Server {
213213
"/tags/{tag}",
214214
web::get()
215215
.to(http::datasets::get_datasets_by_tag)
216-
.authorize_for_resource(Action::GetStreamInfo),
216+
.authorize(Action::GetStreamInfo),
217217
)
218218
.route(
219219
"/{name}/correlated",
220220
web::get()
221221
.to(http::datasets::get_correlated_datasets)
222-
.authorize_for_resource(Action::GetStreamInfo),
222+
.authorize(Action::GetStreamInfo),
223223
)
224224
.route(
225225
"/{name}",

src/handlers/mod.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,10 @@ impl Display for TelemetryType {
9292
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
9393
#[serde(rename_all = "kebab-case")]
9494
pub enum DatasetTag {
95-
AgentMonitoring,
96-
K8sMonitoring,
95+
AgentObservability,
96+
K8sObservability,
9797
DatabaseObservability,
98-
ApplicationMonitoring,
98+
APM,
9999
ServiceMap,
100100
}
101101

@@ -104,13 +104,13 @@ impl TryFrom<&str> for DatasetTag {
104104

105105
fn try_from(s: &str) -> Result<Self, Self::Error> {
106106
match s.to_lowercase().as_str() {
107-
"agent-monitoring" => Ok(DatasetTag::AgentMonitoring),
108-
"k8s-monitoring" => Ok(DatasetTag::K8sMonitoring),
107+
"agent-observability" => Ok(DatasetTag::AgentObservability),
108+
"k8s-observability" => Ok(DatasetTag::K8sObservability),
109109
"database-observability" => Ok(DatasetTag::DatabaseObservability),
110-
"application-monitoring" => Ok(DatasetTag::ApplicationMonitoring),
110+
"apm" => Ok(DatasetTag::APM),
111111
"service-map" => Ok(DatasetTag::ServiceMap),
112112
_ => Err(
113-
"Invalid dataset tag. Supported values: agent-monitoring, k8s-monitoring, database-observability, application-monitoring, service-map",
113+
"Invalid dataset tag. Supported values: agent-observability, k8s-observability, database-observability, apm, service-map",
114114
),
115115
}
116116
}
@@ -119,10 +119,10 @@ impl TryFrom<&str> for DatasetTag {
119119
impl Display for DatasetTag {
120120
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121121
f.write_str(match self {
122-
DatasetTag::AgentMonitoring => "agent-monitoring",
123-
DatasetTag::K8sMonitoring => "k8s-monitoring",
122+
DatasetTag::AgentObservability => "agent-observability",
123+
DatasetTag::K8sObservability => "k8s-observability",
124124
DatasetTag::DatabaseObservability => "database-observability",
125-
DatasetTag::ApplicationMonitoring => "application-monitoring",
125+
DatasetTag::APM => "apm",
126126
DatasetTag::ServiceMap => "service-map",
127127
})
128128
}

src/parseable/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ impl Parseable {
477477
TelemetryType::Logs,
478478
&tenant_id,
479479
vec![],
480-
vec![]
480+
vec![],
481481
)
482482
.await;
483483

0 commit comments

Comments
 (0)