feat!: probes generate their own keys and enroll with a join token; node and peer keys are separate [CI]
ci/woodpecker/push/main-amd64-build Pipeline was successful

This commit is contained in:
justme committed 2026-10-07 16:57:34 +08:00
1 parent 1ff847e45a
commit a9f562441f
51 files changed
+505 -749

No files matched your search

@@ -19,6 +19,13 @@ public sealed class EnrollRequest
[JsonPropertyName("tls_spki")]
public string TlsSpki { get; set; } = "";
/// <summary>
/// 同一把 TLS 密钥的完整公钥(SPKI,base64),必须和 <see cref="TlsSpki"/> 对得上。节点用这把密钥做对等面的签名认证
/// (和连服务端用的身份密钥是两把独立的密钥),对端要验签就需要完整的公钥,而不只是指纹。
/// </summary>
[JsonPropertyName("tls_pubkey")]
public string TlsPublicKey { get; set; } = "";
/// <summary>持有证明:对 <c>fleet|v1|enroll|{sha256_hex(join_token)}|{pubkey}</c> 的签名(base64)。</summary>
[JsonPropertyName("proof")]
public string Proof { get; set; } = "";
@@ -29,9 +29,16 @@ public sealed partial class FleetEnrollmentService
if (!TryDecode(request.PublicKey, out byte[] publicKey) || !NodeIdentity.IsValidPublicKey(publicKey)
|| !TryDecode(request.TlsSpki, out byte[] tlsSpki) || tlsSpki.Length != 32
|| !TryDecode(request.TlsPublicKey, out byte[] tlsPublicKey) || !NodeIdentity.IsValidPublicKey(tlsPublicKey)
|| !TryDecode(request.Proof, out byte[] proof))
{
return Result<EnrollResponse>.Fail(FleetErrors.InvalidParams, "pubkey, tls_spki or proof is malformed");
return Result<EnrollResponse>.Fail(FleetErrors.InvalidParams, "pubkey, tls_spki, tls_pubkey or proof is malformed");
}
// 指纹和完整公钥必须是同一把密钥,否则对端按指纹固定证书、按公钥验签,会各认各的
if (!System.Security.Cryptography.CryptographicOperations.FixedTimeEquals(NodeIdentity.Fingerprint(tlsPublicKey), tlsSpki))
{
return Result<EnrollResponse>.Fail(FleetErrors.InvalidParams, "tls_spki does not match tls_pubkey");
}
byte[] tokenHash = TokenHash.Sha256(request.JoinToken);
@@ -61,8 +68,9 @@ public sealed partial class FleetEnrollmentService
bool nameTaken = await _store.FindEstablishedNodeByNameAsync(request.Name, ct) is not null;
NodeStatus status = token.AutoApprove && !nameTaken ? NodeStatus.Active : NodeStatus.Pending;
string prefix = token.Kind.Length > 0 && _options.NodeIdPrefixes.TryGetValue(token.Kind, out string? kindPrefix) ? kindPrefix : _options.NodeIdPrefix;
var node = new NewNode(
new NodeId(Ulid.NewPrefixed(_options.NodeIdPrefix, _time)),
new NodeId(Ulid.NewPrefixed(prefix, _time)),
request.Name,
status,
publicKey,
@@ -70,7 +78,9 @@ public sealed partial class FleetEnrollmentService
token.Labels,
request.Meta?.GetRawText(),
request.NodeVersion,
nowMs);
nowMs,
token.Kind,
tlsPublicKey);
Result<NodeRecord> created = await _store.CreateNodeAsync(node, ct);
if (!created.TryGet(out NodeRecord? record, out FleetError? error))