maintenance: extend SFTP connection options - #4293
Conversation
f5318a0 to
6a36885
Compare
|
Author remediation update: The rollout path now preserves existing SFTP monitors through an explicit one-time compatibility migration instead of making them fail immediately. New configurations still fail closed unless they provide a trusted fingerprint or explicitly select the dangerous compatibility option. Multiple fingerprints are accepted for current and next key rotation, unsafe connections emit controlled warnings, and the UI plus English and Chinese docs explain trusted acquisition, upgrade, rotation, and exit steps. Protocol, verifier, and migration tests passed (15), monitor YAML parsing passed, and the 24-module startup source package passed. GitHub checks are currently queued. Maintainer review remains required. |
|
CI follow-up: the only failing check after the remediation is DOC CI Dead Link Check. It was rerun once and failed again on the same unchanged historical URL, https://gitee.com/hertzbeat/hertzbeat, returning HTTP 405. The changed SFTP documentation passed Markdown and filename checks and adds no failing external link. Backend build, Maven E2E, image E2E, license, and label checks all passed. I am leaving the unrelated global link configuration and historical pages out of this single-purpose PR; the DOC CI result should be retried after the external endpoint or repository-wide link policy is addressed. |
|
DOC CI has now passed on the unchanged current head ( |
|
Thanks — pinning host keys here makes sense. SshClient.setUpDefaultClient() inherits ClientBuilder.DEFAULT_SERVER_KEY_VERIFIER, which is AcceptAllServerKeyVerifier.INSTANCE (verified in sshd-core 2.13.1), so today any server key is accepted. A few points on the implementation. The compatibility migration isn't one-time SftpHostKeyCompatibilityMigration is a CommandLineRunner with no version record or completion marker, so it re-scans all ftp monitors on every startup and writes insecureSkipVerify=true into any SFTP monitor lacking both hostKeyFingerprint and insecureSkipVerify. That's correct for the upgrade moment, but it keeps applying afterwards: a monitor that reaches the database without a host-key policy — via config import, a direct API call, or SQL — gets converted to "skip verification" at the next restart. The normal UI path is likely unaffected, since insecureSkipVerify has defaultValue: false and produces a param row, but the import/API paths bypass that. Suggestion: make it a Flyway Java migration, or persist a completion flag so the backfill runs once. New monitors should opt into the unsafe mode explicitly rather than inherit it. "Required" is declared three different ways In app-ftp.yml, hostKeyFingerprint is required: false and hide: true, its display name says "(必填)/ Required", and the collector treats it as mandatory in both FtpProtocol.isInvalid() and preCheck(). hide: true puts it in the collapsed Advanced Parameters panel (monitor-form.component.html:122-131) rather than hiding it outright, but a user who doesn't expand that panel gets a rejected job referencing a field they never saw. Worth making the three agree — either mark it required and surface it, or drop "必填" from the label. Pin the digest explicitly KeyUtils.getFingerPrint(PublicKey) resolves through DEFAULT_DIGEST_HOLDER, an AtomicReference that's mutable via setDefaultFingerPrintFactory(...) and the KEY_FINGERPRINT_FACTORY_PROP system property. Since the docs and placeholder promise SHA256:, the explicit overload would be safer: KeyUtils.getFingerPrint(BuiltinDigests.sha256, serverKey) Fingerprint comparison is format-sensitive Raw byte equality against the trimmed input means a fingerprint pasted without the SHA256: prefix, or with different base64 casing, fails with the generic "did not match" warning and no hint that the format was the issue. Normalizing, or rejecting malformed entries up front with a clear message, would save operators some guessing. Minor: MessageDigest.isEqual is unnecessary here — fingerprints are public, there's no secret to leak through timing. |
Summary
Regression proof
The rotation contract was first run against the previous PR head. It rejected the second verified key because the implementation treated the entire multi-line value as one fingerprint. The legacy-upgrade contract also had no implementation on the previous head. Both outcome paths pass with this revision.
Validation
FtpProtocolTest,FtpCollectImplTest, andSftpHostKeyCompatibilityMigrationTest).YamlCheckScript: all monitor definitions parsed successfully../mvnw -pl hertzbeat-startup -am -DskipTests package: all 24 reactor modules passed and produced the source-built startup artifact.git diff --check: passed.Upgrade behavior
Existing
ftpmonitors with SFTP enabled and neither a fingerprint nor an explicit verification policy receiveinsecureSkipVerify=trueonce, before scheduler initialization. This preserves collection but produces warnings until the operator verifies fingerprints, adds them, disables the unsafe option, and runs detection. Pinned and previously migrated monitors are not changed. New monitors and newly imported configurations remain fail-closed unless the operator explicitly selects the dangerous temporary option.ssh-keyscanis documented only as a way to retrieve a key, not as proof of identity. Operators must compare the resulting fingerprint through a trusted channel.AI assistance: used for draft implementation and test iteration.
Human validation: the old-head rotation contract failed; focused outcome tests, YAML parsing, Checkstyle, whitespace checks, and the 24-module startup package proof passed.
Risk notes: upgraded monitors remain temporarily unauthenticated until an operator completes the documented pinning step; warnings make this compatibility state visible.