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

389
Cargo.lock generated
View File

@@ -563,17 +563,6 @@ dependencies = [
"xattr",
]
[[package]]
name = "async-channel"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35"
dependencies = [
"concurrent-queue",
"event-listener 2.5.3",
"futures-core",
]
[[package]]
name = "async-channel"
version = "2.5.0"
@@ -604,60 +593,13 @@ dependencies = [
"zstd-safe",
]
[[package]]
name = "async-executor"
version = "1.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8"
dependencies = [
"async-task",
"concurrent-queue",
"fastrand",
"futures-lite",
"pin-project-lite",
"slab",
]
[[package]]
name = "async-global-executor"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c"
dependencies = [
"async-channel 2.5.0",
"async-executor",
"async-io",
"async-lock",
"blocking",
"futures-lite",
"once_cell",
]
[[package]]
name = "async-io"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc"
dependencies = [
"autocfg",
"cfg-if",
"concurrent-queue",
"futures-io",
"futures-lite",
"parking",
"polling",
"rustix 1.1.3",
"slab",
"windows-sys 0.61.2",
]
[[package]]
name = "async-lock"
version = "3.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311"
dependencies = [
"event-listener 5.4.1",
"event-listener",
"event-listener-strategy",
"pin-project-lite",
]
@@ -673,32 +615,6 @@ dependencies = [
"syn 2.0.112",
]
[[package]]
name = "async-std"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c8e079a4ab67ae52b7403632e4618815d6db36d2a010cfe41b02c1b1578f93b"
dependencies = [
"async-channel 1.9.0",
"async-global-executor",
"async-io",
"async-lock",
"crossbeam-utils",
"futures-channel",
"futures-core",
"futures-io",
"futures-lite",
"gloo-timers",
"kv-log-macro",
"log",
"memchr",
"once_cell",
"pin-project-lite",
"pin-utils",
"slab",
"wasm-bindgen-futures",
]
[[package]]
name = "async-stream"
version = "0.3.6"
@@ -721,12 +637,6 @@ dependencies = [
"syn 2.0.112",
]
[[package]]
name = "async-task"
version = "4.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
[[package]]
name = "async-trait"
version = "0.1.89"
@@ -1433,19 +1343,6 @@ dependencies = [
"generic-array 0.14.7",
]
[[package]]
name = "blocking"
version = "1.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21"
dependencies = [
"async-channel 2.5.0",
"async-task",
"futures-io",
"futures-lite",
"piper",
]
[[package]]
name = "blowfish"
version = "0.9.1"
@@ -2248,12 +2145,27 @@ dependencies = [
"cpufeatures",
"curve25519-dalek-derive",
"digest 0.10.7",
"fiat-crypto",
"fiat-crypto 0.2.9",
"rustc_version",
"subtle",
"zeroize",
]
[[package]]
name = "curve25519-dalek"
version = "5.0.0-pre.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d8cfa313d59919eda35b420bd37db85bf58d6754d6f128b9949932b0c0fcce7"
dependencies = [
"cfg-if",
"cpufeatures",
"curve25519-dalek-derive",
"digest 0.11.0-rc.4",
"fiat-crypto 0.3.0",
"rustc_version",
"subtle",
]
[[package]]
name = "curve25519-dalek-derive"
version = "0.1.1"
@@ -3362,7 +3274,6 @@ dependencies = [
"flatbuffers",
"futures",
"md5 0.8.0",
"native-tls",
"rand 0.10.0-rc.5",
"rcgen",
"reqwest",
@@ -3379,7 +3290,6 @@ dependencies = [
"serde",
"serde_json",
"serial_test",
"ssh2",
"suppaftp",
"tokio",
"tonic",
@@ -3425,14 +3335,23 @@ dependencies = [
"signature 2.2.0",
]
[[package]]
name = "ed25519"
version = "3.0.0-rc.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "594435fe09e345ee388e4e8422072ff7dfeca8729389fbd997b3f5504c44cd47"
dependencies = [
"signature 3.0.0-rc.5",
]
[[package]]
name = "ed25519-dalek"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9"
dependencies = [
"curve25519-dalek",
"ed25519",
"curve25519-dalek 4.1.3",
"ed25519 2.2.3",
"rand_core 0.6.4",
"serde",
"sha2 0.10.9",
@@ -3440,6 +3359,18 @@ dependencies = [
"zeroize",
]
[[package]]
name = "ed25519-dalek"
version = "3.0.0-pre.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbef01b6e6a5f913ae480bb34ddd798ce6d358054bebf77177200ec84af61ad5"
dependencies = [
"curve25519-dalek 5.0.0-pre.2",
"ed25519 3.0.0-rc.2",
"sha2 0.11.0-rc.3",
"subtle",
]
[[package]]
name = "either"
version = "1.15.0"
@@ -3616,12 +3547,6 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "event-listener"
version = "2.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
[[package]]
name = "event-listener"
version = "5.4.1"
@@ -3639,7 +3564,7 @@ version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93"
dependencies = [
"event-listener 5.4.1",
"event-listener",
"pin-project-lite",
]
@@ -3685,6 +3610,12 @@ version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
[[package]]
name = "fiat-crypto"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24"
[[package]]
name = "filetime"
version = "0.2.26"
@@ -3806,21 +3737,6 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
"foreign-types-shared",
]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "form_urlencoded"
version = "1.2.2"
@@ -4067,18 +3983,6 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
[[package]]
name = "gloo-timers"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994"
dependencies = [
"futures-channel",
"futures-core",
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "google-cloud-auth"
version = "1.3.0"
@@ -4965,14 +4869,15 @@ checksum = "8bb03732005da905c88227371639bf1ad885cc712789c011c31c5fb3ab3ccf02"
[[package]]
name = "internal-russh-forked-ssh-key"
version = "0.6.11+upstream-0.6.7"
version = "0.6.16+upstream-0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a77eae781ed6a7709fb15b64862fcca13d886b07c7e2786f5ed34e5e2b9187"
checksum = "fe44f2bbd99fcb302e246e2d6bcf51aeda346d02a365f80296a07a8c711b6da6"
dependencies = [
"argon2 0.5.3",
"bcrypt-pbkdf",
"digest 0.11.0-rc.4",
"ecdsa 0.16.9",
"ed25519-dalek",
"ed25519-dalek 2.2.0",
"hex",
"hmac 0.12.1",
"num-bigint-dig",
@@ -4980,11 +4885,13 @@ dependencies = [
"p384",
"p521",
"rand_core 0.6.4",
"rsa 0.9.9",
"rsa 0.10.0-rc.10",
"sec1 0.7.3",
"sha1 0.10.6",
"sha1 0.11.0-rc.3",
"sha2 0.10.9",
"signature 2.2.0",
"signature 3.0.0-rc.5",
"ssh-cipher 0.2.0",
"ssh-encoding 0.2.0",
"subtle",
@@ -5107,7 +5014,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c76e1c7d7df3e34443b3621b459b066a7b79644f059fc8b2db7070c825fd417e"
dependencies = [
"base64",
"ed25519-dalek",
"ed25519-dalek 2.2.0",
"getrandom 0.2.16",
"hmac 0.12.1",
"js-sys",
@@ -5143,15 +5050,6 @@ dependencies = [
"libc",
]
[[package]]
name = "kv-log-macro"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f"
dependencies = [
"log",
]
[[package]]
name = "lazy-regex"
version = "3.4.2"
@@ -5356,20 +5254,6 @@ dependencies = [
"redox_syscall 0.7.0",
]
[[package]]
name = "libssh2-sys"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "220e4f05ad4a218192533b300327f5150e809b54c4ec83b5a1d91833601811b9"
dependencies = [
"cc",
"libc",
"libz-sys",
"openssl-sys",
"pkg-config",
"vcpkg",
]
[[package]]
name = "libsystemd"
version = "0.7.2"
@@ -5432,18 +5316,6 @@ dependencies = [
"zlib-rs",
]
[[package]]
name = "libz-sys"
version = "1.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15d118bbf3771060e7311cc7bb0545b01d08a8b4a7de949198dec1fa0ca1c0f7"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "linux-raw-sys"
version = "0.4.15"
@@ -5732,7 +5604,7 @@ dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
"equivalent",
"event-listener 5.4.1",
"event-listener",
"futures-util",
"parking_lot",
"portable-atomic",
@@ -5747,23 +5619,6 @@ version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084"
[[package]]
name = "native-tls"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e"
dependencies = [
"libc",
"log",
"openssl",
"openssl-probe 0.1.6",
"openssl-sys",
"schannel",
"security-framework 2.11.1",
"security-framework-sys",
"tempfile",
]
[[package]]
name = "neli"
version = "0.7.3"
@@ -5949,6 +5804,7 @@ dependencies = [
"num-iter",
"num-traits",
"rand 0.8.5",
"serde",
"smallvec",
"zeroize",
]
@@ -6161,56 +6017,12 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]]
name = "openssl"
version = "0.10.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328"
dependencies = [
"bitflags 2.10.0",
"cfg-if",
"foreign-types",
"libc",
"once_cell",
"openssl-macros",
"openssl-sys",
]
[[package]]
name = "openssl-macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.112",
]
[[package]]
name = "openssl-probe"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
[[package]]
name = "openssl-probe"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391"
[[package]]
name = "openssl-sys"
version = "0.9.111"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "opentelemetry"
version = "0.31.0"
@@ -6724,17 +6536,6 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "piper"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066"
dependencies = [
"atomic-waker",
"fastrand",
"futures-io",
]
[[package]]
name = "pkcs1"
version = "0.7.5"
@@ -6837,20 +6638,6 @@ dependencies = [
"plotters-backend",
]
[[package]]
name = "polling"
version = "3.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218"
dependencies = [
"cfg-if",
"concurrent-queue",
"hermit-abi",
"pin-project-lite",
"rustix 1.1.3",
"windows-sys 0.61.2",
]
[[package]]
name = "pollster"
version = "0.4.0"
@@ -7729,7 +7516,6 @@ dependencies = [
"pkcs1 0.7.5",
"pkcs8 0.10.2",
"rand_core 0.6.4",
"sha2 0.10.9",
"signature 2.2.0",
"spki 0.7.3",
"subtle",
@@ -7749,6 +7535,7 @@ dependencies = [
"pkcs1 0.8.0-rc.4",
"pkcs8 0.11.0-rc.8",
"rand_core 0.10.0-rc-2",
"sha2 0.11.0-rc.3",
"signature 3.0.0-rc.5",
"spki 0.8.0-rc.4",
"subtle",
@@ -7807,9 +7594,9 @@ dependencies = [
[[package]]
name = "russh"
version = "0.55.0"
version = "0.56.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82b4d036bb45d7bbe99dbfef4ec60eaeb614708d22ff107124272f8ef6b54548"
checksum = "bdbb7dcdd62c17ac911307ff693f55b3ec6712004d2d66ffdb8c0fa00269fd66"
dependencies = [
"aes 0.8.4",
"aws-lc-rs",
@@ -7819,16 +7606,15 @@ dependencies = [
"bytes",
"cbc",
"ctr 0.9.2",
"curve25519-dalek",
"curve25519-dalek 4.1.3",
"data-encoding",
"delegate",
"der 0.7.10",
"digest 0.10.7",
"ecdsa 0.16.9",
"ed25519-dalek",
"ed25519-dalek 2.2.0",
"elliptic-curve 0.13.8",
"enum_dispatch",
"flate2",
"futures",
"generic-array 1.3.5",
"getrandom 0.2.16",
@@ -7846,12 +7632,12 @@ dependencies = [
"p521",
"pageant",
"pbkdf2 0.12.2",
"pkcs1 0.7.5",
"pkcs1 0.8.0-rc.4",
"pkcs5",
"pkcs8 0.10.2",
"rand 0.8.5",
"rand_core 0.6.4",
"rsa 0.9.9",
"rsa 0.10.0-rc.10",
"russh-cryptovec",
"russh-util",
"sec1 0.7.3",
@@ -8002,7 +7788,7 @@ dependencies = [
"moka",
"pin-project-lite",
"pprof",
"rand 0.8.5",
"rand 0.10.0-rc.5",
"reqwest",
"rmp-serde",
"russh",
@@ -8198,7 +7984,7 @@ dependencies = [
name = "rustfs-ecstore"
version = "0.0.5"
dependencies = [
"async-channel 2.5.0",
"async-channel",
"async-recursion",
"async-trait",
"aws-config",
@@ -8765,10 +8551,10 @@ version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63"
dependencies = [
"openssl-probe 0.2.0",
"openssl-probe",
"rustls-pki-types",
"schannel",
"security-framework 3.5.1",
"security-framework",
]
[[package]]
@@ -9009,19 +8795,6 @@ dependencies = [
"hybrid-array",
]
[[package]]
name = "security-framework"
version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
dependencies = [
"bitflags 2.10.0",
"core-foundation 0.9.4",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework"
version = "3.5.1"
@@ -9621,6 +9394,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ad6a09263583e83e934fcd436b7e3bb9d69602e2feef3787adb615c1fe3a343"
dependencies = [
"base64ct",
"crypto-bigint 0.7.0-rc.10",
"digest 0.11.0-rc.4",
"pem-rfc7468 1.0.0",
"subtle",
@@ -9633,7 +9407,9 @@ version = "0.7.0-rc.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7faefb89d4a5304e31238913d1f7f164e22494276ed58cd84d5058ba7b04911f"
dependencies = [
"ed25519-dalek 3.0.0-pre.2",
"rand_core 0.10.0-rc-2",
"rsa 0.10.0-rc.10",
"sec1 0.8.0-rc.10",
"sha2 0.11.0-rc.3",
"signature 3.0.0-rc.5",
@@ -9643,18 +9419,6 @@ dependencies = [
"zeroize",
]
[[package]]
name = "ssh2"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f84d13b3b8a0d4e91a2629911e951db1bb8671512f5c09d7d4ba34500ba68c8"
dependencies = [
"bitflags 2.10.0",
"libc",
"libssh2-sys",
"parking_lot",
]
[[package]]
name = "stable_deref_trait"
version = "1.2.1"
@@ -9754,16 +9518,17 @@ version = "7.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba8928c89e226be233f0eb1594e9bd023f72a948dc06581c0d908387f57de1de"
dependencies = [
"async-std",
"async-trait",
"chrono",
"futures-lite",
"lazy-regex",
"log",
"native-tls",
"pin-project",
"rustls",
"rustls-pki-types",
"thiserror 2.0.17",
"tokio",
"tokio-rustls",
]
[[package]]
@@ -10859,12 +10624,6 @@ dependencies = [
"url",
]
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version_check"
version = "0.9.5"

View File

@@ -268,14 +268,11 @@ opentelemetry-stdout = { version = "0.31.0" }
# FTP and SFTP
libunftp = "0.21.0"
russh = "0.55.0"
russh = { version = "0.56.0", features = ["aws-lc-rs", "rsa"], default-features = false }
russh-sftp = "2.1.1"
russh-keys = "0.49.2"
ssh-key = "0.7.0-rc.4"
ssh2 = "0.9"
suppaftp = { version = "7.0.7", features = ["async-std", "rustls", "native-tls"] }
ssh-key = { version = "0.7.0-rc.4", features = ["std", "rsa", "ed25519"] }
suppaftp = { version = "7.0.7", features = ["tokio", "tokio-rustls", "rustls"] }
rcgen = "0.14.6"
native-tls = "0.2.14"
# Performance Analysis and Memory Profiling
mimalloc = "0.1"

View File

@@ -20,6 +20,7 @@ pub(crate) mod env;
pub(crate) mod heal;
pub(crate) mod object;
pub(crate) mod profiler;
pub(crate) mod protocols;
pub(crate) mod runtime;
pub(crate) mod targets;
pub(crate) mod tls;

View File

@@ -0,0 +1,40 @@
// Copyright 2024 RustFS Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Protocol server configuration constants
/// Default FTPS server bind address
pub const DEFAULT_FTPS_ADDRESS: &str = "0.0.0.0:8021";
/// Default SFTP server bind address
pub const DEFAULT_SFTP_ADDRESS: &str = "0.0.0.0:8022";
/// Default FTPS passive ports range (optional)
pub const DEFAULT_FTPS_PASSIVE_PORTS: Option<&str> = None;
/// Default FTPS external IP (auto-detected)
pub const DEFAULT_FTPS_EXTERNAL_IP: Option<&str> = None;
/// Environment variable names
pub const ENV_FTPS_ENABLE: &str = "RUSTFS_FTPS_ENABLE";
pub const ENV_FTPS_ADDRESS: &str = "RUSTFS_FTPS_ADDRESS";
pub const ENV_FTPS_CERTS_FILE: &str = "RUSTFS_FTPS_CERTS_FILE";
pub const ENV_FTPS_KEY_FILE: &str = "RUSTFS_FTPS_KEY_FILE";
pub const ENV_FTPS_PASSIVE_PORTS: &str = "RUSTFS_FTPS_PASSIVE_PORTS";
pub const ENV_FTPS_EXTERNAL_IP: &str = "RUSTFS_FTPS_EXTERNAL_IP";
pub const ENV_SFTP_ENABLE: &str = "RUSTFS_SFTP_ENABLE";
pub const ENV_SFTP_ADDRESS: &str = "RUSTFS_SFTP_ADDRESS";
pub const ENV_SFTP_HOST_KEY: &str = "RUSTFS_SFTP_HOST_KEY";
pub const ENV_SFTP_AUTHORIZED_KEYS: &str = "RUSTFS_SFTP_AUTHORIZED_KEYS";

View File

@@ -31,6 +31,8 @@ pub use constants::object::*;
#[cfg(feature = "constants")]
pub use constants::profiler::*;
#[cfg(feature = "constants")]
pub use constants::protocols::*;
#[cfg(feature = "constants")]
pub use constants::runtime::*;
#[cfg(feature = "constants")]
pub use constants::targets::*;

View File

@@ -52,10 +52,8 @@ base64 = { workspace = true }
rand = { workspace = true }
chrono = { workspace = true }
md5 = { workspace = true }
ssh2.workspace = true
suppaftp.workspace = true
rcgen.workspace = true
anyhow.workspace = true
native-tls.workspace = true
rustls.workspace = true
rustls-pemfile.workspace = true

View File

@@ -17,12 +17,14 @@
use crate::common::rustfs_binary_path;
use crate::protocols::test_env::{DEFAULT_ACCESS_KEY, DEFAULT_SECRET_KEY, ProtocolTestEnvironment};
use anyhow::Result;
use native_tls::TlsConnector;
use rcgen::generate_simple_self_signed;
use rustls::crypto::aws_lc_rs::default_provider;
use rustls::{ClientConfig, RootCertStore};
use std::io::Cursor;
use std::path::PathBuf;
use suppaftp::NativeTlsConnector;
use suppaftp::NativeTlsFtpStream;
use std::sync::Arc;
use suppaftp::RustlsConnector;
use suppaftp::RustlsFtpStream;
use tokio::process::Command;
use tracing::info;
@@ -48,16 +50,11 @@ pub async fn test_ftps_core_operations() -> Result<()> {
info!("Starting FTPS server on {}", FTPS_ADDRESS);
let binary_path = rustfs_binary_path();
let mut server_process = Command::new(&binary_path)
.args([
"--ftps-enable",
"--ftps-address",
FTPS_ADDRESS,
"--ftps-certs-file",
cert_path.to_str().unwrap(),
"--ftps-key-file",
key_path.to_str().unwrap(),
&env.temp_dir,
])
.env("RUSTFS_FTPS_ENABLE", "true")
.env("RUSTFS_FTPS_ADDRESS", FTPS_ADDRESS)
.env("RUSTFS_FTPS_CERTS_FILE", cert_path.to_str().unwrap())
.env("RUSTFS_FTPS_KEY_FILE", key_path.to_str().unwrap())
.arg(&env.temp_dir)
.spawn()?;
// Ensure server is cleaned up even on failure
@@ -67,14 +64,31 @@ pub async fn test_ftps_core_operations() -> Result<()> {
.await
.map_err(|e| anyhow::anyhow!("{}", e))?;
// Create native TLS connector that accepts the certificate
let tls_connector = TlsConnector::builder().danger_accept_invalid_certs(true).build()?;
// Install the aws-lc-rs crypto provider
default_provider()
.install_default()
.map_err(|e| anyhow::anyhow!("Failed to install crypto provider: {:?}", e))?;
// Wrap in suppaftp's NativeTlsConnector
let tls_connector = NativeTlsConnector::from(tls_connector);
// Create a simple rustls config that accepts any certificate for testing
let mut root_store = RootCertStore::empty();
// Add the self-signed certificate to the trust store for e2e
// Note: In a real environment, you'd use proper root certificates
let cert_pem = cert.cert.pem();
let cert_der = rustls_pemfile::certs(&mut Cursor::new(cert_pem))
.collect::<Result<Vec<_>, _>>()
.map_err(|e| anyhow::anyhow!("Failed to parse cert: {}", e))?;
root_store.add_parsable_certificates(cert_der);
let config = ClientConfig::builder()
.with_root_certificates(root_store)
.with_no_client_auth();
// Wrap in suppaftp's RustlsConnector
let tls_connector = RustlsConnector::from(Arc::new(config));
// Connect to FTPS server
let ftp_stream = NativeTlsFtpStream::connect(FTPS_ADDRESS).map_err(|e| anyhow::anyhow!("Failed to connect: {}", e))?;
let ftp_stream = RustlsFtpStream::connect(FTPS_ADDRESS).map_err(|e| anyhow::anyhow!("Failed to connect: {}", e))?;
// Upgrade to secure connection
let mut ftp_stream = ftp_stream

View File

@@ -310,7 +310,6 @@ pub async fn list_path_raw(rx: CancellationToken, opts: ListPathRawOptions) -> d
if at_eof + has_err == readers.len() {
if has_err > 0
&& let Some(finished_fn) = opts.finished.as_ref()
&& has_err > 0
{
finished_fn(&errs).await;
}

View File

@@ -108,11 +108,95 @@ export RUSTFS_ENABLE_LOCKS=false
./rustfs --address 127.0.0.1:9000 ...
```
## Protocol Servers
### RUSTFS_FTPS_ENABLE
Controls whether the FTPS (FTP over TLS) server should be started.
- **Default**: `false`
- **Valid values**: `true`, `false`
- **Description**: When enabled, starts an FTPS server for secure file transfers over TLS.
### RUSTFS_FTPS_ADDRESS
FTPS server bind address.
- **Default**: `0.0.0.0:8021`
- **Valid values**: Valid IP:PORT combination
- **Description**: The address and port where the FTPS server will listen for connections.
### RUSTFS_FTPS_CERTS_FILE
Path to FTPS server TLS certificate file.
- **Default**: None (required when FTPS is enabled)
- **Valid values**: Path to a PEM-encoded certificate file
- **Description**: TLS certificate used for securing FTPS connections.
### RUSTFS_FTPS_KEY_FILE
Path to FTPS server TLS private key file.
- **Default**: None (required when FTPS is enabled)
- **Valid values**: Path to a PEM-encoded private key file
- **Description**: TLS private key corresponding to the certificate.
### RUSTFS_FTPS_PASSIVE_PORTS
Passive port range for FTPS data connections.
- **Default**: None (system-assigned ports)
- **Valid values**: Port range in format "START-END" (e.g., "40000-50000")
- **Description**: Range of ports for FTPS passive mode data connections.
### RUSTFS_FTPS_EXTERNAL_IP
External IP address for FTPS passive mode.
- **Default**: None (auto-detected)
- **Valid values**: Valid IP address
- **Description**: External IP address advertised to FTPS clients for passive mode, useful for NAT setups.
### RUSTFS_SFTP_ENABLE
Controls whether the SFTP (SSH File Transfer Protocol) server should be started.
- **Default**: `false`
- **Valid values**: `true`, `false`
- **Description**: When enabled, starts an SFTP server for secure file transfers over SSH.
### RUSTFS_SFTP_ADDRESS
SFTP server bind address.
- **Default**: `0.0.0.0:8022`
- **Valid values**: Valid IP:PORT combination
- **Description**: The address and port where the SFTP server will listen for connections.
### RUSTFS_SFTP_HOST_KEY
Path to SFTP server SSH host key file.
- **Default**: None (required when SFTP is enabled)
- **Valid values**: Path to an SSH host key file
- **Description**: SSH host key used for server identification.
### RUSTFS_SFTP_AUTHORIZED_KEYS
Path to SFTP authorized keys file.
- **Default**: None (required when SFTP is enabled)
- **Valid values**: Path to a file containing OpenSSH public keys
- **Description**: File containing authorized SSH public keys for client authentication.
## Performance Impact
- **Scanner**: Light to moderate CPU/IO impact during scans
- **Heal**: Moderate to high CPU/IO impact during healing operations
- **Locks**: Minimal CPU/memory overhead for coordination; disabling can improve throughput in single-client scenarios
- **Memory**: Each service uses additional memory for processing queues and metadata
- **FTPS**: Moderate CPU/memory overhead for TLS operations and connection management
- **SFTP**: Moderate CPU/memory overhead for SSH operations and key management
Disabling these services in resource-constrained environments can improve performance for primary storage operations.

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"] }

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! {

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

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);

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

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

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)?
};