Merge pull request #287 from rustfs/feature/tls

Add TLS support and replace log crate with tracing crate
This commit is contained in:
houseme
2025-04-02 01:21:37 +08:00
committed by GitHub
15 changed files with 457 additions and 84 deletions
+4 -1
View File
@@ -8,4 +8,7 @@
.devcontainer
rustfs/static/*
vendor
cli/rustfs-gui/embedded-rustfs/rustfs
cli/rustfs-gui/embedded-rustfs/rustfs
.log
config/obs.toml
config/certs/*
Generated
+189 -13
View File
@@ -679,6 +679,29 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "aws-lc-rs"
version = "1.12.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dabb68eb3a7aa08b46fddfd59a3d55c978243557a90ab804769f7e20e67d2b01"
dependencies = [
"aws-lc-sys",
"zeroize",
]
[[package]]
name = "aws-lc-sys"
version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77926887776171ced7d662120a75998e444d3750c951abfe07f90da130514b1f"
dependencies = [
"bindgen",
"cc",
"cmake",
"dunce",
"fs_extra",
]
[[package]]
name = "axum"
version = "0.7.9"
@@ -734,6 +757,29 @@ dependencies = [
"tracing",
]
[[package]]
name = "axum-server"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1ad46c3ec4e12f4a4b6835e173ba21c25e484c9d02b49770bf006ce5367c036"
dependencies = [
"arc-swap",
"bytes",
"futures-util",
"http",
"http-body",
"http-body-util",
"hyper",
"hyper-util",
"pin-project-lite",
"rustls 0.21.12",
"rustls-pemfile",
"tokio",
"tokio-rustls 0.24.1",
"tower 0.4.13",
"tower-service",
]
[[package]]
name = "backon"
version = "1.4.0"
@@ -795,6 +841,29 @@ dependencies = [
"num-traits",
]
[[package]]
name = "bindgen"
version = "0.69.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088"
dependencies = [
"bitflags 2.9.0",
"cexpr",
"clang-sys",
"itertools 0.12.1",
"lazy_static",
"lazycell",
"log",
"prettyplease",
"proc-macro2",
"quote",
"regex",
"rustc-hash 1.1.0",
"shlex",
"syn 2.0.98",
"which",
]
[[package]]
name = "bitflags"
version = "1.3.2"
@@ -1002,6 +1071,15 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
[[package]]
name = "cexpr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
[[package]]
name = "cfb"
version = "0.7.3"
@@ -1133,6 +1211,17 @@ dependencies = [
"zeroize",
]
[[package]]
name = "clang-sys"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
dependencies = [
"glob",
"libc",
"libloading 0.8.6",
]
[[package]]
name = "clap"
version = "4.5.31"
@@ -1173,6 +1262,15 @@ version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
[[package]]
name = "cmake"
version = "0.1.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0"
dependencies = [
"cc",
]
[[package]]
name = "cocoa"
version = "0.25.0"
@@ -3116,6 +3214,12 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "fs_extra"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
[[package]]
name = "futf"
version = "0.1.5"
@@ -3853,10 +3957,10 @@ dependencies = [
"http",
"hyper",
"hyper-util",
"rustls",
"rustls 0.23.23",
"rustls-pki-types",
"tokio",
"tokio-rustls",
"tokio-rustls 0.26.2",
"tower-service",
"webpki-roots",
]
@@ -3908,7 +4012,6 @@ dependencies = [
"itertools 0.14.0",
"jsonwebtoken",
"lazy_static",
"log",
"madmin",
"policy",
"rand 0.8.5",
@@ -4172,6 +4275,15 @@ version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itertools"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
dependencies = [
"either",
]
[[package]]
name = "itertools"
version = "0.13.0"
@@ -4331,6 +4443,12 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "lazycell"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "lexical-core"
version = "1.0.5"
@@ -5726,7 +5844,6 @@ dependencies = [
"itertools 0.14.0",
"jsonwebtoken",
"lazy_static",
"log",
"madmin",
"rand 0.8.5",
"regex",
@@ -6034,7 +6151,7 @@ dependencies = [
"quinn-proto",
"quinn-udp",
"rustc-hash 2.1.1",
"rustls",
"rustls 0.23.23",
"socket2",
"thiserror 2.0.11",
"tokio",
@@ -6052,7 +6169,7 @@ dependencies = [
"rand 0.8.5",
"ring",
"rustc-hash 2.1.1",
"rustls",
"rustls 0.23.23",
"rustls-pki-types",
"slab",
"thiserror 2.0.11",
@@ -6354,7 +6471,7 @@ dependencies = [
"percent-encoding",
"pin-project-lite",
"quinn",
"rustls",
"rustls 0.23.23",
"rustls-pemfile",
"rustls-pki-types",
"serde",
@@ -6363,7 +6480,7 @@ dependencies = [
"sync_wrapper",
"system-configuration",
"tokio",
"tokio-rustls",
"tokio-rustls 0.26.2",
"tokio-util",
"tower 0.5.2",
"tower-service",
@@ -6529,6 +6646,7 @@ dependencies = [
"async-trait",
"atoi",
"axum",
"axum-server",
"bytes",
"chrono",
"clap",
@@ -6551,7 +6669,6 @@ dependencies = [
"lazy_static",
"local-ip-address",
"lock",
"log",
"madmin",
"matchit 0.8.6",
"mime",
@@ -6567,6 +6684,9 @@ dependencies = [
"query",
"rmp-serde",
"rust-embed",
"rustls 0.23.23",
"rustls-pemfile",
"rustls-pki-types",
"s3s",
"serde",
"serde_json",
@@ -6574,6 +6694,7 @@ dependencies = [
"shadow-rs",
"time",
"tokio",
"tokio-rustls 0.26.2",
"tokio-stream",
"tokio-util",
"tonic",
@@ -6596,7 +6717,6 @@ dependencies = [
"chrono",
"dioxus",
"dirs 6.0.0",
"futures-util",
"hex",
"keyring",
"lazy_static",
@@ -6623,17 +6743,30 @@ dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "rustls"
version = "0.21.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e"
dependencies = [
"log",
"ring",
"rustls-webpki 0.101.7",
"sct",
]
[[package]]
name = "rustls"
version = "0.23.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395"
dependencies = [
"aws-lc-rs",
"log",
"once_cell",
"ring",
"rustls-pki-types",
"rustls-webpki",
"rustls-webpki 0.102.8",
"subtle",
"zeroize",
]
@@ -6656,12 +6789,23 @@ dependencies = [
"web-time",
]
[[package]]
name = "rustls-webpki"
version = "0.101.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "rustls-webpki"
version = "0.102.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
dependencies = [
"aws-lc-rs",
"ring",
"rustls-pki-types",
"untrusted",
@@ -6758,6 +6902,16 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "sct"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "security-framework"
version = "2.11.1"
@@ -7722,13 +7876,23 @@ dependencies = [
"syn 2.0.98",
]
[[package]]
name = "tokio-rustls"
version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
dependencies = [
"rustls 0.21.12",
"tokio",
]
[[package]]
name = "tokio-rustls"
version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b"
dependencies = [
"rustls",
"rustls 0.23.23",
"tokio",
]
@@ -7838,7 +8002,7 @@ dependencies = [
"rustls-pemfile",
"socket2",
"tokio",
"tokio-rustls",
"tokio-rustls 0.26.2",
"tokio-stream",
"tower 0.4.13",
"tower-layer",
@@ -8594,6 +8758,18 @@ dependencies = [
"windows-core 0.58.0",
]
[[package]]
name = "which"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
dependencies = [
"either",
"home",
"once_cell",
"rustix",
]
[[package]]
name = "winapi"
version = "0.3.9"
+9 -4
View File
@@ -47,9 +47,10 @@ flatbuffers = "24.12.23"
futures = "0.3.31"
futures-util = "0.3.31"
common = { path = "./common/common" }
policy = {path = "./policy"}
policy = { path = "./policy" }
hex = "0.4.3"
hyper = "1.6.0"
#hyper-rustls = { version = "0.27.5", features = ["http2"] }
hyper-util = { version = "0.1.10", features = [
"tokio",
"server-auto",
@@ -72,11 +73,14 @@ prost-types = "0.13.4"
protobuf = "3.7"
protos = { path = "./common/protos" }
rand = "0.8.5"
reqwest = { version = "0.12.12", default-features = false, features = ["rustls-tls", "charset", "http2", "macos-system-configuration", "stream","blocking"] }
reqwest = { version = "0.12.12", default-features = false, features = ["rustls-tls", "charset", "http2", "macos-system-configuration", "stream", "blocking"] }
rfd = { version = "0.15.2", default-features = false, features = ["xdg-portal", "tokio"] }
rmp = "0.8.14"
rmp-serde = "1.3.0"
rust-embed = "8.6.0"
rustls = { version = "0.23" }
rustls-pki-types = "1.11.0"
rustls-pemfile = "2.2.0"
s3s = { git = "https://github.com/Nugine/s3s.git", rev = "ab139f72fe768fb9d8cecfe36269451da1ca9779", default-features = true, features = [
"tower",
] }
@@ -98,9 +102,11 @@ tokio = { version = "1.43.0", features = ["fs", "rt-multi-thread"] }
tonic = { version = "0.12.3", features = ["gzip"] }
tonic-build = "0.12.3"
tonic-reflection = "0.12"
tokio-rustls = { version = "0.26", default-features = false }
tokio-stream = "0.1.17"
tokio-util = { version = "0.7.13", features = ["io", "compat"] }
tower = { version = "0.5.2", features = ["timeout"] }
tower-http = { version = "0.6.2", features = ["cors"] }
tracing = "0.1.41"
tracing-error = "0.2.1"
tracing-subscriber = { version = "0.3.19", features = ["env-filter", "time"] }
@@ -112,12 +118,11 @@ uuid = { version = "1.15.1", features = [
"fast-rng",
"macro-diagnostics",
] }
log = "0.4.25"
axum = "0.7.9"
axum-server = { version = "0.6", features = ["tls-rustls"] }
md-5 = "0.10.6"
workers = { path = "./common/workers" }
test-case = "3.3.1"
zip = "2.2.3"
snafu = "0.8.5"
-1
View File
@@ -10,7 +10,6 @@ version.workspace = true
chrono = { workspace = true }
dioxus = { workspace = true, features = ["router"] }
dirs = { workspace = true }
futures-util = { workspace = true }
hex = { workspace = true }
keyring = { workspace = true }
lazy_static = { workspace = true }
-1
View File
@@ -11,7 +11,6 @@ workspace = true
[dependencies]
tokio.workspace = true
log.workspace = true
time = { workspace = true, features = ["serde-human-readable"] }
serde = { workspace = true, features = ["derive", "rc"] }
ecstore = { path = "../ecstore" }
+6 -6
View File
@@ -6,12 +6,12 @@ use std::{
};
use arc_swap::{ArcSwap, AsRaw, Guard};
use log::warn;
use policy::{
auth::UserIdentity,
policy::{Args, PolicyDoc},
};
use time::OffsetDateTime;
use tracing::warn;
use crate::store::{GroupInfo, MappedPolicy};
@@ -63,7 +63,7 @@ impl Cache {
let mut new = CacheEntity::clone(&cur);
op(&mut new);
// 使用cas原子替换内容
// 使用 cas 原子替换内容
let prev = target.compare_and_swap(&*cur, Arc::new(new));
let swapped = Self::ptr_eq(&*cur, &*prev);
if swapped {
@@ -112,8 +112,8 @@ impl CacheInner {
// todo!()
// }
// /// 如果是临时用户,返回Ok(Some(partent_name)))
// /// 如果不是临时用户,返回Ok(None)
// /// 如果是临时用户,返回 Ok(Some(partent_name)))
// /// 如果不是临时用户,返回 Ok(None)
// fn is_temp_user(&self, user_name: &str) -> crate::Result<Option<&str>> {
// let user = self
// .get_user(user_name)
@@ -126,8 +126,8 @@ impl CacheInner {
// }
// }
// /// 如果是临时用户,返回Ok(Some(partent_name)))
// /// 如果不是临时用户,返回Ok(None)
// /// 如果是临时用户,返回 Ok(Some(partent_name)))
// /// 如果不是临时用户,返回 Ok(None)
// fn is_service_account(&self, user_name: &str) -> crate::Result<Option<&str>> {
// let user = self
// .get_user(user_name)
+1 -1
View File
@@ -1,12 +1,12 @@
use common::error::{Error, Result};
use ecstore::store::ECStore;
use error::Error as IamError;
use log::debug;
use manager::IamCache;
use policy::auth::Credentials;
use std::sync::{Arc, OnceLock};
use store::object::ObjectStore;
use sys::IamSys;
use tracing::debug;
pub mod cache;
pub mod error;
+1 -1
View File
@@ -11,7 +11,6 @@ use crate::{
use common::error::{Error, Result};
use ecstore::config::error::is_err_config_not_found;
use ecstore::utils::{crypto::base64_encode, path::path_join_buf};
use log::{debug, warn};
use madmin::{AccountStatus, AddOrUpdateUserReq, GroupDesc};
use policy::{
arn::ARN,
@@ -40,6 +39,7 @@ use tokio::{
},
};
use tracing::error;
use tracing::{debug, warn};
const IAM_FORMAT_FILE: &str = "format.json";
const IAM_FORMAT_VERSION_1: i32 = 1;
-1
View File
@@ -11,7 +11,6 @@ workspace = true
[dependencies]
tokio.workspace = true
log.workspace = true
time = { workspace = true, features = ["serde-human-readable"] }
serde = { workspace = true, features = ["derive", "rc"] }
serde_json.workspace = true
+8 -4
View File
@@ -16,7 +16,6 @@ workspace = true
[dependencies]
madmin.workspace = true
log.workspace = true
async-trait.workspace = true
bytes.workspace = true
clap.workspace = true
@@ -24,7 +23,7 @@ csv = "1.3.1"
datafusion = { workspace = true }
common.workspace = true
ecstore.workspace = true
policy.workspace =true
policy.workspace = true
flatbuffers.workspace = true
futures.workspace = true
futures-util.workspace = true
@@ -42,6 +41,9 @@ prost-types.workspace = true
protos.workspace = true
protobuf.workspace = true
rmp-serde.workspace = true
rustls.workspace = true
rustls-pemfile.workspace = true
rustls-pki-types.workspace = true
s3s.workspace = true
serde.workspace = true
serde_json.workspace = true
@@ -54,9 +56,10 @@ tokio = { workspace = true, features = [
"net",
"signal",
] }
tokio-rustls.workspace = true
lazy_static.workspace = true
tokio-stream.workspace = true
tonic = { version = "0.12.3", features = ["gzip"] }
tonic.workspace = true
tonic-reflection.workspace = true
tower.workspace = true
tracing-error.workspace = true
@@ -65,6 +68,7 @@ transform-stream.workspace = true
uuid = "1.15.1"
url.workspace = true
axum.workspace = true
axum-server = { workspace = true }
matchit = "0.8.6"
shadow-rs.workspace = true
const-str = { version = "0.6.1", features = ["std", "proc"] }
@@ -75,7 +79,7 @@ query = { path = "../s3select/query" }
api = { path = "../s3select/api" }
iam = { path = "../iam" }
jsonwebtoken = "9.3.0"
tower-http = { version = "0.6.2", features = ["cors"] }
tower-http.workspace = true
mime_guess = "2.0.5"
rust-embed = { workspace = true, features = ["interpolate-folder-path"] }
local-ip-address = { workspace = true }
+12
View File
@@ -7,6 +7,14 @@ shadow_rs::shadow!(build);
pub const DEFAULT_ACCESS_KEY: &str = "rustfsadmin";
pub const DEFAULT_SECRET_KEY: &str = "rustfsadmin";
/// Default TLS key for rustfs
/// This is the default key for TLS.
pub(crate) const RUSTFS_TLS_KEY: &str = "rustfs_tls_key.pem";
/// Default TLS cert for rustfs
/// This is the default cert for TLS.
pub(crate) const RUSTFS_TLS_CERT: &str = "rustfs_tls_cert.pem";
#[allow(clippy::const_is_empty)]
const SHORT_VERSION: &str = {
if !build::TAG.is_empty() {
@@ -62,4 +70,8 @@ pub struct Opt {
#[arg(long, default_value_t = format!("127.0.0.1:{}", 9002), env = "RUSTFS_CONSOLE_ADDRESS")]
pub console_address: String,
/// tls path for rustfs api and console.
#[arg(long, env = "RUSTFS_TLS_PATH")]
pub tls_path: Option<String>,
}
+100 -9
View File
@@ -6,19 +6,24 @@ use axum::{
routing::get,
Router,
};
use axum_server::tls_rustls::RustlsConfig;
use mime_guess::from_path;
use rust_embed::RustEmbed;
use serde::Serialize;
use shadow_rs::shadow;
use std::net::{Ipv4Addr, SocketAddr, ToSocketAddrs};
use std::sync::OnceLock;
use tracing::info;
use std::time::Duration;
use tokio::signal;
use tracing::{debug, error, info};
shadow!(build);
const RUSTFS_ADMIN_PREFIX: &str = "/rustfs/admin/v3";
const RUSTFS_CONSOLE_TLS_KEY: &str = "rustfs_console_tls_key.pem";
const RUSTFS_CONSOLE_TLS_CERT: &str = "rustfs_console_tls_cert.pem";
#[derive(RustEmbed)]
#[folder = "$CARGO_MANIFEST_DIR/static"]
struct StaticFiles;
@@ -189,18 +194,104 @@ async fn config_handler(Host(host): Host) -> impl IntoResponse {
.unwrap()
}
pub async fn start_static_file_server(addrs: &str, local_ip: Ipv4Addr, access_key: &str, secret_key: &str) {
// 创建路由
pub async fn start_static_file_server(
addrs: &str,
local_ip: Ipv4Addr,
access_key: &str,
secret_key: &str,
tls_path: Option<String>,
) {
// Create a route
let app = Router::new()
.route("/config.json", get(config_handler))
.nest_service("/", get(static_handler));
let listener = tokio::net::TcpListener::bind(addrs).await.unwrap();
let local_addr = listener.local_addr().unwrap();
let local_addr: SocketAddr = addrs.parse().expect("Failed to parse socket address");
info!("WebUI: http://{}:{} http://127.0.0.1:{}", local_ip, local_addr.port(), local_addr.port());
info!(" RootUser: {}", access_key);
info!(" RootPass: {}", secret_key);
axum::serve(listener, app).await.unwrap();
let tls_path = tls_path.unwrap_or_default();
let key_path = format!("{}/{}", tls_path, RUSTFS_CONSOLE_TLS_KEY);
let cert_path = format!("{}/{}", tls_path, RUSTFS_CONSOLE_TLS_CERT);
// Check and start the HTTPS/HTTP server
match start_server(addrs, local_addr, &key_path, &cert_path, app.clone()).await {
Ok(_) => info!("Server shutdown gracefully"),
Err(e) => error!("Server error: {}", e),
}
}
async fn start_server(addrs: &str, local_addr: SocketAddr, key_path: &str, cert_path: &str, app: Router) -> std::io::Result<()> {
let has_tls_certs = tokio::try_join!(tokio::fs::metadata(key_path), tokio::fs::metadata(cert_path)).is_ok();
if has_tls_certs {
debug!("Found TLS certificates, starting with HTTPS");
match tokio::try_join!(tokio::fs::read(key_path), tokio::fs::read(cert_path)) {
Ok((key_data, cert_data)) => {
match RustlsConfig::from_pem(cert_data, key_data).await {
Ok(config) => {
let handle = axum_server::Handle::new();
// create a signal off listening task
let handle_clone = handle.clone();
tokio::spawn(async move {
shutdown_signal().await;
handle_clone.graceful_shutdown(Some(Duration::from_secs(10)));
});
debug!("Starting HTTPS server...");
axum_server::bind_rustls(local_addr, config)
.handle(handle.clone())
.serve(app.into_make_service())
.await
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
Ok(())
}
Err(e) => {
error!("Failed to create TLS config: {}", e);
start_http_server(addrs, app).await
}
}
}
Err(e) => {
error!("Failed to read TLS certificates: {}", e);
start_http_server(addrs, app).await
}
}
} else {
debug!("TLS certificates not found at {} and {}", key_path, cert_path);
start_http_server(addrs, app).await
}
}
async fn start_http_server(addrs: &str, app: Router) -> std::io::Result<()> {
debug!("Starting HTTP server...");
let listener = tokio::net::TcpListener::bind(addrs).await.unwrap();
axum::serve(listener, app)
.with_graceful_shutdown(shutdown_signal())
.await
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))
}
async fn shutdown_signal() {
let ctrl_c = async {
signal::ctrl_c().await.expect("failed to install Ctrl+C handler");
};
#[cfg(unix)]
let terminate = async {
signal::unix::signal(signal::unix::SignalKind::terminate())
.expect("failed to install signal handler")
.recv()
.await;
};
#[cfg(not(unix))]
let terminate = std::future::pending::<()>();
tokio::select! {
_ = ctrl_c => {
info!("shutdown_signal ctrl_c")
},
_ = terminate => {
info!("shutdown_signal terminate")
},
}
}
+78 -21
View File
@@ -9,13 +9,14 @@ mod utils;
use crate::auth::IAMAuth;
use crate::console::{init_console_cfg, CONSOLE_CONFIG};
use crate::utils::error;
use chrono::Datelike;
use clap::Parser;
use common::{
error::{Error, Result},
globals::set_global_addr,
};
use config::{DEFAULT_ACCESS_KEY, DEFAULT_SECRET_KEY};
use config::{DEFAULT_ACCESS_KEY, DEFAULT_SECRET_KEY, RUSTFS_TLS_CERT, RUSTFS_TLS_KEY};
use ecstore::heal::background_heal_ops::init_auto_heal;
use ecstore::utils::net::{self, get_available_port};
use ecstore::{
@@ -34,10 +35,13 @@ use hyper_util::{
};
use iam::init_iam_sys;
use protos::proto_gen::node_service::node_service_server::NodeServiceServer;
use rustls::ServerConfig;
use s3s::{host::MultiDomain, service::S3ServiceBuilder};
use service::hybrid;
use std::sync::Arc;
use std::{io::IsTerminal, net::SocketAddr};
use tokio::net::TcpListener;
use tokio_rustls::TlsAcceptor;
use tonic::{metadata::MetadataValue, Request, Status};
use tower_http::cors::CorsLayer;
use tracing::{debug, error, info, warn};
@@ -87,7 +91,7 @@ fn main() -> Result<()> {
//解析获得到的参数
let opt = config::Opt::parse();
//设置trace
//设置 trace
setup_tracing();
//运行参数
@@ -110,18 +114,17 @@ async fn run(opt: config::Opt) -> Result<()> {
debug!("server_address {}", &server_address);
//设置AKSK
//设置 AKSK
iam::init_global_action_cred(Some(opt.access_key.clone()), Some(opt.secret_key.clone())).unwrap();
set_global_rustfs_port(server_port);
//监听地址,端口从参数中获取
//监听地址端口从参数中获取
let listener = TcpListener::bind(server_address.clone()).await?;
//获取监听地址
let local_addr: SocketAddr = listener.local_addr()?;
let local_ip = utils::get_local_ip().ok_or(local_addr.ip()).unwrap();
// 用于rpc
// 用于 rpc
let (endpoint_pools, setup_type) = EndpointServerPools::from_volumes(server_address.clone().as_str(), opt.volumes.clone())
.map_err(|err| Error::from_string(err.to_string()))?;
@@ -172,7 +175,7 @@ async fn run(opt: config::Opt) -> Result<()> {
.map_err(|err| Error::from_string(err.to_string()))?;
// Setup S3 service
// 本项目使用s3s库来实现s3服务
// 本项目使用 s3s 库来实现 s3 服务
let service = {
let store = storage::ecfs::FS::new();
// let mut b = S3ServiceBuilder::new(storage::ecfs::FS::new(server_address.clone(), endpoint_pools).await?);
@@ -180,7 +183,7 @@ async fn run(opt: config::Opt) -> Result<()> {
let access_key = opt.access_key.clone();
let secret_key = opt.secret_key.clone();
//显示info信息
//显示 info 信息
debug!("authentication is enabled {}, {}", &access_key, &secret_key);
b.set_auth(IAMAuth::new(access_key, secret_key));
@@ -213,9 +216,28 @@ async fn run(opt: config::Opt) -> Result<()> {
let rpc_service = NodeServiceServer::with_interceptor(make_server(), check_auth);
let tls_path = opt.tls_path.clone().unwrap_or_default();
let key_path = format!("{}/{}", tls_path, RUSTFS_TLS_KEY);
let cert_path = format!("{}/{}", tls_path, RUSTFS_TLS_CERT);
let has_tls_certs = tokio::try_join!(tokio::fs::metadata(key_path.clone()), tokio::fs::metadata(cert_path.clone())).is_ok();
let tls_acceptor = if has_tls_certs {
debug!("Found TLS certificates, starting with HTTPS");
let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();
let certs = utils::load_certs(cert_path.as_str()).map_err(|e| error(e.to_string()))?;
let key = utils::load_private_key(key_path.as_str()).map_err(|e| error(e.to_string()))?;
let mut server_config = ServerConfig::builder()
.with_no_client_auth()
.with_single_cert(certs, key)
.map_err(|e| error(e.to_string()))?;
server_config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec(), b"http/1.0".to_vec()];
Some(TlsAcceptor::from(Arc::new(server_config)))
} else {
debug!("TLS certificates not found, starting with HTTP");
None
};
tokio::spawn(async move {
let hyper_service = service.into_shared();
let hybrid_service = TowerToHyperService::new(
tower::ServiceBuilder::new()
.layer(CorsLayer::permissive())
@@ -225,8 +247,10 @@ async fn run(opt: config::Opt) -> Result<()> {
let http_server = ConnBuilder::new(TokioExecutor::new());
let mut ctrl_c = std::pin::pin!(tokio::signal::ctrl_c());
let graceful = hyper_util::server::graceful::GracefulShutdown::new();
debug!("graceful initiated");
loop {
debug!("waiting for SIGINT or SIGTERM has_tls_certs: {}", has_tls_certs);
// Wait for a connection
let (socket, _) = tokio::select! {
res = listener.accept() => {
match res {
@@ -241,20 +265,46 @@ async fn run(opt: config::Opt) -> Result<()> {
break;
}
};
let conn = http_server.serve_connection(TokioIo::new(socket), hybrid_service.clone());
let conn = graceful.watch(conn.into_owned());
tokio::spawn(async move {
let _ = conn.await;
});
if has_tls_certs {
debug!("TLS certificates found, starting with SIGINT");
let tls_socket = match tls_acceptor.as_ref().ok_or_else(|| error("TLS not configured".to_string())).unwrap().accept(socket).await {
Ok(tls_socket) => tls_socket,
Err(err) => {
error!("TLS handshake failed {}", err);
continue;
}
};
let conn = http_server.serve_connection(TokioIo::new(tls_socket), hybrid_service.clone());
let conn = graceful.watch(conn.into_owned());
tokio::task::spawn_blocking(move || {
tokio::runtime::Runtime::new()
.expect("Failed to create runtime")
.block_on(async move {
if let Err(err) = conn.await {
error!("Https Connection error: {}", err);
}
});
});
debug!("TLS handshake success");
} else {
debug!("Http handshake start");
let conn = http_server.serve_connection(TokioIo::new(socket), hybrid_service.clone());
let conn = graceful.watch(conn.into_owned());
tokio::spawn(async move {
if let Err(err) = conn.await {
error!("Http Connection error: {}", err);
}
});
debug!("Http handshake success");
}
}
tokio::select! {
() = graceful.shutdown() => {
tracing::debug!("Gracefully shutdown!");
debug!("Gracefully shutdown!");
},
() = tokio::time::sleep(std::time::Duration::from_secs(10)) => {
tracing::debug!("Waited 10 seconds for graceful shutdown, aborting...");
debug!("Waited 10 seconds for graceful shutdown, aborting...");
}
}
});
@@ -268,7 +318,7 @@ async fn run(opt: config::Opt) -> Result<()> {
})?;
ECStore::init(store.clone()).await.map_err(|err| {
error!("ECStore init faild {:?}", &err);
error!("ECStore init failed {:?}", &err);
Error::from_string(err.to_string())
})?;
debug!("init store success!");
@@ -276,7 +326,7 @@ async fn run(opt: config::Opt) -> Result<()> {
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!("new_global_notification_sys failed {:?}", &err);
Error::from_string(err.to_string())
})?;
@@ -294,8 +344,15 @@ async fn run(opt: config::Opt) -> Result<()> {
let access_key = opt.access_key.clone();
let secret_key = opt.secret_key.clone();
let console_address = opt.console_address.clone();
let tls_path = opt.tls_path.clone();
if console_address.is_empty() {
error!("console_address is empty");
return Err(Error::from_string("console_address is empty".to_string()));
}
tokio::spawn(async move {
console::start_static_file_server(&console_address, local_ip, &access_key, &secret_key).await;
console::start_static_file_server(&console_address, local_ip, &access_key, &secret_key, tls_path).await;
});
}
+21 -21
View File
@@ -46,7 +46,6 @@ use futures::pin_mut;
use futures::{Stream, StreamExt};
use http::HeaderMap;
use lazy_static::lazy_static;
use log::warn;
use policy::auth;
use policy::policy::action::Action;
use policy::policy::action::S3Action;
@@ -70,6 +69,7 @@ use tokio_util::io::StreamReader;
use tracing::debug;
use tracing::error;
use tracing::info;
use tracing::warn;
use transform_stream::AsyncTryStream;
use uuid::Uuid;
@@ -230,7 +230,7 @@ impl S3 for FS {
#[tracing::instrument(level = "debug", skip(self, req))]
async fn delete_bucket(&self, req: S3Request<DeleteBucketInput>) -> S3Result<S3Response<DeleteBucketOutput>> {
let input = req.input;
// TODO: DeleteBucketInput 没有force参数?
// TODO: DeleteBucketInput 没有 force 参数?
let Some(store) = new_object_layer_fn() else {
return Err(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string()));
};
@@ -586,8 +586,8 @@ impl S3 for FS {
.await
.is_ok()
|| authorize_request(&mut req, Action::S3Action(S3Action::GetBucketLocationAction))
.await
.is_ok()
.await
.is_ok()
})
});
}
@@ -1256,7 +1256,7 @@ impl S3 for FS {
conditions: &conditions,
object: "",
})
.await;
.await;
let write_olny = PolicySys::is_allowed(&BucketPolicyArgs {
bucket: &bucket,
@@ -1267,7 +1267,7 @@ impl S3 for FS {
conditions: &conditions,
object: "",
})
.await;
.await;
let is_public = read_olny && write_olny;
@@ -1680,11 +1680,11 @@ impl S3 for FS {
// TODO: valid target list
if let Some(NotificationConfiguration {
event_bridge_configuration,
lambda_function_configurations,
queue_configurations,
topic_configurations,
}) = has_notification_config
event_bridge_configuration,
lambda_function_configurations,
queue_configurations,
topic_configurations,
}) = has_notification_config
{
Ok(S3Response::new(GetBucketNotificationConfigurationOutput {
event_bridge_configuration,
@@ -1785,10 +1785,10 @@ impl S3 for FS {
//
!gs.is_empty()
&& gs.first().is_some_and(|g| {
g.to_owned()
.permission
.is_some_and(|p| p.as_str() == Permission::FULL_CONTROL)
})
g.to_owned()
.permission
.is_some_and(|p| p.as_str() == Permission::FULL_CONTROL)
})
})
});
@@ -1855,10 +1855,10 @@ impl S3 for FS {
//
!gs.is_empty()
&& gs.first().is_some_and(|g| {
g.to_owned()
.permission
.is_some_and(|p| p.as_str() == Permission::FULL_CONTROL)
})
g.to_owned()
.permission
.is_some_and(|p| p.as_str() == Permission::FULL_CONTROL)
})
})
});
@@ -1934,9 +1934,9 @@ impl S3 for FS {
}
#[allow(dead_code)]
pub fn bytes_stream<S, E>(stream: S, content_length: usize) -> impl Stream<Item = Result<Bytes, E>> + Send + 'static
pub fn bytes_stream<S, E>(stream: S, content_length: usize) -> impl Stream<Item=Result<Bytes, E>> + Send + 'static
where
S: Stream<Item = Result<Bytes, E>> + Send + 'static,
S: Stream<Item=Result<Bytes, E>> + Send + 'static,
E: Send + 'static,
{
AsyncTryStream::<Bytes, E, _>::new(|mut y| async move {
+28
View File
@@ -1,4 +1,7 @@
use rustls_pemfile::{certs, private_key};
use rustls_pki_types::{CertificateDer, PrivateKeyDer};
use std::net::IpAddr;
use std::{fs, io};
pub(crate) fn get_local_ip() -> Option<std::net::Ipv4Addr> {
match local_ip_address::local_ip() {
@@ -7,3 +10,28 @@ pub(crate) fn get_local_ip() -> Option<std::net::Ipv4Addr> {
Ok(IpAddr::V6(_)) => todo!(),
}
}
/// Load public certificate from file.
pub(crate) fn load_certs(filename: &str) -> io::Result<Vec<CertificateDer<'static>>> {
// Open certificate file.
let cert_file = fs::File::open(filename).map_err(|e| error(format!("failed to open {}: {}", filename, e)))?;
let mut reader = io::BufReader::new(cert_file);
// Load and return certificate.
let certs = certs(&mut reader).collect::<Result<Vec<_>, _>>()?;
Ok(certs)
}
/// Load private key from file.
pub(crate) fn load_private_key(filename: &str) -> io::Result<PrivateKeyDer<'static>> {
// Open keyfile.
let keyfile = fs::File::open(filename).map_err(|e| error(format!("failed to open {}: {}", filename, e)))?;
let mut reader = io::BufReader::new(keyfile);
// Load and return a single private key.
private_key(&mut reader)?.ok_or_else(|| error(format!("no private key found in {}", filename)))
}
pub(crate) fn error(err: String) -> io::Error {
io::Error::new(io::ErrorKind::Other, err)
}