Stopped automatic SQL Server services (8e)
SQLI-SVC-001 (High) reports a service set to start automatically that is not running (SQL Server Agent, Full-text launcher, Launchpad …), from the sys.dm_server_services data the configuration collector already reads (2008 R2 SP1+; not relevant before). The service account is sensitive. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4d18d20ab0
commit
66129d99fc
6 changed files with 91 additions and 2 deletions
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
SQLInsight Pro er et overvågningsværktøj til Microsoft SQL Server, skrevet i C# på .NET. Det kører hos kunden og forlader ikke netværket, medmindre kunden selv vælger det. Værktøjet nøjes ikke med at vise tal. Det forklarer, hvad der er galt, hvorfor det er et problem, og hvordan det løses. Rådene har samme niveau som dem, man får fra en erfaren DBA.
|
||||
|
||||
> **Status:** Fase 1–4 er implementeret: agent, 78 indbyggede regler plus community-regler, notifikationer, lokalt repository og web-UI, licenser, signerede opdateringer, SQLInsight Hub med portal, erfaring på tværs af kunder, PDF-rapporter og integration med Prometheus, Grafana og SCOM, plus MSI-installer, community-websted og Discourse-forum. Se [installation](docs/installation.md), [opdateringer](docs/opdatering.md), [integration](docs/integration.md), [rapporter](docs/rapporter.md), [egne regler](docs/regler.md), [databehandling](docs/databehandling.md), [community](docs/community.md), [Roadmap](#roadmap) og [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||
> **Status:** Fase 1–4 er implementeret: agent, 79 indbyggede regler plus community-regler, notifikationer, lokalt repository og web-UI, licenser, signerede opdateringer, SQLInsight Hub med portal, erfaring på tværs af kunder, PDF-rapporter og integration med Prometheus, Grafana og SCOM, plus MSI-installer, community-websted og Discourse-forum. Se [installation](docs/installation.md), [opdateringer](docs/opdatering.md), [integration](docs/integration.md), [rapporter](docs/rapporter.md), [egne regler](docs/regler.md), [databehandling](docs/databehandling.md), [community](docs/community.md), [Roadmap](#roadmap) og [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -19,3 +19,7 @@ Lock Pages in Memory og Instant File Initialization kan kun aflæses fra SQL Ser
|
|||
Agenten læser konfigurationen hvert 15. minut (collector `instance-config`) og sammenligner med sidste gang, også på tværs af en genstart af agenten. Ændringer af sp_configure, trace flags og tjenestekonti giver fundet **SQLI-CFG-013 Konfiguration ændret** (information, i et døgn), og alle ændringer, også version og antal tempdb-filer, står i ændringsloggen og i driftsrapporten. Den første måling efter installationen er udgangspunktet.
|
||||
|
||||
Tidspunktet er, hvornår ændringen blev opdaget, ikke hvornår den blev lavet. Ændringsloggen gemmes lige så længe som løste fund (`SQLInsight:Retention:ResolvedFindingDays`, standard 365 dage).
|
||||
|
||||
## Tjenester, der ikke kører
|
||||
|
||||
Reglen **SQLI-SVC-001** (Høj) melder, når en SQL Server-tjeneste, der er sat til at starte automatisk, ikke kører: typisk SQL Server Agent (så kører hverken backup eller vedligeholdelse), Full-text Filter Daemon Launcher eller Launchpad. Tjenesterne læses fra `sys.dm_server_services` sammen med konfigurationen hvert 15. minut og kræver SQL Server 2008 R2 SP1 eller nyere; på ældre versioner er reglen ikke relevant.
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ public static class BuiltInRules
|
|||
new VersionStoreRule(),
|
||||
new TempdbFullRule(),
|
||||
new TempdbSessionRule(),
|
||||
new StoppedServiceRule(),
|
||||
new MemoryGrantsPendingRule(),
|
||||
new AnomalyRule(),
|
||||
new PlanRegressionRule(),
|
||||
|
|
|
|||
51
src/SQLInsight.Rules/Instance/ServiceRules.cs
Normal file
51
src/SQLInsight.Rules/Instance/ServiceRules.cs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
using SQLInsight.Core.Collection;
|
||||
using SQLInsight.Core.Data;
|
||||
using SQLInsight.Core.Findings;
|
||||
using SQLInsight.Core.Instances;
|
||||
using SQLInsight.Rules.Engine;
|
||||
|
||||
namespace SQLInsight.Rules.Instance;
|
||||
|
||||
/// <summary>
|
||||
/// A SQL Server service set to start automatically is not running: SQL Server Agent (no backups or maintenance jobs),
|
||||
/// the Full-text launcher (no full-text search) or Launchpad (no R/Python). From sys.dm_server_services, SQL Server
|
||||
/// 2008 R2 SP1+.
|
||||
/// </summary>
|
||||
public sealed class StoppedServiceRule : Rule
|
||||
{
|
||||
public override string Id => "SQLI-SVC-001";
|
||||
public override string Title => "En SQL Server-tjeneste, der skal starte automatisk, kører ikke";
|
||||
public override IReadOnlyCollection<Capability> RequiredCapabilities => [Capability.VolumeStats];
|
||||
|
||||
public override RuleEvaluation Evaluate(RuleContext context)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(context);
|
||||
var setup = context.Data.Get<InstanceConfigurationSnapshot>();
|
||||
if (!setup.ServicesAvailable)
|
||||
{
|
||||
throw new DataUnavailableException("Tjenesterne kunne ikke læses (sys.dm_server_services).");
|
||||
}
|
||||
|
||||
return Result(setup.Services
|
||||
.Where(s => string.Equals(s.StartupType, "Automatic", StringComparison.OrdinalIgnoreCase)
|
||||
&& !string.Equals(s.Status, "Running", StringComparison.OrdinalIgnoreCase))
|
||||
.Select(s => CreateFinding(
|
||||
Severity.High,
|
||||
$"Tjenesten {s.Name} kører ikke",
|
||||
$"{s.Name} er sat til at starte automatisk, men står som \"{s.Status}\". "
|
||||
+ (s.Name.Contains("Agent", StringComparison.OrdinalIgnoreCase)
|
||||
? "Uden SQL Server Agent kører hverken backup, integritetstjek, indexvedligehold eller andre planlagte job."
|
||||
: s.Name.Contains("Full-text", StringComparison.OrdinalIgnoreCase) || s.Name.Contains("Launcher", StringComparison.OrdinalIgnoreCase)
|
||||
? "Uden den virker fulltext-søgning og -opdatering ikke."
|
||||
: "Funktionerne, der bruger tjenesten, virker ikke."),
|
||||
"Start tjenesten i SQL Server Configuration Manager, og find i Windows' hændelseslog (System) eller tjenestens egen log, hvorfor den stoppede. "
|
||||
+ "Tjek også, at tjenestekontoens kodeord ikke er udløbet.",
|
||||
[
|
||||
new Evidence("Tjeneste", s.Name),
|
||||
new Evidence("Status", s.Status ?? "ukendt"),
|
||||
new Evidence("Start", s.StartupType ?? "–"),
|
||||
new Evidence("Konto", s.Account ?? "–", Sensitive: true),
|
||||
],
|
||||
subject: $"service: {s.Name}")));
|
||||
}
|
||||
}
|
||||
|
|
@ -18,6 +18,6 @@ public class RuleCatalogTests
|
|||
[Fact]
|
||||
public void Rule_count()
|
||||
{
|
||||
Assert.Equal(78, BuiltInRules.Create().Count);
|
||||
Assert.Equal(79, BuiltInRules.Create().Count);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
33
tests/SQLInsight.Rules.Tests/ServiceRuleTests.cs
Normal file
33
tests/SQLInsight.Rules.Tests/ServiceRuleTests.cs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
using SQLInsight.Core.Data;
|
||||
using SQLInsight.Core.Findings;
|
||||
using SQLInsight.Rules.Engine;
|
||||
using SQLInsight.Rules.Instance;
|
||||
using static SQLInsight.Rules.Tests.TestInstances;
|
||||
|
||||
namespace SQLInsight.Rules.Tests;
|
||||
|
||||
public class ServiceRuleTests
|
||||
{
|
||||
private static RuleResult Run(IRule rule, RuleContext context) => Assert.Single(new RuleEngine([rule]).Evaluate(context));
|
||||
|
||||
private static InstanceConfigurationSnapshot Setup(params ServiceInfo[] services) =>
|
||||
new() { CapturedAt = Now, ServicesAvailable = true, Services = services };
|
||||
|
||||
[Fact]
|
||||
public void A_stopped_automatic_service_is_high_and_manual_ones_are_ignored()
|
||||
{
|
||||
var result = Run(new StoppedServiceRule(), With(Setup(
|
||||
new ServiceInfo("SQL Server (MSSQLSERVER)", @"NT Service\MSSQLSERVER", "Automatic", "Running", true),
|
||||
new ServiceInfo("SQL Server Agent (MSSQLSERVER)", @"KUNDE\svc-agent", "Automatic", "Stopped", null),
|
||||
new ServiceInfo("SQL Server Launchpad (MSSQLSERVER)", null, "Manual", "Stopped", null))));
|
||||
|
||||
var finding = Assert.Single(result.Findings);
|
||||
Assert.Equal(Severity.High, finding.Severity);
|
||||
Assert.Contains("backup", finding.Explanation, StringComparison.Ordinal);
|
||||
Assert.True(finding.Evidence.Single(e => e.Name == "Konto").Sensitive);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Before_2008_r2_sp1_it_is_not_relevant() =>
|
||||
Assert.Equal(RuleOutcome.NotApplicable, Run(new StoppedServiceRule(), WithVersion("10.50.1600.1", Setup())).Outcome);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue