44 lines
1.9 KiB
C#
44 lines
1.9 KiB
C#
using System.Security.Cryptography;
|
|
|
|
namespace Fleet.Core;
|
|
|
|
/// <summary>
|
|
/// 节点握手时自述的「我跑的是哪个二进制」:正在运行的可执行文件的 SHA-256,以及(容器节点)宿主机更新器验过的 CI 签名清单和签名。
|
|
/// 服务端在节点第一次握手成功的那一刻把哈希绑定到这个节点,之后哈希对不上就不让它继续运行。
|
|
/// </summary>
|
|
public sealed record BinaryAttestation(string Sha256, string? Manifest, string? Signature);
|
|
|
|
/// <summary>
|
|
/// 正在运行的二进制的哈希。Linux 上读 <c>/proc/self/exe</c>:它指向进程启动时映射的那个映像,磁盘上的文件之后被换掉也不影响,
|
|
/// 所以「运行期间被替换、重启后换了别的」的情况下一次握手就会对不上。算一次,之后缓存。
|
|
/// </summary>
|
|
public static class NodeBinary
|
|
{
|
|
private static readonly Lazy<string?> s_hash = new(Compute);
|
|
|
|
/// <summary>小写十六进制;读不到可执行文件时为 null(这样的节点不做绑定)。</summary>
|
|
public static string? Sha256Hex => s_hash.Value;
|
|
|
|
/// <summary>在后台先算好,免得第一次握手等它。</summary>
|
|
public static void Prime() => _ = Task.Run(() => s_hash.Value);
|
|
|
|
private static string? Compute()
|
|
{
|
|
try
|
|
{
|
|
string? path = OperatingSystem.IsLinux() && File.Exists("/proc/self/exe") ? "/proc/self/exe" : Environment.ProcessPath;
|
|
if (path is null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
using var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete, 1 << 16);
|
|
return Convert.ToHexStringLower(SHA256.HashData(stream));
|
|
}
|
|
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
}
|