@oneuptime/common 10.4.12 → 10.4.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Server/Utils/Monitor/Criteria/DnssecMonitorCriteria.ts +108 -0
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +13 -0
- package/Server/Utils/Monitor/MonitorTemplateUtil.ts +25 -0
- package/Types/Monitor/CriteriaFilter.ts +13 -0
- package/Types/Monitor/DnssecMonitor/DnssecMonitorResponse.ts +69 -0
- package/Types/Monitor/MonitorCriteriaInstance.ts +67 -0
- package/Types/Monitor/MonitorStep.ts +39 -0
- package/Types/Monitor/MonitorStepDnssecMonitor.ts +59 -0
- package/Types/Monitor/MonitorType.ts +17 -1
- package/Types/Probe/ProbeMonitorResponse.ts +2 -0
- package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +51 -0
- package/Utils/Monitor/MonitorMetricType.ts +1 -0
- package/build/dist/Server/Utils/Monitor/Criteria/DnssecMonitorCriteria.js +94 -0
- package/build/dist/Server/Utils/Monitor/Criteria/DnssecMonitorCriteria.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +10 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +22 -3
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
- package/build/dist/Types/Monitor/CriteriaFilter.js +12 -0
- package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
- package/build/dist/Types/Monitor/DnssecMonitor/DnssecMonitorResponse.js +2 -0
- package/build/dist/Types/Monitor/DnssecMonitor/DnssecMonitorResponse.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +62 -0
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +26 -0
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepDnssecMonitor.js +42 -0
- package/build/dist/Types/Monitor/MonitorStepDnssecMonitor.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorType.js +15 -1
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +47 -0
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js +1 -0
- package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import DataToProcess from "../DataToProcess";
|
|
2
|
+
import CompareCriteria from "./CompareCriteria";
|
|
3
|
+
import {
|
|
4
|
+
CheckOn,
|
|
5
|
+
CriteriaFilter,
|
|
6
|
+
FilterType,
|
|
7
|
+
} from "../../../../Types/Monitor/CriteriaFilter";
|
|
8
|
+
import DnssecMonitorResponse from "../../../../Types/Monitor/DnssecMonitor/DnssecMonitorResponse";
|
|
9
|
+
import ProbeMonitorResponse from "../../../../Types/Probe/ProbeMonitorResponse";
|
|
10
|
+
import CaptureSpan from "../../Telemetry/CaptureSpan";
|
|
11
|
+
|
|
12
|
+
export default class DnssecMonitorCriteria {
|
|
13
|
+
@CaptureSpan()
|
|
14
|
+
public static async isMonitorInstanceCriteriaFilterMet(input: {
|
|
15
|
+
dataToProcess: DataToProcess;
|
|
16
|
+
criteriaFilter: CriteriaFilter;
|
|
17
|
+
}): Promise<string | null> {
|
|
18
|
+
const dataToProcess: ProbeMonitorResponse =
|
|
19
|
+
input.dataToProcess as ProbeMonitorResponse;
|
|
20
|
+
|
|
21
|
+
const dnssecResponse: DnssecMonitorResponse | undefined =
|
|
22
|
+
dataToProcess.dnssecResponse;
|
|
23
|
+
|
|
24
|
+
if (!dnssecResponse) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const isTrue: boolean = input.criteriaFilter.filterType === FilterType.True;
|
|
29
|
+
const isFalse: boolean =
|
|
30
|
+
input.criteriaFilter.filterType === FilterType.False;
|
|
31
|
+
|
|
32
|
+
if (input.criteriaFilter.checkOn === CheckOn.DnssecChainValid) {
|
|
33
|
+
if (dnssecResponse.isChainValid && isTrue) {
|
|
34
|
+
return `DNSSEC chain is valid for ${dnssecResponse.domainName}.`;
|
|
35
|
+
}
|
|
36
|
+
if (!dnssecResponse.isChainValid && isFalse) {
|
|
37
|
+
return `DNSSEC chain validation failed for ${dnssecResponse.domainName}.`;
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (input.criteriaFilter.checkOn === CheckOn.DnssecDnskeyExists) {
|
|
43
|
+
const exists: boolean = dnssecResponse.dnskeys.length > 0;
|
|
44
|
+
if (exists && isTrue) {
|
|
45
|
+
return `DNSKEY records present for ${dnssecResponse.domainName}.`;
|
|
46
|
+
}
|
|
47
|
+
if (!exists && isFalse) {
|
|
48
|
+
return `No DNSKEY records found for ${dnssecResponse.domainName}.`;
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (input.criteriaFilter.checkOn === CheckOn.DnssecDsExists) {
|
|
54
|
+
const exists: boolean = dnssecResponse.isParentDsPresent;
|
|
55
|
+
if (exists && isTrue) {
|
|
56
|
+
return `DS records present at parent zone for ${dnssecResponse.domainName}.`;
|
|
57
|
+
}
|
|
58
|
+
if (!exists && isFalse) {
|
|
59
|
+
return `No DS records found at the parent zone for ${dnssecResponse.domainName}.`;
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (input.criteriaFilter.checkOn === CheckOn.DnssecResolverConsensus) {
|
|
65
|
+
const consensus: boolean = dnssecResponse.resolverConsensusAd;
|
|
66
|
+
if (consensus && isTrue) {
|
|
67
|
+
return `All resolvers report DNSSEC-valid (AD flag) for ${dnssecResponse.domainName}.`;
|
|
68
|
+
}
|
|
69
|
+
if (!consensus && isFalse) {
|
|
70
|
+
return `Resolvers do not agree on DNSSEC validity for ${dnssecResponse.domainName}.`;
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (input.criteriaFilter.checkOn === CheckOn.DnssecNameserverConsistent) {
|
|
76
|
+
const consistent: boolean = dnssecResponse.isNameserverConsistent;
|
|
77
|
+
if (consistent && isTrue) {
|
|
78
|
+
return `Authoritative nameservers are consistent for ${dnssecResponse.domainName}.`;
|
|
79
|
+
}
|
|
80
|
+
if (!consistent && isFalse) {
|
|
81
|
+
return `Authoritative nameservers are inconsistent for ${dnssecResponse.domainName}.`;
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (input.criteriaFilter.checkOn === CheckOn.DnssecSignatureExpiresInDays) {
|
|
87
|
+
const threshold: number | null = CompareCriteria.convertToNumber(
|
|
88
|
+
input.criteriaFilter.value,
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
if (threshold === null || threshold === undefined) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (dnssecResponse.daysUntilSignatureExpiry === undefined) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return CompareCriteria.compareCriteriaNumbers({
|
|
100
|
+
value: dnssecResponse.daysUntilSignatureExpiry,
|
|
101
|
+
threshold: threshold,
|
|
102
|
+
criteriaFilter: input.criteriaFilter,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -18,6 +18,7 @@ import ProfileMonitorCriteria from "./Criteria/ProfileMonitorCriteria";
|
|
|
18
18
|
import SnmpMonitorCriteria from "./Criteria/SnmpMonitorCriteria";
|
|
19
19
|
import DnsMonitorCriteria from "./Criteria/DnsMonitorCriteria";
|
|
20
20
|
import DomainMonitorCriteria from "./Criteria/DomainMonitorCriteria";
|
|
21
|
+
import DnssecMonitorCriteria from "./Criteria/DnssecMonitorCriteria";
|
|
21
22
|
import ExternalStatusPageMonitorCriteria from "./Criteria/ExternalStatusPageMonitorCriteria";
|
|
22
23
|
import MonitorCriteriaMessageBuilder from "./MonitorCriteriaMessageBuilder";
|
|
23
24
|
import MonitorCriteriaDataExtractor from "./MonitorCriteriaDataExtractor";
|
|
@@ -761,6 +762,18 @@ ${contextBlock}
|
|
|
761
762
|
}
|
|
762
763
|
}
|
|
763
764
|
|
|
765
|
+
if (input.monitor.monitorType === MonitorType.DNSSEC) {
|
|
766
|
+
const dnssecMonitorResult: string | null =
|
|
767
|
+
await DnssecMonitorCriteria.isMonitorInstanceCriteriaFilterMet({
|
|
768
|
+
dataToProcess: input.dataToProcess,
|
|
769
|
+
criteriaFilter: input.criteriaFilter,
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
if (dnssecMonitorResult) {
|
|
773
|
+
return dnssecMonitorResult;
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
|
|
764
777
|
if (input.monitor.monitorType === MonitorType.ExternalStatusPage) {
|
|
765
778
|
const externalStatusPageResult: string | null =
|
|
766
779
|
await ExternalStatusPageMonitorCriteria.isMonitorInstanceCriteriaFilterMet(
|
|
@@ -19,6 +19,7 @@ import DnsMonitorResponse, {
|
|
|
19
19
|
DnsRecordResponse,
|
|
20
20
|
} from "../../../Types/Monitor/DnsMonitor/DnsMonitorResponse";
|
|
21
21
|
import DomainMonitorResponse from "../../../Types/Monitor/DomainMonitor/DomainMonitorResponse";
|
|
22
|
+
import DnssecMonitorResponse from "../../../Types/Monitor/DnssecMonitor/DnssecMonitorResponse";
|
|
22
23
|
import ExternalStatusPageMonitorResponse, {
|
|
23
24
|
ExternalStatusPageComponentStatus,
|
|
24
25
|
} from "../../../Types/Monitor/ExternalStatusPageMonitor/ExternalStatusPageMonitorResponse";
|
|
@@ -332,6 +333,30 @@ export default class MonitorTemplateUtil {
|
|
|
332
333
|
} as JSONObject;
|
|
333
334
|
}
|
|
334
335
|
|
|
336
|
+
if (data.monitorType === MonitorType.DNSSEC) {
|
|
337
|
+
const dnssecResponse: DnssecMonitorResponse | undefined = (
|
|
338
|
+
data.dataToProcess as ProbeMonitorResponse
|
|
339
|
+
).dnssecResponse;
|
|
340
|
+
|
|
341
|
+
storageMap = {
|
|
342
|
+
isOnline: (data.dataToProcess as ProbeMonitorResponse).isOnline,
|
|
343
|
+
responseTimeInMs: dnssecResponse?.responseTimeInMs,
|
|
344
|
+
failureCause: dnssecResponse?.failureCause,
|
|
345
|
+
domainName: dnssecResponse?.domainName,
|
|
346
|
+
isZoneSigned: dnssecResponse?.isZoneSigned,
|
|
347
|
+
isParentDsPresent: dnssecResponse?.isParentDsPresent,
|
|
348
|
+
isChainValid: dnssecResponse?.isChainValid,
|
|
349
|
+
resolverConsensusAd: dnssecResponse?.resolverConsensusAd,
|
|
350
|
+
isNameserverConsistent: dnssecResponse?.isNameserverConsistent,
|
|
351
|
+
earliestSignatureExpiration:
|
|
352
|
+
dnssecResponse?.earliestSignatureExpiration,
|
|
353
|
+
daysUntilSignatureExpiry: dnssecResponse?.daysUntilSignatureExpiry,
|
|
354
|
+
dnskeyCount: dnssecResponse?.dnskeys?.length,
|
|
355
|
+
dsRecordCount: dnssecResponse?.parentDsRecords?.length,
|
|
356
|
+
rrsigCount: dnssecResponse?.rrsigs?.length,
|
|
357
|
+
} as JSONObject;
|
|
358
|
+
}
|
|
359
|
+
|
|
335
360
|
if (
|
|
336
361
|
data.monitorType === MonitorType.Metrics ||
|
|
337
362
|
data.monitorType === MonitorType.Kubernetes ||
|
|
@@ -84,6 +84,14 @@ export enum CheckOn {
|
|
|
84
84
|
DomainStatusCode = "Domain Status Code",
|
|
85
85
|
DomainIsExpired = "Domain Is Expired",
|
|
86
86
|
|
|
87
|
+
// DNSSEC monitors.
|
|
88
|
+
DnssecChainValid = "DNSSEC Chain Is Valid",
|
|
89
|
+
DnssecDnskeyExists = "DNSSEC DNSKEY Record Exists",
|
|
90
|
+
DnssecDsExists = "DNSSEC DS Record Exists At Parent",
|
|
91
|
+
DnssecSignatureExpiresInDays = "DNSSEC Signature Expires In Days",
|
|
92
|
+
DnssecResolverConsensus = "DNSSEC Resolver Consensus (AD Flag)",
|
|
93
|
+
DnssecNameserverConsistent = "DNSSEC Nameservers Are Consistent",
|
|
94
|
+
|
|
87
95
|
// External Status Page monitors.
|
|
88
96
|
ExternalStatusPageIsOnline = "External Status Page Is Online",
|
|
89
97
|
ExternalStatusPageOverallStatus = "External Status Page Overall Status",
|
|
@@ -279,6 +287,11 @@ export class CriteriaFilterUtil {
|
|
|
279
287
|
checkOn === CheckOn.SnmpIsOnline ||
|
|
280
288
|
checkOn === CheckOn.DnsIsOnline ||
|
|
281
289
|
checkOn === CheckOn.DomainIsExpired ||
|
|
290
|
+
checkOn === CheckOn.DnssecChainValid ||
|
|
291
|
+
checkOn === CheckOn.DnssecDnskeyExists ||
|
|
292
|
+
checkOn === CheckOn.DnssecDsExists ||
|
|
293
|
+
checkOn === CheckOn.DnssecResolverConsensus ||
|
|
294
|
+
checkOn === CheckOn.DnssecNameserverConsistent ||
|
|
282
295
|
checkOn === CheckOn.ExternalStatusPageIsOnline
|
|
283
296
|
) {
|
|
284
297
|
return false;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export interface DnssecKeyRecord {
|
|
2
|
+
flags: number;
|
|
3
|
+
algorithm: number;
|
|
4
|
+
keyTag?: number | undefined;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface DnssecDsRecord {
|
|
8
|
+
keyTag: number;
|
|
9
|
+
algorithm: number;
|
|
10
|
+
digestType: number;
|
|
11
|
+
digest: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface DnssecRrsigRecord {
|
|
15
|
+
typeCovered: string;
|
|
16
|
+
algorithm: number;
|
|
17
|
+
signerName: string;
|
|
18
|
+
keyTag: number;
|
|
19
|
+
inception?: string | undefined;
|
|
20
|
+
expiration?: string | undefined;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface DnssecResolverCheck {
|
|
24
|
+
resolver: string;
|
|
25
|
+
adFlag: boolean;
|
|
26
|
+
servfailWhenValidating: boolean;
|
|
27
|
+
error?: string | undefined;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface DnssecNameserverCheck {
|
|
31
|
+
nameServer: string;
|
|
32
|
+
soaSerial?: string | undefined;
|
|
33
|
+
rrsigExpiration?: string | undefined;
|
|
34
|
+
error?: string | undefined;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default interface DnssecMonitorResponse {
|
|
38
|
+
isOnline: boolean;
|
|
39
|
+
responseTimeInMs: number;
|
|
40
|
+
failureCause: string;
|
|
41
|
+
domainName: string;
|
|
42
|
+
isTimeout?: boolean | undefined;
|
|
43
|
+
|
|
44
|
+
// Zone signed?
|
|
45
|
+
isZoneSigned: boolean;
|
|
46
|
+
|
|
47
|
+
// DNSKEY presence
|
|
48
|
+
dnskeys: Array<DnssecKeyRecord>;
|
|
49
|
+
|
|
50
|
+
// DS at parent
|
|
51
|
+
parentDsRecords: Array<DnssecDsRecord>;
|
|
52
|
+
isParentDsPresent: boolean;
|
|
53
|
+
|
|
54
|
+
// RRSIG over the A record (zone apex by default)
|
|
55
|
+
rrsigs: Array<DnssecRrsigRecord>;
|
|
56
|
+
earliestSignatureExpiration?: string | undefined;
|
|
57
|
+
daysUntilSignatureExpiry?: number | undefined;
|
|
58
|
+
|
|
59
|
+
// Resolver consensus (AD flag + CD-bit SERVFAIL test)
|
|
60
|
+
resolverChecks: Array<DnssecResolverCheck>;
|
|
61
|
+
resolverConsensusAd: boolean;
|
|
62
|
+
|
|
63
|
+
// Primary/secondary nameserver consistency
|
|
64
|
+
nameserverChecks: Array<DnssecNameserverCheck>;
|
|
65
|
+
isNameserverConsistent: boolean;
|
|
66
|
+
|
|
67
|
+
// Overall chain validity (DNSKEY exists, DS exists, RRSIG valid, AD across resolvers)
|
|
68
|
+
isChainValid: boolean;
|
|
69
|
+
}
|
|
@@ -487,6 +487,33 @@ export default class MonitorCriteriaInstance extends DatabaseProperty {
|
|
|
487
487
|
return monitorCriteriaInstance;
|
|
488
488
|
}
|
|
489
489
|
|
|
490
|
+
if (arg.monitorType === MonitorType.DNSSEC) {
|
|
491
|
+
const monitorCriteriaInstance: MonitorCriteriaInstance =
|
|
492
|
+
new MonitorCriteriaInstance();
|
|
493
|
+
|
|
494
|
+
monitorCriteriaInstance.data = {
|
|
495
|
+
id: ObjectID.generate().toString(),
|
|
496
|
+
monitorStatusId: arg.monitorStatusId,
|
|
497
|
+
filterCondition: FilterCondition.All,
|
|
498
|
+
filters: [
|
|
499
|
+
{
|
|
500
|
+
checkOn: CheckOn.DnssecChainValid,
|
|
501
|
+
filterType: FilterType.True,
|
|
502
|
+
value: undefined,
|
|
503
|
+
},
|
|
504
|
+
],
|
|
505
|
+
incidents: [],
|
|
506
|
+
alerts: [],
|
|
507
|
+
createAlerts: false,
|
|
508
|
+
changeMonitorStatus: true,
|
|
509
|
+
createIncidents: false,
|
|
510
|
+
name: `Check if ${arg.monitorName} DNSSEC chain is valid`,
|
|
511
|
+
description: `This criteria checks if the ${arg.monitorName} DNSSEC chain is valid end-to-end`,
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
return monitorCriteriaInstance;
|
|
515
|
+
}
|
|
516
|
+
|
|
490
517
|
if (arg.monitorType === MonitorType.ExternalStatusPage) {
|
|
491
518
|
const monitorCriteriaInstance: MonitorCriteriaInstance =
|
|
492
519
|
new MonitorCriteriaInstance();
|
|
@@ -695,6 +722,46 @@ export default class MonitorCriteriaInstance extends DatabaseProperty {
|
|
|
695
722
|
};
|
|
696
723
|
}
|
|
697
724
|
|
|
725
|
+
if (arg.monitorType === MonitorType.DNSSEC) {
|
|
726
|
+
monitorCriteriaInstance.data = {
|
|
727
|
+
id: ObjectID.generate().toString(),
|
|
728
|
+
monitorStatusId: arg.monitorStatusId,
|
|
729
|
+
filterCondition: FilterCondition.Any,
|
|
730
|
+
filters: [
|
|
731
|
+
{
|
|
732
|
+
checkOn: CheckOn.DnssecChainValid,
|
|
733
|
+
filterType: FilterType.False,
|
|
734
|
+
value: undefined,
|
|
735
|
+
},
|
|
736
|
+
],
|
|
737
|
+
incidents: [
|
|
738
|
+
{
|
|
739
|
+
title: `${arg.monitorName} DNSSEC chain is broken`,
|
|
740
|
+
description: `${arg.monitorName} DNSSEC validation is currently failing.`,
|
|
741
|
+
incidentSeverityId: arg.incidentSeverityId,
|
|
742
|
+
autoResolveIncident: true,
|
|
743
|
+
id: ObjectID.generate().toString(),
|
|
744
|
+
onCallPolicyIds: [],
|
|
745
|
+
},
|
|
746
|
+
],
|
|
747
|
+
changeMonitorStatus: true,
|
|
748
|
+
createIncidents: true,
|
|
749
|
+
createAlerts: false,
|
|
750
|
+
alerts: [
|
|
751
|
+
{
|
|
752
|
+
title: `${arg.monitorName} DNSSEC chain is broken`,
|
|
753
|
+
description: `${arg.monitorName} DNSSEC validation is currently failing.`,
|
|
754
|
+
alertSeverityId: arg.alertSeverityId,
|
|
755
|
+
autoResolveAlert: true,
|
|
756
|
+
id: ObjectID.generate().toString(),
|
|
757
|
+
onCallPolicyIds: [],
|
|
758
|
+
},
|
|
759
|
+
],
|
|
760
|
+
name: `Check if ${arg.monitorName} DNSSEC chain is broken`,
|
|
761
|
+
description: `This criteria checks if the ${arg.monitorName} DNSSEC chain is broken`,
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
|
|
698
765
|
if (arg.monitorType === MonitorType.ExternalStatusPage) {
|
|
699
766
|
monitorCriteriaInstance.data = {
|
|
700
767
|
id: ObjectID.generate().toString(),
|
|
@@ -38,6 +38,9 @@ import MonitorStepDnsMonitor, {
|
|
|
38
38
|
import MonitorStepDomainMonitor, {
|
|
39
39
|
MonitorStepDomainMonitorUtil,
|
|
40
40
|
} from "./MonitorStepDomainMonitor";
|
|
41
|
+
import MonitorStepDnssecMonitor, {
|
|
42
|
+
MonitorStepDnssecMonitorUtil,
|
|
43
|
+
} from "./MonitorStepDnssecMonitor";
|
|
41
44
|
import MonitorStepExternalStatusPageMonitor, {
|
|
42
45
|
MonitorStepExternalStatusPageMonitorUtil,
|
|
43
46
|
} from "./MonitorStepExternalStatusPageMonitor";
|
|
@@ -109,6 +112,9 @@ export interface MonitorStepType {
|
|
|
109
112
|
// Domain monitor
|
|
110
113
|
domainMonitor?: MonitorStepDomainMonitor | undefined;
|
|
111
114
|
|
|
115
|
+
// DNSSEC monitor
|
|
116
|
+
dnssecMonitor?: MonitorStepDnssecMonitor | undefined;
|
|
117
|
+
|
|
112
118
|
// External Status Page monitor
|
|
113
119
|
externalStatusPageMonitor?: MonitorStepExternalStatusPageMonitor | undefined;
|
|
114
120
|
|
|
@@ -150,6 +156,7 @@ export default class MonitorStep extends DatabaseProperty {
|
|
|
150
156
|
snmpMonitor: undefined,
|
|
151
157
|
dnsMonitor: undefined,
|
|
152
158
|
domainMonitor: undefined,
|
|
159
|
+
dnssecMonitor: undefined,
|
|
153
160
|
externalStatusPageMonitor: undefined,
|
|
154
161
|
kubernetesMonitor: undefined,
|
|
155
162
|
dockerMonitor: undefined,
|
|
@@ -191,6 +198,7 @@ export default class MonitorStep extends DatabaseProperty {
|
|
|
191
198
|
snmpMonitor: undefined,
|
|
192
199
|
dnsMonitor: undefined,
|
|
193
200
|
domainMonitor: undefined,
|
|
201
|
+
dnssecMonitor: undefined,
|
|
194
202
|
externalStatusPageMonitor: undefined,
|
|
195
203
|
kubernetesMonitor: undefined,
|
|
196
204
|
dockerMonitor: undefined,
|
|
@@ -334,6 +342,13 @@ export default class MonitorStep extends DatabaseProperty {
|
|
|
334
342
|
return this;
|
|
335
343
|
}
|
|
336
344
|
|
|
345
|
+
public setDnssecMonitor(
|
|
346
|
+
dnssecMonitor: MonitorStepDnssecMonitor,
|
|
347
|
+
): MonitorStep {
|
|
348
|
+
this.data!.dnssecMonitor = dnssecMonitor;
|
|
349
|
+
return this;
|
|
350
|
+
}
|
|
351
|
+
|
|
337
352
|
public setExternalStatusPageMonitor(
|
|
338
353
|
externalStatusPageMonitor: MonitorStepExternalStatusPageMonitor,
|
|
339
354
|
): MonitorStep {
|
|
@@ -508,6 +523,23 @@ export default class MonitorStep extends DatabaseProperty {
|
|
|
508
523
|
}
|
|
509
524
|
}
|
|
510
525
|
|
|
526
|
+
if (monitorType === MonitorType.DNSSEC) {
|
|
527
|
+
if (!value.data.dnssecMonitor) {
|
|
528
|
+
return "DNSSEC configuration is required";
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
if (!value.data.dnssecMonitor.domainName) {
|
|
532
|
+
return "Domain name is required";
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
if (
|
|
536
|
+
!value.data.dnssecMonitor.resolvers ||
|
|
537
|
+
value.data.dnssecMonitor.resolvers.length === 0
|
|
538
|
+
) {
|
|
539
|
+
return "At least one resolver is required";
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
511
543
|
if (monitorType === MonitorType.ExternalStatusPage) {
|
|
512
544
|
if (!value.data.externalStatusPageMonitor) {
|
|
513
545
|
return "External status page configuration is required";
|
|
@@ -600,6 +632,9 @@ export default class MonitorStep extends DatabaseProperty {
|
|
|
600
632
|
domainMonitor: this.data.domainMonitor
|
|
601
633
|
? MonitorStepDomainMonitorUtil.toJSON(this.data.domainMonitor)
|
|
602
634
|
: undefined,
|
|
635
|
+
dnssecMonitor: this.data.dnssecMonitor
|
|
636
|
+
? MonitorStepDnssecMonitorUtil.toJSON(this.data.dnssecMonitor)
|
|
637
|
+
: undefined,
|
|
603
638
|
externalStatusPageMonitor: this.data.externalStatusPageMonitor
|
|
604
639
|
? MonitorStepExternalStatusPageMonitorUtil.toJSON(
|
|
605
640
|
this.data.externalStatusPageMonitor,
|
|
@@ -734,6 +769,9 @@ export default class MonitorStep extends DatabaseProperty {
|
|
|
734
769
|
domainMonitor: json["domainMonitor"]
|
|
735
770
|
? (json["domainMonitor"] as JSONObject)
|
|
736
771
|
: undefined,
|
|
772
|
+
dnssecMonitor: json["dnssecMonitor"]
|
|
773
|
+
? (json["dnssecMonitor"] as JSONObject)
|
|
774
|
+
: undefined,
|
|
737
775
|
externalStatusPageMonitor: json["externalStatusPageMonitor"]
|
|
738
776
|
? (json["externalStatusPageMonitor"] as JSONObject)
|
|
739
777
|
: undefined,
|
|
@@ -775,6 +813,7 @@ export default class MonitorStep extends DatabaseProperty {
|
|
|
775
813
|
snmpMonitor: Zod.any().optional(),
|
|
776
814
|
dnsMonitor: Zod.any().optional(),
|
|
777
815
|
domainMonitor: Zod.any().optional(),
|
|
816
|
+
dnssecMonitor: Zod.any().optional(),
|
|
778
817
|
externalStatusPageMonitor: Zod.any().optional(),
|
|
779
818
|
kubernetesMonitor: Zod.any().optional(),
|
|
780
819
|
dockerMonitor: Zod.any().optional(),
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { JSONObject } from "../JSON";
|
|
2
|
+
|
|
3
|
+
export default interface MonitorStepDnssecMonitor {
|
|
4
|
+
domainName: string;
|
|
5
|
+
resolvers: Array<string>;
|
|
6
|
+
checkNameserverConsistency: boolean;
|
|
7
|
+
signatureExpiryWarningDays: number;
|
|
8
|
+
timeout: number;
|
|
9
|
+
retries: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class MonitorStepDnssecMonitorUtil {
|
|
13
|
+
public static getDefault(): MonitorStepDnssecMonitor {
|
|
14
|
+
return {
|
|
15
|
+
domainName: "",
|
|
16
|
+
resolvers: ["1.1.1.1", "8.8.8.8", "9.9.9.9"],
|
|
17
|
+
checkNameserverConsistency: true,
|
|
18
|
+
signatureExpiryWarningDays: 7,
|
|
19
|
+
timeout: 10000,
|
|
20
|
+
retries: 3,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public static fromJSON(json: JSONObject): MonitorStepDnssecMonitor {
|
|
25
|
+
const defaults: MonitorStepDnssecMonitor =
|
|
26
|
+
MonitorStepDnssecMonitorUtil.getDefault();
|
|
27
|
+
|
|
28
|
+
const resolvers: Array<string> = Array.isArray(json["resolvers"])
|
|
29
|
+
? (json["resolvers"] as Array<string>).filter((value: unknown) => {
|
|
30
|
+
return typeof value === "string" && value.length > 0;
|
|
31
|
+
})
|
|
32
|
+
: defaults.resolvers;
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
domainName: (json["domainName"] as string) || "",
|
|
36
|
+
resolvers: resolvers.length > 0 ? resolvers : defaults.resolvers,
|
|
37
|
+
checkNameserverConsistency:
|
|
38
|
+
typeof json["checkNameserverConsistency"] === "boolean"
|
|
39
|
+
? (json["checkNameserverConsistency"] as boolean)
|
|
40
|
+
: defaults.checkNameserverConsistency,
|
|
41
|
+
signatureExpiryWarningDays:
|
|
42
|
+
(json["signatureExpiryWarningDays"] as number) ||
|
|
43
|
+
defaults.signatureExpiryWarningDays,
|
|
44
|
+
timeout: (json["timeout"] as number) || defaults.timeout,
|
|
45
|
+
retries: (json["retries"] as number) || defaults.retries,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public static toJSON(monitor: MonitorStepDnssecMonitor): JSONObject {
|
|
50
|
+
return {
|
|
51
|
+
domainName: monitor.domainName,
|
|
52
|
+
resolvers: monitor.resolvers,
|
|
53
|
+
checkNameserverConsistency: monitor.checkNameserverConsistency,
|
|
54
|
+
signatureExpiryWarningDays: monitor.signatureExpiryWarningDays,
|
|
55
|
+
timeout: monitor.timeout,
|
|
56
|
+
retries: monitor.retries,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -32,6 +32,9 @@ enum MonitorType {
|
|
|
32
32
|
// DNS monitoring
|
|
33
33
|
DNS = "DNS",
|
|
34
34
|
|
|
35
|
+
// DNSSEC validation monitoring
|
|
36
|
+
DNSSEC = "DNSSEC",
|
|
37
|
+
|
|
35
38
|
// Domain registration monitoring
|
|
36
39
|
Domain = "Domain",
|
|
37
40
|
|
|
@@ -64,12 +67,15 @@ export class MonitorTypeHelper {
|
|
|
64
67
|
MonitorType.Ping,
|
|
65
68
|
MonitorType.IP,
|
|
66
69
|
MonitorType.Port,
|
|
67
|
-
MonitorType.DNS,
|
|
68
70
|
MonitorType.SSLCertificate,
|
|
69
71
|
MonitorType.Domain,
|
|
70
72
|
MonitorType.ExternalStatusPage,
|
|
71
73
|
],
|
|
72
74
|
},
|
|
75
|
+
{
|
|
76
|
+
label: "DNS Monitoring",
|
|
77
|
+
monitorTypes: [MonitorType.DNS, MonitorType.DNSSEC],
|
|
78
|
+
},
|
|
73
79
|
{
|
|
74
80
|
label: "Synthetic Monitoring",
|
|
75
81
|
monitorTypes: [
|
|
@@ -273,6 +279,13 @@ export class MonitorTypeHelper {
|
|
|
273
279
|
"This monitor type lets you monitor DNS resolution for your domains, verify record values, and check DNSSEC validity.",
|
|
274
280
|
icon: IconProp.GlobeAlt,
|
|
275
281
|
},
|
|
282
|
+
{
|
|
283
|
+
monitorType: MonitorType.DNSSEC,
|
|
284
|
+
title: "DNSSEC",
|
|
285
|
+
description:
|
|
286
|
+
"This monitor type performs full DNSSEC validation — DNSKEY, DS at the parent zone, RRSIG validity windows, AD-flag/SERVFAIL behavior across public resolvers, and primary/secondary nameserver consistency.",
|
|
287
|
+
icon: IconProp.Key,
|
|
288
|
+
},
|
|
276
289
|
{
|
|
277
290
|
monitorType: MonitorType.Domain,
|
|
278
291
|
title: "Domain",
|
|
@@ -334,6 +347,7 @@ export class MonitorTypeHelper {
|
|
|
334
347
|
monitorType === MonitorType.CustomJavaScriptCode ||
|
|
335
348
|
monitorType === MonitorType.SNMP ||
|
|
336
349
|
monitorType === MonitorType.DNS ||
|
|
350
|
+
monitorType === MonitorType.DNSSEC ||
|
|
337
351
|
monitorType === MonitorType.Domain ||
|
|
338
352
|
monitorType === MonitorType.ExternalStatusPage;
|
|
339
353
|
return isProbeableMonitor;
|
|
@@ -359,6 +373,7 @@ export class MonitorTypeHelper {
|
|
|
359
373
|
MonitorType.Profiles,
|
|
360
374
|
MonitorType.SNMP,
|
|
361
375
|
MonitorType.DNS,
|
|
376
|
+
MonitorType.DNSSEC,
|
|
362
377
|
MonitorType.Domain,
|
|
363
378
|
MonitorType.ExternalStatusPage,
|
|
364
379
|
MonitorType.Kubernetes,
|
|
@@ -397,6 +412,7 @@ export class MonitorTypeHelper {
|
|
|
397
412
|
monitorType === MonitorType.CustomJavaScriptCode ||
|
|
398
413
|
monitorType === MonitorType.SNMP ||
|
|
399
414
|
monitorType === MonitorType.DNS ||
|
|
415
|
+
monitorType === MonitorType.DNSSEC ||
|
|
400
416
|
monitorType === MonitorType.Domain ||
|
|
401
417
|
monitorType === MonitorType.ExternalStatusPage
|
|
402
418
|
) {
|
|
@@ -9,6 +9,7 @@ import SyntheticMonitorResponse from "../Monitor/SyntheticMonitors/SyntheticMoni
|
|
|
9
9
|
import SnmpMonitorResponse from "../Monitor/SnmpMonitor/SnmpMonitorResponse";
|
|
10
10
|
import DnsMonitorResponse from "../Monitor/DnsMonitor/DnsMonitorResponse";
|
|
11
11
|
import DomainMonitorResponse from "../Monitor/DomainMonitor/DomainMonitorResponse";
|
|
12
|
+
import DnssecMonitorResponse from "../Monitor/DnssecMonitor/DnssecMonitorResponse";
|
|
12
13
|
import ExternalStatusPageMonitorResponse from "../Monitor/ExternalStatusPageMonitor/ExternalStatusPageMonitorResponse";
|
|
13
14
|
import MonitorEvaluationSummary from "../Monitor/MonitorEvaluationSummary";
|
|
14
15
|
import ObjectID from "../ObjectID";
|
|
@@ -35,6 +36,7 @@ export default interface ProbeMonitorResponse {
|
|
|
35
36
|
snmpResponse?: SnmpMonitorResponse | undefined;
|
|
36
37
|
dnsResponse?: DnsMonitorResponse | undefined;
|
|
37
38
|
domainResponse?: DomainMonitorResponse | undefined;
|
|
39
|
+
dnssecResponse?: DnssecMonitorResponse | undefined;
|
|
38
40
|
externalStatusPageResponse?: ExternalStatusPageMonitorResponse | undefined;
|
|
39
41
|
monitoredAt: Date;
|
|
40
42
|
isTimeout?: boolean | undefined;
|
|
@@ -405,6 +405,57 @@ export default class TemplateVariablesCatalog {
|
|
|
405
405
|
],
|
|
406
406
|
};
|
|
407
407
|
|
|
408
|
+
case MonitorType.DNSSEC:
|
|
409
|
+
return {
|
|
410
|
+
title: "DNSSEC",
|
|
411
|
+
variables: [
|
|
412
|
+
{
|
|
413
|
+
key: "isOnline",
|
|
414
|
+
description: "True if the DNSSEC check completed.",
|
|
415
|
+
},
|
|
416
|
+
{ key: "domainName", description: "Zone queried." },
|
|
417
|
+
{
|
|
418
|
+
key: "isZoneSigned",
|
|
419
|
+
description: "True if any DNSKEY records exist for the zone.",
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
key: "isParentDsPresent",
|
|
423
|
+
description: "True if DS records exist at the parent zone.",
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
key: "isChainValid",
|
|
427
|
+
description:
|
|
428
|
+
"True if DNSKEY, DS, RRSIG, and resolver AD-flag all check out.",
|
|
429
|
+
},
|
|
430
|
+
{
|
|
431
|
+
key: "resolverConsensusAd",
|
|
432
|
+
description:
|
|
433
|
+
"True if every configured resolver returned the AD flag.",
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
key: "isNameserverConsistent",
|
|
437
|
+
description:
|
|
438
|
+
"True if every authoritative nameserver returned the same SOA serial.",
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
key: "earliestSignatureExpiration",
|
|
442
|
+
description: "Earliest RRSIG expiration timestamp (ISO).",
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
key: "daysUntilSignatureExpiry",
|
|
446
|
+
description: "Days until the earliest RRSIG expires.",
|
|
447
|
+
},
|
|
448
|
+
{ key: "dnskeyCount", description: "Number of DNSKEY records." },
|
|
449
|
+
{
|
|
450
|
+
key: "dsRecordCount",
|
|
451
|
+
description: "Number of DS records at the parent.",
|
|
452
|
+
},
|
|
453
|
+
{ key: "rrsigCount", description: "Number of RRSIG records seen." },
|
|
454
|
+
{ key: "responseTimeInMs", description: "Total check duration." },
|
|
455
|
+
{ key: "failureCause", description: "Failure reason." },
|
|
456
|
+
],
|
|
457
|
+
};
|
|
458
|
+
|
|
408
459
|
case MonitorType.ExternalStatusPage:
|
|
409
460
|
return {
|
|
410
461
|
title: "External Status Page",
|
|
@@ -171,6 +171,7 @@ class MonitorMetricTypeUtil {
|
|
|
171
171
|
monitorType === MonitorType.Port ||
|
|
172
172
|
monitorType === MonitorType.SNMP ||
|
|
173
173
|
monitorType === MonitorType.DNS ||
|
|
174
|
+
monitorType === MonitorType.DNSSEC ||
|
|
174
175
|
monitorType === MonitorType.Domain ||
|
|
175
176
|
monitorType === MonitorType.ExternalStatusPage
|
|
176
177
|
) {
|