AssumeRoleHandle done

This commit is contained in:
weisd
2024-12-10 16:59:27 +08:00
parent 637d614618
commit 8172c4f06a
21 changed files with 339 additions and 59 deletions
+1
View File
@@ -67,6 +67,7 @@ atoi = "2.0.0"
serde_urlencoded = "0.7.1"
crypto = { path = "../crypto" }
iam = { path = "../iam" }
jsonwebtoken = "9.3.0"
[build-dependencies]
prost-build.workspace = true
+78 -9
View File
@@ -20,6 +20,7 @@ use ecstore::GLOBAL_Endpoints;
use futures::{Stream, StreamExt};
use http::Uri;
use hyper::StatusCode;
use iam::get_global_action_cred;
use madmin::metrics::RealtimeMetrics;
use madmin::utils::parse_duration;
use matchit::Params;
@@ -47,6 +48,9 @@ use tracing::{error, info, warn};
pub mod service_account;
pub mod trace;
const ASSUME_ROLE_ACTION: &str = "AssumeRole";
const ASSUME_ROLE_VERSION: &str = "2011-06-15";
#[derive(Deserialize, Debug, Default)]
#[serde(rename_all = "PascalCase", default)]
pub struct AssumeRoleRequest {
@@ -85,13 +89,30 @@ pub struct AssumeRoleRequest {
// pub parent_user: String,
// }
#[derive(Debug, Serialize, Default)]
pub struct STSClaims {
parent: String,
exp: usize,
access_key: String,
}
fn get_token_signing_key() -> Option<String> {
if let Some(s) = get_global_action_cred() {
Some(s.secret_key.clone())
} else {
None
}
}
pub struct AssumeRoleHandle {}
#[async_trait::async_trait]
impl Operation for AssumeRoleHandle {
async fn call(&self, req: S3Request<Body>, _params: Params<'_, '_>) -> S3Result<S3Response<(StatusCode, Body)>> {
warn!("handle AssumeRoleHandle");
let Some(cred) = req.credentials else { return Err(s3_error!(InvalidRequest, "get cred failed")) };
let Some(user) = req.credentials else { return Err(s3_error!(InvalidRequest, "get cred failed")) };
// TODO: 判断权限, 不允许sts访问
let mut input = req.input;
@@ -100,17 +121,67 @@ impl Operation for AssumeRoleHandle {
};
let body: AssumeRoleRequest = from_bytes(&bytes).map_err(|_e| s3_error!(InvalidRequest, "get body failed"))?;
warn!("AssumeRole get body {:?}", body);
if body.action.as_str() != ASSUME_ROLE_ACTION {
return Err(s3_error!(InvalidArgument, "not suport action"));
}
let exp = OffsetDateTime::now_utc().saturating_add(Duration::days(1));
if body.version.as_str() != ASSUME_ROLE_VERSION {
return Err(s3_error!(InvalidArgument, "not suport version"));
}
warn!("AssumeRole get cred {:?}", &user);
warn!("AssumeRole get body {:?}", &body);
let Ok(iam_store) = iam::get() else { return Err(s3_error!(InvalidRequest, "iam not init")) };
if let Err(_err) = iam_store.policy_db_get(&user.access_key, None).await {
return Err(s3_error!(InvalidArgument, "invalid policy arg"));
}
let Some(secret) = get_token_signing_key() else {
return Err(s3_error!(InvalidArgument, "sk not init"));
};
let exp = {
if body.duration_seconds > 0 {
body.duration_seconds
} else {
3600
}
};
let mut claims = STSClaims {
parent: user.access_key.clone(),
exp,
..Default::default()
};
let ak = iam::utils::gen_access_key(20).unwrap_or_default();
let sk = iam::utils::gen_secret_key(32).unwrap_or_default();
claims.access_key = ak.clone();
let mut cred = match iam::auth::Credentials::create_new_credentials_with_metadata(&ak, &sk, &claims, &secret, Some(exp)) {
Ok(res) => res,
Err(_er) => return Err(s3_error!(InvalidRequest, "")),
};
cred.parent_user = user.access_key.clone();
if let Err(err) = iam_store.set_temp_user(&cred.access_key, &cred, "").await {
error!("set_temp_user err {:?}", err);
return Err(s3_error!(InternalError, "set_temp_user failed"));
}
// TODO: create tmp access_key
let resp = AssumeRoleOutput {
credentials: Some(Credentials {
access_key_id: cred.access_key,
expiration: Timestamp::from(exp),
secret_access_key: cred.secret_key.expose().to_string(),
session_token: "sdfsdf".to_owned(),
expiration: Timestamp::from(
cred.expiration
.unwrap_or(OffsetDateTime::now_utc().saturating_add(Duration::seconds(3600))),
),
secret_access_key: cred.secret_key,
session_token: cred.session_token,
}),
..Default::default()
};
@@ -119,8 +190,6 @@ impl Operation for AssumeRoleHandle {
let output = xml::serialize::<AssumeRoleOutput>(&resp).unwrap();
Ok(S3Response::new((StatusCode::OK, Body::from(output))))
// return Err(s3_error!(NotImplemented));
}
}
+39
View File
@@ -0,0 +1,39 @@
use iam::cache::CacheInner;
use s3s::auth::S3Auth;
use s3s::auth::SecretKey;
use s3s::auth::SimpleAuth;
use s3s::s3_error;
use s3s::S3Result;
pub struct IAMAuth {
simple_auth: SimpleAuth,
}
impl IAMAuth {
pub fn new(ak: impl Into<String>, sk: impl Into<SecretKey>) -> Self {
let simple_auth = SimpleAuth::from_single(ak, sk);
Self { simple_auth }
}
}
#[async_trait::async_trait]
impl S3Auth for IAMAuth {
async fn get_secret_key(&self, access_key: &str) -> S3Result<SecretKey> {
if access_key.is_empty() {
return Err(s3_error!(NotSignedUp, "Your account is not signed up"));
}
if let Ok(key) = self.simple_auth.get_secret_key(access_key).await {
return Ok(key);
}
if let Ok(iam_store) = iam::get() {
let c = CacheInner::from(&iam_store.cache);
if let Some(id) = c.get_user(access_key) {
return Ok(SecretKey::from(id.credentials.secret_key.clone()));
}
}
Err(s3_error!(NotSignedUp, "Your account is not signed up2"))
}
}
+7 -3
View File
@@ -1,8 +1,10 @@
mod admin;
mod auth;
mod config;
mod grpc;
mod service;
mod storage;
use crate::auth::IAMAuth;
use clap::Parser;
use common::{
error::{Error, Result},
@@ -26,7 +28,7 @@ use hyper_util::{
};
use iam::init_iam_sys;
use protos::proto_gen::node_service::node_service_server::NodeServiceServer;
use s3s::{auth::SimpleAuth, service::S3ServiceBuilder};
use s3s::service::S3ServiceBuilder;
use service::hybrid;
use std::{io::IsTerminal, net::SocketAddr, str::FromStr};
use tokio::net::TcpListener;
@@ -87,6 +89,7 @@ async fn run(opt: config::Opt) -> Result<()> {
debug!("server_address {}", &server_address);
iam::init_global_action_cred(None, None).unwrap();
set_global_rustfs_port(server_port);
//监听地址,端口从参数中获取
@@ -133,7 +136,7 @@ async fn run(opt: config::Opt) -> Result<()> {
}
//显示info信息
info!("authentication is enabled {}, {}", &access_key, &secret_key);
b.set_auth(SimpleAuth::from_single(access_key, secret_key));
b.set_auth(IAMAuth::new(access_key, secret_key));
b.set_access(store.clone());
@@ -212,6 +215,8 @@ async fn run(opt: config::Opt) -> Result<()> {
})?;
warn!(" init store success!");
init_iam_sys(store.clone()).await.unwrap();
new_global_notification_sys(endpoint_pools.clone()).await.map_err(|err| {
error!("new_global_notification_sys faild {:?}", &err);
Error::from_string(err.to_string())
@@ -221,7 +226,6 @@ async fn run(opt: config::Opt) -> Result<()> {
init_data_scanner().await;
// init auto heal
init_auto_heal().await;
init_iam_sys(store.clone()).await.unwrap();
info!("server was started");