mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-11-04 11:07:35 +01:00
weed-vector: check master certificates against the server allowlists, read -config_dir (#12374)
* weed-vector: look for security.toml in -config_dir first weed processes search the directory -config_dir names before ., so a cluster keeping security.toml there left the engine in plaintext. --config-dir (also -config_dir, WEED_VECTOR_CONFIG_DIR) does the same. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011UpvafvK8JpagF94MHWqwK * weed-vector: dial the masters the way weed clients do The master's certificate must chain to grpc.ca and is not checked against the host dialed, as weed clients verify (advancedtls.CertVerification), so masters sharing one workload certificate, or dialed by IP, register as they do from weed. Instead, grpc.client.master_allowed_server_commonNames, grpc.client.allowed_server_commonNames or grpc.allowed_server_commonNames (and the wildcard domain likewise) restrict which server identities are accepted: the common name or a DNS SAN, or an exact URI SAN, as security.Authenticator.AuthenticateServer does. These used to be refused at startup; --tls-server-name is gone with the host check. The TLS runs in a connector that reads the credentials asynchronously at every dial, so the connect timeout still covers the reads, the TCP connect and the handshake together. An IPv6 master's brackets are stripped before the dial. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test/s3vectors: the hardened leg allowlists server identities for grpc.client The gateway and the engine then accept only servers named localhost, which exercises the engine's allowed_server_commonNames check on the master dial. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011UpvafvK8JpagF94MHWqwK * weed-vector: parse the refresh interval with time.ParseDuration's arithmetic The interval was summed in floating-point seconds, so 0.9ns rounded up to 1ns where Go truncates it to 0 and falls back to the 5h default, 0.3s was off by a nanosecond, and 3000000h was accepted where Go rejects anything past the longest time.Duration. Each part is now an integer count of nanoseconds plus the fraction Go adds, with Go's overflow bounds, and the value is no longer trimmed, as Go does not trim it either. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * weed-vector: test a master dial whose credential read stalls The bounded-dial tests passed no credentials or a prebuilt endpoint, so moving the credential read out of the connect timeout would have failed none of them. The new test points grpc.ca at a FIFO nobody writes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * weed-vector: dial a closed port in the stalled credential read test Against a silent listener, a dial that never read the credentials timed out with the same message, so the test passed without the read. Nothing listens on the port now, so only the stalled read can time out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * weed-vector: test that Security::load searches the config dir Only candidates() was tested, so load dropping config_dir on the way would have passed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * weed-vector: expand a leading ~ in -config_dir like weed's ResolvePath Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * weed-vector: hold the port in the stalled credential read test A released port can be taken before the dial, and a dial that skipped the read would then time out and pass. A listener that drops every connection keeps the port and still fails such a dial at once. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
30f0364256
commit
5063aa9be2
7 files changed
+683
-180
No files matched your search
@@ -109,7 +109,10 @@ def write_tls(directory):
|
||||
"-out", "outsider.pem", "-days", "2", "-extfile", "ext.cnf")
|
||||
cert, key, ca = (f'{key} = {json.dumps(str(directory / name), ensure_ascii=False)}\n' for key, name in (("cert", "cert.pem"), ("key", "key.pem"), ("ca", "ca.pem")))
|
||||
pem = cert + key + ca
|
||||
grpc = "".join(f"[grpc.{component}]\n{cert}{key}\n" for component in ("master", "volume", "filer", "s3", "client"))
|
||||
grpc = "".join(f"[grpc.{component}]\n{cert}{key}\n" for component in ("master", "volume", "filer", "s3"))
|
||||
# Clients (the gateway, the engine) accept only servers named localhost;
|
||||
# the engine serves only clients named localhost.
|
||||
grpc += f"[grpc.client]\n{cert}{key}allowed_server_commonNames = \"localhost\"\n"
|
||||
grpc += f"[grpc.vector]\n{cert}{key}allowed_commonNames = \"localhost\"\n"
|
||||
(directory / "security.toml").write_text(f"[https.volume]\n{pem}\n[https.client]\nenabled = true\n{pem}\n[grpc]\n{ca}\n{grpc}")
|
||||
|
||||
|
||||
Reference in new issue
Block a user