fix(iam): invalidate peer STS caches on revocation (#5718)

This commit is contained in:
Zhengchao An
2026-08-05 09:17:36 +08:00
committed by GitHub
parent 327fdd5fc2
commit 4576c2e470
7 changed files with 992 additions and 75 deletions
+25 -13
View File
@@ -28,7 +28,10 @@ use crate::{
use futures::future::join_all;
use rustfs_io_metrics::record_system_path_failure;
use rustfs_policy::{auth::UserIdentity, policy::PolicyDoc};
use rustfs_utils::path::{SLASH_SEPARATOR, path_join_buf};
use rustfs_utils::{
MaskedAccessKey,
path::{SLASH_SEPARATOR, path_join_buf},
};
use serde::{Serialize, de::DeserializeOwned};
use std::sync::{LazyLock, Mutex};
use std::time::{Duration, Instant};
@@ -600,10 +603,10 @@ impl ObjectStore {
.await
.map_err(|err| {
if is_err_config_not_found(&err) {
warn!(name, user_type = ?user_type, "IAM user identity missing");
debug!(name = %MaskedAccessKey(name), user_type = ?user_type, "IAM user identity missing");
Error::NoSuchUser(name.to_owned())
} else {
warn!(name, user_type = ?user_type, error = ?err, "IAM user identity load failed");
warn!(name = %MaskedAccessKey(name), user_type = ?user_type, error = ?err, "IAM user identity load failed");
err
}
})?;
@@ -611,7 +614,7 @@ impl ObjectStore {
if u.credentials.is_expired() {
let _ = self.delete_iam_config(get_user_identity_path(name, user_type)).await;
let _ = self.delete_iam_config(get_mapped_policy_path(name, user_type, false)).await;
warn!(name, user_type = ?user_type, "IAM user identity expired and was removed");
warn!(name = %MaskedAccessKey(name), user_type = ?user_type, "IAM user identity expired and was removed");
return Err(Error::NoSuchUser(name.to_owned()));
}
@@ -635,7 +638,7 @@ impl ObjectStore {
let _ = self.delete_iam_config(get_user_identity_path(name, user_type)).await;
let _ = self.delete_iam_config(get_mapped_policy_path(name, user_type, false)).await;
}
warn!(name, user_type = ?user_type, error = ?err, "IAM JWT claim extraction failed");
warn!(name = %MaskedAccessKey(name), user_type = ?user_type, error = ?err, "IAM JWT claim extraction failed");
return Err(Error::NoSuchUser(name.to_owned()));
}
}
@@ -873,13 +876,7 @@ impl Store for ObjectStore {
async fn delete_user_identity(&self, name: &str, user_type: UserType) -> Result<()> {
self.delete_iam_config(get_user_identity_path(name, user_type))
.await
.map_err(|err| {
if is_err_config_not_found(&err) {
Error::NoSuchPolicy
} else {
err
}
})?;
.map_err(|err| map_delete_user_identity_error(name, err))?;
Ok(())
}
async fn load_user_identity(&self, name: &str, user_type: UserType) -> Result<UserIdentity> {
@@ -1327,9 +1324,18 @@ impl Store for ObjectStore {
}
}
fn map_delete_user_identity_error(name: &str, err: Error) -> Error {
if is_err_config_not_found(&err) {
Error::NoSuchUser(name.to_owned())
} else {
err
}
}
#[cfg(test)]
mod tests {
use super::{DecryptSource, LoadMode, ObjectStore};
use super::{DecryptSource, LoadMode, ObjectStore, map_delete_user_identity_error};
use crate::error::Error;
use crate::keyring;
use rustfs_credentials::{Credentials, init_global_action_credentials};
use serial_test::serial;
@@ -1352,6 +1358,12 @@ mod tests {
assert!(!LoadMode::Locked.read_opts().no_lock);
}
#[test]
fn missing_user_identity_delete_maps_to_no_such_user() {
let err = map_delete_user_identity_error("missing-sts", Error::ConfigNotFound);
assert!(matches!(err, Error::NoSuchUser(name) if name == "missing-sts"));
}
fn test_cred() -> Credentials {
if let Some(cred) = crate::root_credentials::credentials() {
return cred;