mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-08 22:33:22 +00:00
upgrade docker image version and fix docker comman
This commit is contained in:
@@ -33,7 +33,8 @@ const RUSTFS_ADMIN_PREFIX: &str = "/rustfs/admin/v3";
|
||||
#[folder = "$CARGO_MANIFEST_DIR/static"]
|
||||
struct StaticFiles;
|
||||
|
||||
async fn static_handler(uri: axum::http::Uri) -> impl IntoResponse {
|
||||
/// Static file handler
|
||||
async fn static_handler(uri: Uri) -> impl IntoResponse {
|
||||
let mut path = uri.path().trim_start_matches('/');
|
||||
if path.is_empty() {
|
||||
path = "index.html"
|
||||
@@ -193,7 +194,7 @@ fn _is_private_ip(ip: std::net::IpAddr) -> bool {
|
||||
async fn config_handler(uri: Uri, Host(host): Host) -> impl IntoResponse {
|
||||
let scheme = uri.scheme().map(|s| s.as_str()).unwrap_or("http");
|
||||
|
||||
// 从 uri 中获取 host,如果没有则使用 Host extractor 的值
|
||||
// Get the host from the uri and use the value of the host extractor if it doesn't have one
|
||||
let host = uri.host().unwrap_or(host.as_str());
|
||||
|
||||
let host = if host.contains(':') {
|
||||
@@ -203,7 +204,7 @@ async fn config_handler(uri: Uri, Host(host): Host) -> impl IntoResponse {
|
||||
host
|
||||
};
|
||||
|
||||
// 将当前配置复制一份
|
||||
// Make a copy of the current configuration
|
||||
let mut cfg = CONSOLE_CONFIG.get().unwrap().clone();
|
||||
|
||||
let url = format!("{}://{}:{}", scheme, host, cfg.port);
|
||||
@@ -224,9 +225,9 @@ pub async fn start_static_file_server(
|
||||
secret_key: &str,
|
||||
tls_path: Option<String>,
|
||||
) {
|
||||
// 配置 CORS
|
||||
// Configure CORS
|
||||
let cors = CorsLayer::new()
|
||||
.allow_origin(Any) // 生产环境建议指定具体域名
|
||||
.allow_origin(Any) // In the production environment, we recommend that you specify a specific domain name
|
||||
.allow_methods([http::Method::GET, http::Method::POST])
|
||||
.allow_headers([header::CONTENT_TYPE]);
|
||||
// Create a route
|
||||
@@ -298,7 +299,7 @@ async fn start_server(server_addr: SocketAddr, tls_path: Option<String>, app: Ro
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
/// HTTP 到 HTTPS 的 308 重定向
|
||||
/// 308 redirect for HTTP to HTTPS
|
||||
fn redirect_to_https(https_port: u16) -> Router {
|
||||
Router::new().route(
|
||||
"/*path",
|
||||
|
||||
@@ -10,6 +10,7 @@ lazy_static::lazy_static! {
|
||||
static ref LICENSE: OnceLock<Token> = OnceLock::new();
|
||||
}
|
||||
|
||||
/// Initialize the license
|
||||
pub fn init_license(license: Option<String>) {
|
||||
if license.is_none() {
|
||||
error!("License is None");
|
||||
@@ -23,10 +24,13 @@ pub fn init_license(license: Option<String>) {
|
||||
});
|
||||
}
|
||||
|
||||
/// Get the license
|
||||
pub fn get_license() -> Option<Token> {
|
||||
LICENSE.get().cloned()
|
||||
}
|
||||
|
||||
/// Check the license
|
||||
/// This function checks if the license is valid.
|
||||
#[allow(unreachable_code)]
|
||||
pub fn license_check() -> Result<()> {
|
||||
return Ok(());
|
||||
|
||||
@@ -129,7 +129,7 @@ impl Default for ServiceStateManager {
|
||||
}
|
||||
}
|
||||
|
||||
// 使用示例
|
||||
// Example of use
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -138,18 +138,18 @@ mod tests {
|
||||
fn test_service_state_manager() {
|
||||
let manager = ServiceStateManager::new();
|
||||
|
||||
// 初始状态应该是 Starting
|
||||
// The initial state should be Starting
|
||||
assert_eq!(manager.current_state(), ServiceState::Starting);
|
||||
|
||||
// 更新状态到 Ready
|
||||
// Update the status to Ready
|
||||
manager.update(ServiceState::Ready);
|
||||
assert_eq!(manager.current_state(), ServiceState::Ready);
|
||||
|
||||
// 更新状态到 Stopping
|
||||
// Update the status to Stopping
|
||||
manager.update(ServiceState::Stopping);
|
||||
assert_eq!(manager.current_state(), ServiceState::Stopping);
|
||||
|
||||
// 更新状态到 Stopped
|
||||
// Update the status to Stopped
|
||||
manager.update(ServiceState::Stopped);
|
||||
assert_eq!(manager.current_state(), ServiceState::Stopped);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
use crate::config::{RUSTFS_TLS_CERT, RUSTFS_TLS_KEY};
|
||||
use rustls::server::{ClientHello, ResolvesServerCert, ResolvesServerCertUsingSni};
|
||||
use rustls::sign::CertifiedKey;
|
||||
use rustls_pemfile::{certs, private_key};
|
||||
use rustls_pki_types::{CertificateDer, PrivateKeyDer};
|
||||
use std::collections::HashMap;
|
||||
use std::io::Error;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::{fs, io};
|
||||
use tracing::{debug, warn};
|
||||
|
||||
/// Load public certificate from file.
|
||||
/// This function loads a public certificate from the specified 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<_>, _>>()
|
||||
.map_err(|_| error(format!("certificate file {} format error", filename)))?;
|
||||
if certs.is_empty() {
|
||||
return Err(error(format!("No valid certificate was found in the certificate file {}", filename)));
|
||||
}
|
||||
Ok(certs)
|
||||
}
|
||||
|
||||
/// Load private key from file.
|
||||
/// This function loads a private key from the specified 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)))
|
||||
}
|
||||
|
||||
/// error function
|
||||
pub(crate) fn error(err: String) -> Error {
|
||||
Error::new(io::ErrorKind::Other, err)
|
||||
}
|
||||
|
||||
/// Load all certificates and private keys in the directory
|
||||
/// This function loads all certificate and private key pairs from the specified directory.
|
||||
/// It looks for files named `rustfs_cert.pem` and `rustfs_key.pem` in each subdirectory.
|
||||
/// The root directory can also contain a default certificate/private key pair.
|
||||
pub(crate) fn load_all_certs_from_directory(
|
||||
dir_path: &str,
|
||||
) -> io::Result<HashMap<String, (Vec<CertificateDer<'static>>, PrivateKeyDer<'static>)>> {
|
||||
let mut cert_key_pairs = HashMap::new();
|
||||
let dir = Path::new(dir_path);
|
||||
|
||||
if !dir.exists() || !dir.is_dir() {
|
||||
return Err(error(format!(
|
||||
"The certificate directory does not exist or is not a directory: {}",
|
||||
dir_path
|
||||
)));
|
||||
}
|
||||
|
||||
// 1. First check whether there is a certificate/private key pair in the root directory
|
||||
let root_cert_path = dir.join(RUSTFS_TLS_CERT);
|
||||
let root_key_path = dir.join(RUSTFS_TLS_KEY);
|
||||
|
||||
if root_cert_path.exists() && root_key_path.exists() {
|
||||
debug!("find the root directory certificate: {:?}", root_cert_path);
|
||||
let root_cert_str = root_cert_path
|
||||
.to_str()
|
||||
.ok_or_else(|| error(format!("Invalid UTF-8 in root certificate path: {:?}", root_cert_path)))?;
|
||||
let root_key_str = root_key_path
|
||||
.to_str()
|
||||
.ok_or_else(|| error(format!("Invalid UTF-8 in root key path: {:?}", root_key_path)))?;
|
||||
match load_cert_key_pair(root_cert_str, root_key_str) {
|
||||
Ok((certs, key)) => {
|
||||
// The root directory certificate is used as the default certificate and is stored using special keys.
|
||||
cert_key_pairs.insert("default".to_string(), (certs, key));
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("unable to load root directory certificate: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2.iterate through all folders in the directory
|
||||
for entry in fs::read_dir(dir)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
|
||||
if path.is_dir() {
|
||||
let domain_name = path
|
||||
.file_name()
|
||||
.and_then(|name| name.to_str())
|
||||
.ok_or_else(|| error(format!("invalid domain name directory:{:?}", path)))?;
|
||||
|
||||
// find certificate and private key files
|
||||
let cert_path = path.join(RUSTFS_TLS_CERT); // e.g., rustfs_cert.pem
|
||||
let key_path = path.join(RUSTFS_TLS_KEY); // e.g., rustfs_key.pem
|
||||
|
||||
if cert_path.exists() && key_path.exists() {
|
||||
debug!("find the domain name certificate: {} in {:?}", domain_name, cert_path);
|
||||
match load_cert_key_pair(cert_path.to_str().unwrap(), key_path.to_str().unwrap()) {
|
||||
Ok((certs, key)) => {
|
||||
cert_key_pairs.insert(domain_name.to_string(), (certs, key));
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("unable to load the certificate for {} domain name: {}", domain_name, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if cert_key_pairs.is_empty() {
|
||||
return Err(error(format!("No valid certificate/private key pair found in directory {}", dir_path)));
|
||||
}
|
||||
|
||||
Ok(cert_key_pairs)
|
||||
}
|
||||
|
||||
/// loading a single certificate private key pair
|
||||
/// This function loads a certificate and private key from the specified paths.
|
||||
/// It returns a tuple containing the certificate and private key.
|
||||
fn load_cert_key_pair(cert_path: &str, key_path: &str) -> io::Result<(Vec<CertificateDer<'static>>, PrivateKeyDer<'static>)> {
|
||||
let certs = load_certs(cert_path)?;
|
||||
let key = load_private_key(key_path)?;
|
||||
Ok((certs, key))
|
||||
}
|
||||
|
||||
/// Create a multi-cert resolver
|
||||
/// This function loads all certificates and private keys from the specified directory.
|
||||
/// It uses the first certificate/private key pair found in the root directory as the default certificate.
|
||||
/// The rest of the certificates/private keys are used for SNI resolution.
|
||||
///
|
||||
pub fn create_multi_cert_resolver(
|
||||
cert_key_pairs: HashMap<String, (Vec<CertificateDer<'static>>, PrivateKeyDer<'static>)>,
|
||||
) -> io::Result<impl ResolvesServerCert> {
|
||||
#[derive(Debug)]
|
||||
struct MultiCertResolver {
|
||||
cert_resolver: ResolvesServerCertUsingSni,
|
||||
default_cert: Option<Arc<CertifiedKey>>,
|
||||
}
|
||||
impl ResolvesServerCert for MultiCertResolver {
|
||||
fn resolve(&self, client_hello: ClientHello) -> Option<Arc<CertifiedKey>> {
|
||||
// try matching certificates with sni
|
||||
if let Some(cert) = self.cert_resolver.resolve(client_hello) {
|
||||
return Some(cert);
|
||||
}
|
||||
|
||||
// If there is no matching SNI certificate, use the default certificate
|
||||
self.default_cert.clone()
|
||||
}
|
||||
}
|
||||
|
||||
let mut resolver = ResolvesServerCertUsingSni::new();
|
||||
let mut default_cert = None;
|
||||
|
||||
for (domain, (certs, key)) in cert_key_pairs {
|
||||
// create a signature
|
||||
let signing_key = rustls::crypto::aws_lc_rs::sign::any_supported_type(&key)
|
||||
.map_err(|_| error(format!("unsupported private key types:{}", domain)))?;
|
||||
|
||||
// create a CertifiedKey
|
||||
let certified_key = CertifiedKey::new(certs, signing_key);
|
||||
if domain == "default" {
|
||||
default_cert = Some(Arc::new(certified_key.clone()));
|
||||
} else {
|
||||
// add certificate to resolver
|
||||
resolver
|
||||
.add(&domain, certified_key)
|
||||
.map_err(|e| error(format!("failed to add a domain name certificate:{},err: {:?}", domain, e)))?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(MultiCertResolver {
|
||||
cert_resolver: resolver,
|
||||
default_cert,
|
||||
})
|
||||
}
|
||||
+7
-181
@@ -1,16 +1,11 @@
|
||||
use crate::config::{RUSTFS_TLS_CERT, RUSTFS_TLS_KEY};
|
||||
use rustls::server::{ClientHello, ResolvesServerCert, ResolvesServerCertUsingSni};
|
||||
use rustls::sign::CertifiedKey;
|
||||
use rustls_pemfile::{certs, private_key};
|
||||
use rustls_pki_types::{CertificateDer, PrivateKeyDer};
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Debug;
|
||||
use std::io::Error;
|
||||
mod certs;
|
||||
use std::net::IpAddr;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::{fs, io};
|
||||
use tracing::{debug, warn};
|
||||
|
||||
pub(crate) use certs::create_multi_cert_resolver;
|
||||
pub(crate) use certs::error;
|
||||
pub(crate) use certs::load_all_certs_from_directory;
|
||||
pub(crate) use certs::load_certs;
|
||||
pub(crate) use certs::load_private_key;
|
||||
|
||||
/// Get the local IP address.
|
||||
/// This function retrieves the local IP address of the machine.
|
||||
@@ -21,172 +16,3 @@ pub(crate) fn get_local_ip() -> Option<std::net::Ipv4Addr> {
|
||||
Ok(IpAddr::V6(_)) => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Load public certificate from file.
|
||||
/// This function loads a public certificate from the specified 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<_>, _>>()
|
||||
.map_err(|_| error(format!("certificate file {} format error", filename)))?;
|
||||
if certs.is_empty() {
|
||||
return Err(error(format!("No valid certificate was found in the certificate file {}", filename)));
|
||||
}
|
||||
Ok(certs)
|
||||
}
|
||||
|
||||
/// Load private key from file.
|
||||
/// This function loads a private key from the specified 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)))
|
||||
}
|
||||
|
||||
/// error function
|
||||
pub(crate) fn error(err: String) -> Error {
|
||||
Error::new(io::ErrorKind::Other, err)
|
||||
}
|
||||
|
||||
/// Load all certificates and private keys in the directory
|
||||
/// This function loads all certificate and private key pairs from the specified directory.
|
||||
/// It looks for files named `rustfs_cert.pem` and `rustfs_key.pem` in each subdirectory.
|
||||
/// The root directory can also contain a default certificate/private key pair.
|
||||
pub(crate) fn load_all_certs_from_directory(
|
||||
dir_path: &str,
|
||||
) -> io::Result<HashMap<String, (Vec<CertificateDer<'static>>, PrivateKeyDer<'static>)>> {
|
||||
let mut cert_key_pairs = HashMap::new();
|
||||
let dir = Path::new(dir_path);
|
||||
|
||||
if !dir.exists() || !dir.is_dir() {
|
||||
return Err(error(format!(
|
||||
"The certificate directory does not exist or is not a directory: {}",
|
||||
dir_path
|
||||
)));
|
||||
}
|
||||
|
||||
// 1. First check whether there is a certificate/private key pair in the root directory
|
||||
let root_cert_path = dir.join(RUSTFS_TLS_CERT);
|
||||
let root_key_path = dir.join(RUSTFS_TLS_KEY);
|
||||
|
||||
if root_cert_path.exists() && root_key_path.exists() {
|
||||
debug!("find the root directory certificate: {:?}", root_cert_path);
|
||||
let root_cert_str = root_cert_path
|
||||
.to_str()
|
||||
.ok_or_else(|| error(format!("Invalid UTF-8 in root certificate path: {:?}", root_cert_path)))?;
|
||||
let root_key_str = root_key_path
|
||||
.to_str()
|
||||
.ok_or_else(|| error(format!("Invalid UTF-8 in root key path: {:?}", root_key_path)))?;
|
||||
match load_cert_key_pair(root_cert_str, root_key_str) {
|
||||
Ok((certs, key)) => {
|
||||
// The root directory certificate is used as the default certificate and is stored using special keys.
|
||||
cert_key_pairs.insert("default".to_string(), (certs, key));
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("unable to load root directory certificate: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2.iterate through all folders in the directory
|
||||
for entry in fs::read_dir(dir)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
|
||||
if path.is_dir() {
|
||||
let domain_name = path
|
||||
.file_name()
|
||||
.and_then(|name| name.to_str())
|
||||
.ok_or_else(|| error(format!("invalid domain name directory:{:?}", path)))?;
|
||||
|
||||
// find certificate and private key files
|
||||
let cert_path = path.join(RUSTFS_TLS_CERT); // e.g., rustfs_cert.pem
|
||||
let key_path = path.join(RUSTFS_TLS_KEY); // e.g., rustfs_key.pem
|
||||
|
||||
if cert_path.exists() && key_path.exists() {
|
||||
debug!("find the domain name certificate: {} in {:?}", domain_name, cert_path);
|
||||
match load_cert_key_pair(cert_path.to_str().unwrap(), key_path.to_str().unwrap()) {
|
||||
Ok((certs, key)) => {
|
||||
cert_key_pairs.insert(domain_name.to_string(), (certs, key));
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("unable to load the certificate for {} domain name: {}", domain_name, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if cert_key_pairs.is_empty() {
|
||||
return Err(error(format!("No valid certificate/private key pair found in directory {}", dir_path)));
|
||||
}
|
||||
|
||||
Ok(cert_key_pairs)
|
||||
}
|
||||
|
||||
/// loading a single certificate private key pair
|
||||
/// This function loads a certificate and private key from the specified paths.
|
||||
/// It returns a tuple containing the certificate and private key.
|
||||
fn load_cert_key_pair(cert_path: &str, key_path: &str) -> io::Result<(Vec<CertificateDer<'static>>, PrivateKeyDer<'static>)> {
|
||||
let certs = load_certs(cert_path)?;
|
||||
let key = load_private_key(key_path)?;
|
||||
Ok((certs, key))
|
||||
}
|
||||
|
||||
/// Create a multi-cert resolver
|
||||
/// This function loads all certificates and private keys from the specified directory.
|
||||
/// It uses the first certificate/private key pair found in the root directory as the default certificate.
|
||||
/// The rest of the certificates/private keys are used for SNI resolution.
|
||||
///
|
||||
pub fn create_multi_cert_resolver(
|
||||
cert_key_pairs: HashMap<String, (Vec<CertificateDer<'static>>, PrivateKeyDer<'static>)>,
|
||||
) -> io::Result<impl ResolvesServerCert> {
|
||||
#[derive(Debug)]
|
||||
struct MultiCertResolver {
|
||||
cert_resolver: ResolvesServerCertUsingSni,
|
||||
default_cert: Option<Arc<CertifiedKey>>,
|
||||
}
|
||||
impl ResolvesServerCert for MultiCertResolver {
|
||||
fn resolve(&self, client_hello: ClientHello) -> Option<Arc<CertifiedKey>> {
|
||||
// try matching certificates with sni
|
||||
if let Some(cert) = self.cert_resolver.resolve(client_hello) {
|
||||
return Some(cert);
|
||||
}
|
||||
|
||||
// If there is no matching SNI certificate, use the default certificate
|
||||
self.default_cert.clone()
|
||||
}
|
||||
}
|
||||
|
||||
let mut resolver = ResolvesServerCertUsingSni::new();
|
||||
let mut default_cert = None;
|
||||
|
||||
for (domain, (certs, key)) in cert_key_pairs {
|
||||
// create a signature
|
||||
let signing_key = rustls::crypto::aws_lc_rs::sign::any_supported_type(&key)
|
||||
.map_err(|_| error(format!("unsupported private key types:{}", domain)))?;
|
||||
|
||||
// create a CertifiedKey
|
||||
let certified_key = CertifiedKey::new(certs, signing_key);
|
||||
if domain == "default" {
|
||||
default_cert = Some(Arc::new(certified_key.clone()));
|
||||
} else {
|
||||
// add certificate to resolver
|
||||
resolver
|
||||
.add(&domain, certified_key)
|
||||
.map_err(|e| error(format!("failed to add a domain name certificate:{},err: {:?}", domain, e)))?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(MultiCertResolver {
|
||||
cert_resolver: resolver,
|
||||
default_cert,
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user