chore: replace native-tls with pure rustls for FTPS/SFTP e2e tests (#1334)

Signed-off-by: yxrxy <1532529704@qq.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
yxrxy
2026-01-02 11:08:28 +08:00
committed by GitHub
parent 8d7cd4cb1b
commit cf53a9d84a
16 changed files with 299 additions and 444 deletions
+1 -2
View File
@@ -115,8 +115,7 @@ md5.workspace = true
mime_guess = { workspace = true }
moka = { workspace = true }
pin-project-lite.workspace = true
# rand = "0.8" is pinned due to dependency conflicts with workspace version
rand = "0.8"
rand = { workspace = true }
rust-embed = { workspace = true, features = ["interpolate-folder-path"] }
s3s.workspace = true
shadow-rs = { workspace = true, features = ["build", "metadata"] }
-41
View File
@@ -135,47 +135,6 @@ pub struct Opt {
/// Options: GeneralPurpose, AiTraining, DataAnalytics, WebWorkload, IndustrialIoT, SecureStorage
#[arg(long, default_value_t = String::from("GeneralPurpose"), env = "RUSTFS_BUFFER_PROFILE")]
pub buffer_profile: String,
/// Enable FTPS server
#[arg(long, default_value_t = false, env = "RUSTFS_FTPS_ENABLE")]
pub ftps_enable: bool,
/// FTPS server bind address
#[arg(long, default_value_t = String::from("0.0.0.0:21"), env = "RUSTFS_FTPS_ADDRESS")]
pub ftps_address: String,
/// FTPS server certificate file path
#[arg(long, env = "RUSTFS_FTPS_CERTS_FILE")]
pub ftps_certs_file: Option<String>,
/// FTPS server private key file path
#[arg(long, env = "RUSTFS_FTPS_KEY_FILE")]
pub ftps_key_file: Option<String>,
/// FTPS server passive ports range (e.g., "40000-50000")
#[arg(long, env = "RUSTFS_FTPS_PASSIVE_PORTS")]
pub ftps_passive_ports: Option<String>,
/// FTPS server external IP address for passive mode (auto-detected if not specified)
#[arg(long, env = "RUSTFS_FTPS_EXTERNAL_IP")]
pub ftps_external_ip: Option<String>,
/// Enable SFTP server
#[arg(long, default_value_t = false, env = "RUSTFS_SFTP_ENABLE")]
pub sftp_enable: bool,
/// SFTP server bind address
#[arg(long, default_value_t = String::from("0.0.0.0:22"), env = "RUSTFS_SFTP_ADDRESS")]
pub sftp_address: String,
/// SFTP server host key file path
#[arg(long, env = "RUSTFS_SFTP_HOST_KEY")]
pub sftp_host_key: Option<String>,
/// Path to authorized SSH public keys file for SFTP authentication
/// Each line should contain an OpenSSH public key: ssh-rsa AAAA... comment
#[arg(long, env = "RUSTFS_SFTP_AUTHORIZED_KEYS")]
pub sftp_authorized_keys: Option<String>,
}
// lazy_static::lazy_static! {
+28 -18
View File
@@ -320,32 +320,38 @@ pub(crate) fn init_buffer_profile_system(opt: &config::Opt) {
/// as other services and MUST integrate with the global shutdown system.
#[instrument(skip_all)]
pub async fn init_ftp_system(
opt: &crate::config::Opt,
shutdown_tx: tokio::sync::broadcast::Sender<()>,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
use crate::protocols::ftps::server::{FtpsConfig, FtpsServer};
use std::net::SocketAddr;
// Check if FTPS is enabled
if !opt.ftps_enable {
let ftps_enable = rustfs_utils::get_env_bool(rustfs_config::ENV_FTPS_ENABLE, false);
if !ftps_enable {
debug!("FTPS system is disabled");
return Ok(());
}
// Parse FTPS address
let addr: SocketAddr = opt
.ftps_address
let ftps_address_str = rustfs_utils::get_env_str(rustfs_config::ENV_FTPS_ADDRESS, rustfs_config::DEFAULT_FTPS_ADDRESS);
let addr: SocketAddr = ftps_address_str
.parse()
.map_err(|e| format!("Invalid FTPS address '{}': {}", opt.ftps_address, e))?;
.map_err(|e| format!("Invalid FTPS address '{}': {}", ftps_address_str, e))?;
// Get FTPS configuration from environment variables
let cert_file = rustfs_utils::get_env_opt_str(rustfs_config::ENV_FTPS_CERTS_FILE);
let key_file = rustfs_utils::get_env_opt_str(rustfs_config::ENV_FTPS_KEY_FILE);
let passive_ports = rustfs_utils::get_env_opt_str(rustfs_config::ENV_FTPS_PASSIVE_PORTS);
let external_ip = rustfs_utils::get_env_opt_str(rustfs_config::ENV_FTPS_EXTERNAL_IP);
// Create FTPS configuration
let config = FtpsConfig {
bind_addr: addr,
passive_ports: opt.ftps_passive_ports.clone(),
external_ip: opt.ftps_external_ip.clone(),
passive_ports,
external_ip,
ftps_required: true,
cert_file: opt.ftps_certs_file.clone(),
key_file: opt.ftps_key_file.clone(),
cert_file,
key_file,
};
// Create FTPS server
@@ -380,31 +386,35 @@ pub async fn init_ftp_system(
/// as other services and MUST integrate with the global shutdown system.
#[instrument(skip_all)]
pub async fn init_sftp_system(
opt: &config::Opt,
shutdown_tx: tokio::sync::broadcast::Sender<()>,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
use crate::protocols::sftp::server::{SftpConfig, SftpServer};
use std::net::SocketAddr;
// Check if SFTP is enabled
if !opt.sftp_enable {
let sftp_enable = rustfs_utils::get_env_bool(rustfs_config::ENV_SFTP_ENABLE, false);
if !sftp_enable {
debug!("SFTP system is disabled");
return Ok(());
}
// Parse SFTP address
let addr: SocketAddr = opt
.sftp_address
let sftp_address_str = rustfs_utils::get_env_str(rustfs_config::ENV_SFTP_ADDRESS, rustfs_config::DEFAULT_SFTP_ADDRESS);
let addr: SocketAddr = sftp_address_str
.parse()
.map_err(|e| format!("Invalid SFTP address '{}': {}", opt.sftp_address, e))?;
.map_err(|e| format!("Invalid SFTP address '{}': {}", sftp_address_str, e))?;
// Get SFTP configuration from environment variables
let host_key = rustfs_utils::get_env_opt_str(rustfs_config::ENV_SFTP_HOST_KEY);
let authorized_keys = rustfs_utils::get_env_opt_str(rustfs_config::ENV_SFTP_AUTHORIZED_KEYS);
// Create SFTP configuration
let config = SftpConfig {
bind_addr: addr,
require_key_auth: false, // TODO: Add key auth configuration
cert_file: None, // CA certificates for client certificate authentication
key_file: opt.sftp_host_key.clone(), // SFTP server host key
authorized_keys_file: opt.sftp_authorized_keys.clone(), // Pre-loaded authorized SSH public keys
require_key_auth: false, // TODO: Add key auth configuration
cert_file: None, // CA certificates for client certificate authentication
key_file: host_key, // SFTP server host key
authorized_keys_file: authorized_keys, // Pre-loaded authorized SSH public keys
};
// Create SFTP server
+2 -6
View File
@@ -272,14 +272,10 @@ async fn run(opt: config::Opt) -> Result<()> {
let (ftp_sftp_shutdown_tx, _) = tokio::sync::broadcast::channel(1);
// Initialize FTP system if enabled
init_ftp_system(&opt, ftp_sftp_shutdown_tx.clone())
.await
.map_err(Error::other)?;
init_ftp_system(ftp_sftp_shutdown_tx.clone()).await.map_err(Error::other)?;
// Initialize SFTP system if enabled
init_sftp_system(&opt, ftp_sftp_shutdown_tx.clone())
.await
.map_err(Error::other)?;
init_sftp_system(ftp_sftp_shutdown_tx.clone()).await.map_err(Error::other)?;
// Initialize buffer profiling system
init_buffer_profile_system(&opt);
+27 -31
View File
@@ -10,27 +10,23 @@ RustFS provides multiple protocol interfaces for accessing object storage, inclu
### Enable Protocols on Startup
```bash
# Start RustFS with all protocols enabled
rustfs \
--address 0.0.0.0:9000 \
--access-key rustfsadmin \
--secret-key rustfsadmin \
--ftps-enable \
--ftps-address 0.0.0.0:21 \
--ftps-certs-file /path/to/cert.pem \
--ftps-key-file /path/to/key.pem \
--ftps-passive-ports "40000-41000" \
--sftp-enable \
--sftp-address 0.0.0.0:22 \
--sftp-host-key /path/to/host_key \
--sftp-authorized-keys /path/to/authorized_keys \
/data
# Start RustFS with FTPS enabled
export RUSTFS_FTPS_ENABLE=true
export RUSTFS_FTPS_CERTS_FILE=/path/to/cert.pem
export RUSTFS_FTPS_KEY_FILE=/path/to/key.pem
rustfs --address 0.0.0.0:9000 --access-key rustfsadmin --secret-key rustfsadmin /data
# Start RustFS with SFTP enabled
export RUSTFS_SFTP_ENABLE=true
export RUSTFS_SFTP_HOST_KEY=/path/to/host_key
export RUSTFS_SFTP_AUTHORIZED_KEYS=/path/to/authorized_keys
rustfs --address 0.0.0.0:9000 --access-key rustfsadmin --secret-key rustfsadmin /data
```
## Protocol Details
### FTPS
- **Port**: 21
- **Port**: 8021 (default)
- **Protocol**: FTP over TLS (FTPS)
- **Authentication**: Access Key / Secret Key (same as S3)
- **Features**:
@@ -44,7 +40,7 @@ rustfs \
- No multipart upload
### SFTP
- **Port**: 22
- **Port**: 8022 (default)
- **Protocol**: SSH File Transfer Protocol
- **Authentication**:
- Password (Access Key / Secret Key)
@@ -133,23 +129,23 @@ ssh-keygen -l -f /path/to/host_key
### FTPS Configuration
| Option | Environment Variable | Description | Default |
|--------|---------------------|-------------|---------|
| `--ftps-enable` | `RUSTFS_FTPS_ENABLE` | Enable FTPS server | `false` |
| `--ftps-address` | `RUSTFS_FTPS_ADDRESS` | FTPS bind address | `0.0.0.0:21` |
| `--ftps-certs-file` | `RUSTFS_FTPS_CERTS_FILE` | TLS certificate file | - |
| `--ftps-key-file` | `RUSTFS_FTPS_KEY_FILE` | TLS private key file | - |
| `--ftps-passive-ports` | `RUSTFS_FTPS_PASSIVE_PORTS` | Passive port range | - |
| `--ftps-external-ip` | `RUSTFS_FTPS_EXTERNAL_IP` | External IP for NAT | - |
| Environment Variable | Description | Default |
|---------------------|-------------|---------|
| `RUSTFS_FTPS_ENABLE` | Enable FTPS server | `false` |
| `RUSTFS_FTPS_ADDRESS` | FTPS bind address | `0.0.0.0:8021` |
| `RUSTFS_FTPS_CERTS_FILE` | TLS certificate file | - |
| `RUSTFS_FTPS_KEY_FILE` | TLS private key file | - |
| `RUSTFS_FTPS_PASSIVE_PORTS` | Passive port range | - |
| `RUSTFS_FTPS_EXTERNAL_IP` | External IP for NAT | - |
### SFTP Configuration
| Option | Environment Variable | Description | Default |
|--------|---------------------|-------------|---------|
| `--sftp-enable` | `RUSTFS_SFTP_ENABLE` | Enable SFTP server | `false` |
| `--sftp-address` | `RUSTFS_SFTP_ADDRESS` | SFTP bind address | `0.0.0.0:22` |
| `--sftp-host-key` | `RUSTFS_SFTP_HOST_KEY` | SSH host key file | - |
| `--sftp-authorized-keys` | `RUSTFS_SFTP_AUTHORIZED_KEYS` | Authorized keys file | - |
| Environment Variable | Description | Default |
|---------------------|-------------|---------|
| `RUSTFS_SFTP_ENABLE` | Enable SFTP server | `false` |
| `RUSTFS_SFTP_ADDRESS` | SFTP bind address | `0.0.0.0:8022` |
| `RUSTFS_SFTP_HOST_KEY` | SSH host key file | - |
| `RUSTFS_SFTP_AUTHORIZED_KEYS` | Authorized keys file | - |
## See Also
+3 -3
View File
@@ -20,9 +20,9 @@ use crate::protocols::session::context::Protocol;
pub fn is_operation_supported(protocol: Protocol, action: &S3Action) -> bool {
match protocol {
Protocol::Ftps => match action {
// Bucket operations: FTPS cannot create buckets via protocol commands
S3Action::CreateBucket => false,
S3Action::DeleteBucket => false,
// Bucket operations: FTPS has no native bucket commands, but gateway allows create/delete
S3Action::CreateBucket => true,
S3Action::DeleteBucket => true,
// Object operations: All file operations supported
S3Action::GetObject => true, // RETR command
+2 -1
View File
@@ -69,7 +69,8 @@ impl SftpServer {
russh::keys::load_secret_key(path, None)?
} else {
warn!("No host key provided, generating random key (not recommended for production).");
let mut rng = rand::rngs::OsRng;
use russh::keys::signature::rand_core::OsRng;
let mut rng = OsRng;
PrivateKey::random(&mut rng, Algorithm::Ed25519)?
};