Security: Pro-Geräte Agent-Keys statt geteiltem AGENT_API_KEY (v2.8.0)
Agent v2.8.0 tauscht beim Start automatisch den geteilten Bootstrap-Key gegen einen individuellen Per-Device-Key (POST /api/monitoring/enroll, idempotent). Checkin/Announcements-Poll/Setup-Download/WS-Agent-Verbindungen validieren den Key jetzt gegen den jeweiligen Hostname — ein gestohlener Key kann sich nicht mehr als anderer Agent ausgeben (manuell verifiziert). Alte Agents mit dem geteilten Key funktionieren während der Übergangsphase weiter (validateAgentKey() akzeptiert beides), damit der Rollout die Fleet nicht abrupt bricht — Migration läuft über den bestehenden Staged-Rollout (Test → Pilot → Produktion). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,7 @@ namespace ITNexusAgent;
|
||||
|
||||
public class AgentWorker
|
||||
{
|
||||
private const string Version = "2.7.0";
|
||||
private const string Version = "2.8.0";
|
||||
private const string DataDir = @"C:\ProgramData\IT Nexus Agent";
|
||||
private const string ConfigPath = @"C:\ProgramData\IT Nexus Agent\config.json";
|
||||
private const string StatusPath = @"C:\ProgramData\IT Nexus Agent\status.json";
|
||||
@@ -40,12 +40,24 @@ public class AgentWorker
|
||||
|
||||
Log($"Agent v{Version} gestartet");
|
||||
|
||||
// Security-Migration: geteilten Bootstrap-Key gegen individuellen Per-Device-Key tauschen.
|
||||
// Idempotent (Server liefert bestehenden Key erneut) — daher bei jedem Start sicher aufrufbar.
|
||||
var hostname = SystemInfoService.GetHostname();
|
||||
var enrolledKey = await _api.EnrollAsync(hostname);
|
||||
if (!string.IsNullOrEmpty(enrolledKey) && enrolledKey != _config.AgentKey)
|
||||
{
|
||||
_config.AgentKey = enrolledKey;
|
||||
_config.Save(ConfigPath);
|
||||
_api.UpdateKey(enrolledKey);
|
||||
Log("ENROLL: Per-Device-Key erhalten und gespeichert");
|
||||
}
|
||||
|
||||
// WebSocket Shell-Service im Hintergrund starten
|
||||
var shellService = new ShellService(_config.ServerUrl, _config.AgentKey, SystemInfoService.GetHostname());
|
||||
var shellService = new ShellService(_config.ServerUrl, _config.AgentKey, hostname);
|
||||
_ = shellService.RunAsync(_ct);
|
||||
|
||||
// WebRTC Remote Desktop Service im Hintergrund starten
|
||||
var rtcService = new RtcService(_config.ServerUrl, _config.AgentKey, SystemInfoService.GetHostname());
|
||||
var rtcService = new RtcService(_config.ServerUrl, _config.AgentKey, hostname);
|
||||
_ = rtcService.RunAsync(_ct);
|
||||
|
||||
while (!_ct.IsCancellationRequested)
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<AssemblyName>IT-Nexus-Agent</AssemblyName>
|
||||
<RootNamespace>ITNexusAgent</RootNamespace>
|
||||
<Version>2.7.0</Version>
|
||||
<AssemblyVersion>2.7.0.0</AssemblyVersion>
|
||||
<Version>2.8.0</Version>
|
||||
<AssemblyVersion>2.8.0.0</AssemblyVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
|
||||
|
||||
@@ -17,4 +17,9 @@ public class AgentConfig
|
||||
return JsonConvert.DeserializeObject<AgentConfig>(json)
|
||||
?? throw new Exception("Ungültige config.json");
|
||||
}
|
||||
|
||||
public void Save(string path)
|
||||
{
|
||||
File.WriteAllText(path, JsonConvert.SerializeObject(this, Formatting.Indented));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,25 @@ public class ApiService(string serverUrl, string agentKey)
|
||||
{
|
||||
private readonly HttpClient _http = new() { Timeout = TimeSpan.FromSeconds(30) };
|
||||
private readonly string _baseUrl = serverUrl.TrimEnd('/');
|
||||
private readonly string _agentKey = agentKey;
|
||||
private string _agentKey = agentKey;
|
||||
|
||||
// Nach erfolgreichem Enrollment wird der geteilte Bootstrap-Key durch den individuellen
|
||||
// Per-Device-Key ersetzt — alle nachfolgenden Requests dieser Instanz nutzen ab dann den neuen Key.
|
||||
public void UpdateKey(string newKey) => _agentKey = newKey;
|
||||
|
||||
public async Task<string?> EnrollAsync(string hostname)
|
||||
{
|
||||
try
|
||||
{
|
||||
var req = BuildRequest(HttpMethod.Post, "/api/monitoring/enroll", new { hostname });
|
||||
var resp = await _http.SendAsync(req);
|
||||
if (!resp.IsSuccessStatusCode) return null;
|
||||
var body = await resp.Content.ReadAsStringAsync();
|
||||
var result = JsonConvert.DeserializeAnonymousType(body, new { status = "", data = new { agent_key = "" } });
|
||||
return result?.data?.agent_key;
|
||||
}
|
||||
catch { return null; }
|
||||
}
|
||||
|
||||
private HttpRequestMessage BuildRequest(HttpMethod method, string path, object? body = null)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#define MyAppName "IT Nexus Agent"
|
||||
#define MyAppVersion "2.7.0"
|
||||
#define MyAppVersion "2.8.0"
|
||||
#define MyAppPublisher "Cereda Systems GmbH"
|
||||
#define MyAppURL "https://it-nexus.cereda-systems.de"
|
||||
#define MyAppExeName "IT-Nexus-Agent.exe"
|
||||
|
||||
Reference in New Issue
Block a user