diff --git a/crates/policy/src/policy/action.rs b/crates/policy/src/policy/action.rs
index 19f9bc098..c01fa0a30 100644
--- a/crates/policy/src/policy/action.rs
+++ b/crates/policy/src/policy/action.rs
@@ -500,6 +500,8 @@ pub enum AdminAction {
SetBucketTargetAction,
#[strum(serialize = "admin:GetBucketTarget")]
GetBucketTargetAction,
+ #[strum(serialize = "admin:GetMetrics")]
+ GetMetricsAction,
#[strum(serialize = "admin:ReplicationDiff")]
ReplicationDiff,
#[strum(serialize = "admin:GetReplicationMetrics")]
@@ -656,6 +658,7 @@ impl AdminAction {
| AdminAction::SetBucketQuotaAdminAction
| AdminAction::SetBucketTargetAction
| AdminAction::GetBucketTargetAction
+ | AdminAction::GetMetricsAction
| AdminAction::ReplicationDiff
| AdminAction::GetReplicationMetricsAction
| AdminAction::ImportBucketMetadataAction
@@ -820,6 +823,11 @@ mod tests {
assert!(AdminAction::GetReplicationMetricsAction.is_valid());
}
+ #[test]
+ fn test_get_metrics_admin_action_is_valid() {
+ assert!(AdminAction::GetMetricsAction.is_valid());
+ }
+
#[test]
fn test_table_catalog_admin_action_is_valid() {
let get_action = AdminAction::try_from("admin:GetTableCatalog").expect("Should parse GetTableCatalog action");
diff --git a/rustfs/src/admin/handlers/metrics.rs b/rustfs/src/admin/handlers/metrics.rs
index 0ae43236f..872e5a23a 100644
--- a/rustfs/src/admin/handlers/metrics.rs
+++ b/rustfs/src/admin/handlers/metrics.rs
@@ -18,7 +18,10 @@
//! keeping the response format explicitly NDJSON. It is not a Prometheus text
//! exposition endpoint.
+use crate::admin::auth::validate_admin_request;
use crate::admin::router::Operation;
+use crate::auth::{check_key_valid, get_session_token};
+use crate::server::RemoteAddr;
use crate::storage::request_context::spawn_traced;
use bytes::Bytes;
use futures::{Stream, StreamExt};
@@ -28,6 +31,7 @@ use matchit::Params;
use rustfs_ecstore::metrics_realtime::{CollectMetricsOpts, MetricType, collect_local_metrics};
use rustfs_madmin::metrics::RealtimeMetrics;
use rustfs_madmin::utils::parse_duration;
+use rustfs_policy::policy::action::{Action, AdminAction};
use s3s::header::CONTENT_TYPE;
use s3s::stream::{ByteStream, DynByteStream};
use s3s::{Body, S3Request, S3Response, S3Result, StdError, s3_error};
@@ -178,14 +182,32 @@ impl ByteStream for MetricsStream {}
pub struct MetricsHandler {}
+async fn authorize_metrics_request(req: &S3Request
) -> S3Result<()> {
+ let Some(input_cred) = req.credentials.as_ref() else {
+ return Err(s3_error!(AccessDenied, "Signature is required"));
+ };
+
+ let (cred, owner) =
+ check_key_valid(get_session_token(&req.uri, &req.headers).unwrap_or_default(), &input_cred.access_key).await?;
+ let remote_addr = req.extensions.get::