diff --git a/.script/tests/KqlvalidationsTests/CustomTables/PQCEngine_CL.json b/.script/tests/KqlvalidationsTests/CustomTables/PQCEngine_CL.json new file mode 100644 index 00000000000..31fa868cdc9 --- /dev/null +++ b/.script/tests/KqlvalidationsTests/CustomTables/PQCEngine_CL.json @@ -0,0 +1,92 @@ +{ "Name": "PQCEngine_CL", +"Properties":[ + { + "Name": "TenantId", + "Type": "String" + }, + { + "Name": "SourceSystem", + "Type": "String" + }, + { + "Name": "MG", + "Type": "String" + }, + { + "Name": "ManagementGroupName", + "Type": "String" + }, + { + "Name": "TimeGenerated", + "Type": "DateTime" + }, + { + "Name": "Computer", + "Type": "String" + }, + { + "Name": "RawData", + "Type": "String" + }, + { + "Name": "InstanceId", + "Type": "String" + }, + { + "Name": "Hostname", + "Type": "String" + }, + { + "Name": "EventType", + "Type": "String" + }, + { + "Name": "Algorithm", + "Type": "String" + }, + { + "Name": "Operation", + "Type": "String" + }, + { + "Name": "PeerGroups", + "Type": "String" + }, + { + "Name": "NegotiatedGroup", + "Type": "String" + }, + { + "Name": "CipherSuite", + "Type": "String" + }, + { + "Name": "ClientClass", + "Type": "String" + }, + { + "Name": "PQCOffered", + "Type": "Int32" + }, + { + "Name": "PQCNegotiated", + "Type": "Int32" + }, + { + "Name": "Success", + "Type": "Int32" + }, + { + "Name": "Detail", + "Type": "String" + }, + { + "Name": "Metadata", + "Type": "String" + }, + { + "Name": "_ResourceId", + "Type": "String" + } +] +} diff --git a/.script/tests/detectionTemplateSchemaValidation/ValidConnectorIds.json b/.script/tests/detectionTemplateSchemaValidation/ValidConnectorIds.json index 880727c1fef..ddc9ad08ae5 100644 --- a/.script/tests/detectionTemplateSchemaValidation/ValidConnectorIds.json +++ b/.script/tests/detectionTemplateSchemaValidation/ValidConnectorIds.json @@ -370,5 +370,7 @@ "RedRaysSAPSecurityFindings", "NetcraftIntegrationGatewayDefinition", "HoneyForge", - "QCryptonPQCScanner" + "QCryptonPQCScanner", + "QCryptonPQCEngine", + "QCryptonPQCVPNOverlay" ] diff --git a/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Analytic_Rules/HighClassicalClientRate.yaml b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Analytic_Rules/HighClassicalClientRate.yaml new file mode 100644 index 00000000000..b51df13c98d --- /dev/null +++ b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Analytic_Rules/HighClassicalClientRate.yaml @@ -0,0 +1,37 @@ +id: ad4e5f6a-7b8c-4d9e-0f1a-2b3c4d5e6f7a +name: High percentage of classical-only clients on PQC Engine +description: | + More than 50% of TLS handshakes on a PQC Engine instance in the last 24 hours were from + classical-only clients that did not offer any post-quantum key exchange groups. These + connections are not protected against harvest-now-decrypt-later attacks. Consider requiring + PQC-capable TLS libraries or upgrading connecting services to OpenSSL 3.5+ or BoringSSL with + ML-KEM support. +severity: Informational +requiredDataConnectors: + - connectorId: QCryptonPQCEngine + dataTypes: + - PQCEngine_CL +queryFrequency: P1D +queryPeriod: P1D +triggerOperator: gt +triggerThreshold: 0 +tactics: + - Discovery +relevantTechniques: + - T1082 +query: | + PQCEngine_CL + | where TimeGenerated > ago(1d) + | where EventType == "handshake" + | summarize Total = count(), Classical = countif(ClientClass in ("classical", "legacy")) by Hostname, InstanceId + | extend ClassicalPct = round(100.0 * Classical / Total, 1) + | where ClassicalPct > 50 + | project Hostname, InstanceId, Total, Classical, ClassicalPct + | order by ClassicalPct desc +entityMappings: + - entityType: Host + fieldMappings: + - identifier: HostName + columnName: Hostname +version: 1.0.0 +kind: Scheduled diff --git a/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Analytic_Rules/KEMOperationFailureSpike.yaml b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Analytic_Rules/KEMOperationFailureSpike.yaml new file mode 100644 index 00000000000..ba17617ee02 --- /dev/null +++ b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Analytic_Rules/KEMOperationFailureSpike.yaml @@ -0,0 +1,36 @@ +id: be5f6a7b-8c9d-4e0f-1a2b-3c4d5e6f7a8b +name: KEM operation failure spike on PQC Engine +description: | + An elevated rate of KEM (Key Encapsulation Mechanism) operation failures was detected on a + PQC Engine instance. This may indicate incompatible ML-KEM implementations between client and + server, corrupted key material, memory constraints on the F5 BIG-IP, or a misconfigured PQC + Engine provider. Investigate the failing algorithm and operation type. +severity: Medium +requiredDataConnectors: + - connectorId: QCryptonPQCEngine + dataTypes: + - PQCEngine_CL +queryFrequency: PT1H +queryPeriod: PT1H +triggerOperator: gt +triggerThreshold: 5 +tactics: + - Impact +relevantTechniques: + - T1499 +query: | + PQCEngine_CL + | where TimeGenerated > ago(1h) + | where EventType == "kem_op" + | where Success == 0 + | summarize FailureCount = count(), Algorithms = make_set(Algorithm, 5), Operations = make_set(Operation, 5) by Hostname, InstanceId + | where FailureCount > 5 + | project Hostname, InstanceId, FailureCount, Algorithms, Operations + | order by FailureCount desc +entityMappings: + - entityType: Host + fieldMappings: + - identifier: HostName + columnName: Hostname +version: 1.0.0 +kind: Scheduled diff --git a/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Analytic_Rules/PQCDowngradeOnEngine.yaml b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Analytic_Rules/PQCDowngradeOnEngine.yaml new file mode 100644 index 00000000000..702b22716f0 --- /dev/null +++ b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Analytic_Rules/PQCDowngradeOnEngine.yaml @@ -0,0 +1,36 @@ +id: 9c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f +name: PQC downgrade on engine -- client offered hybrid but classical negotiated +description: | + A TLS handshake completed where the client offered post-quantum hybrid key exchange groups but + the F5 BIG-IP negotiated a classical-only group. This may indicate PQC Engine misconfiguration, + an intermediate device stripping PQC groups from the ClientHello, or the engine running in + monitor mode rather than enforce mode. Investigate the negotiated vs offered groups. +severity: High +requiredDataConnectors: + - connectorId: QCryptonPQCEngine + dataTypes: + - PQCEngine_CL +queryFrequency: PT1H +queryPeriod: PT1H +triggerOperator: gt +triggerThreshold: 0 +tactics: + - InitialAccess + - Collection +relevantTechniques: + - T1557 + - T1040 +query: | + PQCEngine_CL + | where TimeGenerated > ago(1h) + | where EventType == "handshake" + | where PQCOffered == 1 and PQCNegotiated == 0 + | project TimeGenerated, Hostname, InstanceId, NegotiatedGroup, PeerGroups, CipherSuite, ClientClass, Detail + | order by TimeGenerated desc +entityMappings: + - entityType: Host + fieldMappings: + - identifier: HostName + columnName: Hostname +version: 1.0.0 +kind: Scheduled diff --git a/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Analytic_Rules/PolicyBlockDetected.yaml b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Analytic_Rules/PolicyBlockDetected.yaml new file mode 100644 index 00000000000..75936376246 --- /dev/null +++ b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Analytic_Rules/PolicyBlockDetected.yaml @@ -0,0 +1,33 @@ +id: 7a1b2c3d-4e5f-4a6b-7c8d-9e0f1a2b3c4d +name: PQC Engine policy blocked a TLS handshake +description: | + The PQC Engine crypto policy enforcement blocked a TLS handshake that did not meet minimum + requirements. This may indicate a client attempting to connect with banned cipher suites, + blocked key exchange groups, or TLS versions below the policy minimum. Review the blocked + algorithm and client to determine if policy adjustment or client upgrade is needed. +severity: High +requiredDataConnectors: + - connectorId: QCryptonPQCEngine + dataTypes: + - PQCEngine_CL +queryFrequency: PT1H +queryPeriod: PT1H +triggerOperator: gt +triggerThreshold: 0 +tactics: + - InitialAccess +relevantTechniques: + - T1190 +query: | + PQCEngine_CL + | where TimeGenerated > ago(1h) + | where EventType == "policy_block" + | project TimeGenerated, Hostname, InstanceId, Algorithm, NegotiatedGroup, CipherSuite, ClientClass, Detail + | order by TimeGenerated desc +entityMappings: + - entityType: Host + fieldMappings: + - identifier: HostName + columnName: Hostname +version: 1.0.0 +kind: Scheduled diff --git a/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Analytic_Rules/PolicyUpgradeActivity.yaml b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Analytic_Rules/PolicyUpgradeActivity.yaml new file mode 100644 index 00000000000..16dc57d9297 --- /dev/null +++ b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Analytic_Rules/PolicyUpgradeActivity.yaml @@ -0,0 +1,34 @@ +id: cf6a7b8c-9d0e-4f1a-2b3c-4d5e6f7a8b9c +name: PQC Engine policy upgraded cipher selection +description: | + The PQC Engine policy engine upgraded the cipher selection for one or more TLS handshakes. + This occurs when the engine is in enforce mode and the initial negotiation would have used a + weaker algorithm than the policy allows. The engine intervened to select a stronger (typically + PQ-hybrid) algorithm. This is an expected and positive signal when enforcement is enabled. +severity: Informational +requiredDataConnectors: + - connectorId: QCryptonPQCEngine + dataTypes: + - PQCEngine_CL +queryFrequency: P1D +queryPeriod: P1D +triggerOperator: gt +triggerThreshold: 0 +tactics: + - DefenseEvasion +relevantTechniques: + - T1600 +query: | + PQCEngine_CL + | where TimeGenerated > ago(1d) + | where EventType == "policy_upgrade" + | summarize UpgradeCount = count(), Algorithms = make_set(Algorithm, 10) by Hostname, InstanceId + | project Hostname, InstanceId, UpgradeCount, Algorithms + | order by UpgradeCount desc +entityMappings: + - entityType: Host + fieldMappings: + - identifier: HostName + columnName: Hostname +version: 1.0.0 +kind: Scheduled diff --git a/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Analytic_Rules/VulnerableAlgorithmDetected.yaml b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Analytic_Rules/VulnerableAlgorithmDetected.yaml new file mode 100644 index 00000000000..b5169b4177a --- /dev/null +++ b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Analytic_Rules/VulnerableAlgorithmDetected.yaml @@ -0,0 +1,34 @@ +id: 8b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e +name: Vulnerable classical algorithm detected in TLS negotiation +description: | + The PQC Engine vulnerability database flagged a quantum-vulnerable algorithm during a TLS + handshake or cryptographic operation on F5 BIG-IP. Algorithms such as RSA-2048, ECDSA P-256, + or Ed25519 are vulnerable to Shor's algorithm on a cryptographically relevant quantum computer. + Migrate to PQ-hybrid algorithms (X25519+ML-KEM-768) to protect against harvest-now-decrypt-later + attacks. +severity: High +requiredDataConnectors: + - connectorId: QCryptonPQCEngine + dataTypes: + - PQCEngine_CL +queryFrequency: PT1H +queryPeriod: PT1H +triggerOperator: gt +triggerThreshold: 0 +tactics: + - Collection +relevantTechniques: + - T1040 +query: | + PQCEngine_CL + | where TimeGenerated > ago(1h) + | where EventType == "vuln_detected" + | project TimeGenerated, Hostname, InstanceId, Algorithm, Operation, ClientClass, PQCOffered, Detail + | order by TimeGenerated desc +entityMappings: + - entityType: Host + fieldMappings: + - identifier: HostName + columnName: Hostname +version: 1.0.0 +kind: Scheduled diff --git a/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Data/Solution_QCryptonPQCEngine.json b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Data/Solution_QCryptonPQCEngine.json new file mode 100644 index 00000000000..b78126101e4 --- /dev/null +++ b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Data/Solution_QCryptonPQCEngine.json @@ -0,0 +1,24 @@ +{ + "Name": "QCryptonPQCEngine", + "Author": "QCrypton, Inc.", + "Logo": "", + "Description": "Runtime cryptographic telemetry from QCrypton PQC Engine, an OpenSSL 3.x provider for F5 BIG-IP that adds ML-KEM-768/1024 and ML-DSA-65/87 post-quantum algorithms. Ingests handshake negotiations, KEM operations, policy enforcement events, vulnerable algorithm detections, and client classification into the **PQCEngine_CL** table via the Codeless Connector Framework (RestApiPoller). Ships with 1 data connector, 6 analytic rules, workbook, and Teams-notification playbook.\n\n **Underlying Microsoft Technologies used:** \n\n This solution takes a dependency on the following technologies, and some of these dependencies either may be in [Preview](https://azure.microsoft.com/support/legal/preview-supplemental-terms/) state or might result in additional ingestion or operational costs:\n\n• [Microsoft Sentinel Codeless Connector Framework](https://aka.ms/Sentinel-CCP_Platform)", + "Data Connectors": [ + "Data_Connectors/QCryptonPQCEngine_CCF/QCryptonPQCEngine_ConnectorDefinition.json" + ], + "Workbooks": ["Workbooks/QCryptonPQCEnginePosture.json"], + "Analytic Rules": [ + "Analytic_Rules/PolicyBlockDetected.yaml", + "Analytic_Rules/VulnerableAlgorithmDetected.yaml", + "Analytic_Rules/PQCDowngradeOnEngine.yaml", + "Analytic_Rules/HighClassicalClientRate.yaml", + "Analytic_Rules/KEMOperationFailureSpike.yaml", + "Analytic_Rules/PolicyUpgradeActivity.yaml" + ], + "Playbooks": ["Playbooks/QCryptonPQCEngine-Notify/azuredeploy.json"], + "Metadata": "SolutionMetadata.json", + "BasePath": "Solutions/QCryptonPQCEngine", + "Version": "1.0.0", + "TemplateSpec": true, + "Is1PConnector": false +} diff --git a/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Data_Connectors/QCryptonPQCEngine_CCF/PQCEngine_Table.json b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Data_Connectors/QCryptonPQCEngine_CCF/PQCEngine_Table.json new file mode 100644 index 00000000000..012132830ff --- /dev/null +++ b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Data_Connectors/QCryptonPQCEngine_CCF/PQCEngine_Table.json @@ -0,0 +1,89 @@ +{ + "name": "PQCEngine_CL", + "type": "Microsoft.OperationalInsights/workspaces/tables", + "apiVersion": "2025-02-01", + "properties": { + "retentionInDays": 90, + "schema": { + "name": "PQCEngine_CL", + "description": "Runtime cryptographic telemetry from QCrypton PQC Engine instances deployed on F5 BIG-IP. Contains handshake negotiations, KEM/signature operations, policy enforcement events, vulnerable algorithm detections, and client classification.", + "columns": [ + { + "name": "TimeGenerated", + "type": "datetime", + "description": "Timestamp when the event was generated by the PQC Engine." + }, + { + "name": "InstanceId", + "type": "string", + "description": "Unique identifier for the PQC Engine instance." + }, + { + "name": "Hostname", + "type": "string", + "description": "F5 BIG-IP hostname." + }, + { + "name": "EventType", + "type": "string", + "description": "Event type: handshake, kem_op, sig_op, policy_block, policy_upgrade, vuln_detected, kex_complete." + }, + { + "name": "Algorithm", + "type": "string", + "description": "Algorithm name e.g. mlkem768, mldsa65, RSA-2048." + }, + { + "name": "Operation", + "type": "string", + "description": "Cryptographic operation: encapsulate, decapsulate, sign, verify." + }, + { + "name": "PeerGroups", + "type": "string", + "description": "Comma-separated client offered groups." + }, + { + "name": "NegotiatedGroup", + "type": "string", + "description": "Selected key exchange group." + }, + { + "name": "CipherSuite", + "type": "string", + "description": "TLS cipher suite." + }, + { + "name": "ClientClass", + "type": "string", + "description": "Client classification: pqc_native, pqc_hybrid, classical, legacy." + }, + { + "name": "PQCOffered", + "type": "int", + "description": "Client offered PQC groups (1=yes, 0=no)." + }, + { + "name": "PQCNegotiated", + "type": "int", + "description": "PQC was negotiated (1=yes, 0=no)." + }, + { + "name": "Success", + "type": "int", + "description": "Operation success (1=ok, 0=failed)." + }, + { + "name": "Detail", + "type": "string", + "description": "Free-form reason/context." + }, + { + "name": "Metadata", + "type": "string", + "description": "Additional JSON metadata about the event." + } + ] + } + } +} diff --git a/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Data_Connectors/QCryptonPQCEngine_CCF/QCryptonPQCEngine_ConnectorDefinition.json b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Data_Connectors/QCryptonPQCEngine_CCF/QCryptonPQCEngine_ConnectorDefinition.json new file mode 100644 index 00000000000..9f0ccf58139 --- /dev/null +++ b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Data_Connectors/QCryptonPQCEngine_CCF/QCryptonPQCEngine_ConnectorDefinition.json @@ -0,0 +1,130 @@ +{ + "name": "QCryptonPQCEngineCCPDefinition", + "apiVersion": "2025-03-01", + "type": "Microsoft.SecurityInsights/dataConnectorDefinitions", + "location": "{{location}}", + "kind": "Customizable", + "properties": { + "connectorUiConfig": { + "id": "QCryptonPQCEngineCCPDefinition", + "title": "QCrypton PQC Engine", + "publisher": "QCrypton, Inc.", + "descriptionMarkdown": "The QCrypton PQC Engine data connector ingests runtime cryptographic telemetry from PQC Engine instances deployed on F5 BIG-IP into Microsoft Sentinel through the QCrypton API. PQC Engine is an OpenSSL 3.x provider that adds ML-KEM-768/1024 and ML-DSA-65/87 post-quantum algorithms. This connector streams handshake negotiations, KEM operations, policy enforcement events, and vulnerable algorithm detections into the PQCEngine_CL table.", + "graphQueries": [ + { + "metricName": "Total PQC Engine events received", + "legend": "PQCEngine_CL", + "baseQuery": "PQCEngine_CL" + } + ], + "sampleQueries": [ + { + "description": "PQC adoption rate across handshakes in the last 24h", + "query": "PQCEngine_CL\n| where TimeGenerated > ago(24h)\n| where EventType == 'handshake'\n| summarize Total = count(), PQC = countif(PQCNegotiated == 1)\n| extend PQCPct = round(100.0 * PQC / Total, 1)\n| project Total, PQC, PQCPct" + }, + { + "description": "Policy block events in the last 24h", + "query": "PQCEngine_CL\n| where TimeGenerated > ago(24h)\n| where EventType == 'policy_block'\n| project TimeGenerated, Hostname, InstanceId, Algorithm, NegotiatedGroup, CipherSuite, ClientClass, Detail\n| order by TimeGenerated desc" + }, + { + "description": "Vulnerable algorithm detections", + "query": "PQCEngine_CL\n| where TimeGenerated > ago(24h)\n| where EventType == 'vuln_detected'\n| summarize Count = count() by Algorithm, Detail\n| order by Count desc" + } + ], + "dataTypes": [ + { + "name": "PQCEngine_CL", + "lastDataReceivedQuery": "PQCEngine_CL\n| summarize Time = max(TimeGenerated)\n| where isnotempty(Time)" + } + ], + "connectivityCriteria": [ + { + "type": "HasDataConnectors" + } + ], + "availability": { + "isPreview": false, + "status": 1 + }, + "permissions": { + "resourceProvider": [ + { + "provider": "Microsoft.OperationalInsights/workspaces", + "permissionsDisplayText": "Read and Write permissions are required.", + "providerDisplayName": "Workspace", + "scope": "Workspace", + "requiredPermissions": { + "write": true, + "read": true, + "delete": true, + "action": false + } + } + ], + "customs": [ + { + "name": "QCrypton API Key", + "description": "A QCrypton PQC Engine API key is required. Obtain one from the [QCrypton Portal](https://portal.qcrypton.com)." + } + ] + }, + "instructionSteps": [ + { + "title": "Connect QCrypton PQC Engine to Microsoft Sentinel", + "instructions": [ + { + "type": "Markdown", + "parameters": { + "content": "This connector polls the QCrypton PQC Engine API to retrieve runtime cryptographic telemetry and ingest it into the **PQCEngine_CL** table in your Log Analytics workspace." + } + }, + { + "type": "Markdown", + "parameters": { + "content": "#### 1. API Key\nObtain your QCrypton API key from the [QCrypton Portal](https://portal.qcrypton.com). Navigate to **Settings > API Keys** and generate a key with read access to engine telemetry." + } + }, + { + "type": "Markdown", + "parameters": { + "content": "#### 2. API Server URL\nEnter the base URL of your QCrypton API server. The default is `https://api.qcrypton.com`. If you use a dedicated or regional instance, enter the URL provided by QCrypton." + } + }, + { + "type": "Textbox", + "parameters": { + "label": "QCrypton API Key", + "placeholder": "Enter your QCrypton API key", + "type": "password", + "name": "apiKey", + "validations": { + "required": true + } + } + }, + { + "type": "Textbox", + "parameters": { + "label": "QCrypton API Server URL", + "placeholder": "https://api.qcrypton.com", + "type": "text", + "name": "apiServerUrl", + "description": "Enter the QCrypton API base URL. Do not include a trailing slash or path.", + "validations": { + "required": true + } + } + }, + { + "type": "ConnectionToggleButton", + "parameters": { + "connectLabel": "Connect", + "name": "toggle" + } + } + ] + } + ] + } + } +} diff --git a/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Data_Connectors/QCryptonPQCEngine_CCF/QCryptonPQCEngine_DCR.json b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Data_Connectors/QCryptonPQCEngine_CCF/QCryptonPQCEngine_DCR.json new file mode 100644 index 00000000000..0e70a965e7c --- /dev/null +++ b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Data_Connectors/QCryptonPQCEngine_CCF/QCryptonPQCEngine_DCR.json @@ -0,0 +1,95 @@ +{ + "name": "QCryptonPQCEngineDCR", + "apiVersion": "2023-03-11", + "type": "Microsoft.Insights/dataCollectionRules", + "location": "{{location}}", + "properties": { + "dataCollectionEndpointId": "{{dataCollectionEndpointId}}", + "streamDeclarations": { + "Custom-PQCEngine_CL": { + "columns": [ + { + "name": "TimeGenerated", + "type": "datetime" + }, + { + "name": "InstanceId", + "type": "string" + }, + { + "name": "Hostname", + "type": "string" + }, + { + "name": "EventType", + "type": "string" + }, + { + "name": "Algorithm", + "type": "string" + }, + { + "name": "Operation", + "type": "string" + }, + { + "name": "PeerGroups", + "type": "string" + }, + { + "name": "NegotiatedGroup", + "type": "string" + }, + { + "name": "CipherSuite", + "type": "string" + }, + { + "name": "ClientClass", + "type": "string" + }, + { + "name": "PQCOffered", + "type": "int" + }, + { + "name": "PQCNegotiated", + "type": "int" + }, + { + "name": "Success", + "type": "int" + }, + { + "name": "Detail", + "type": "string" + }, + { + "name": "Metadata", + "type": "string" + } + ] + } + }, + "destinations": { + "logAnalytics": [ + { + "workspaceResourceId": "{{workspaceResourceId}}", + "name": "clv2ws1" + } + ] + }, + "dataFlows": [ + { + "streams": [ + "Custom-PQCEngine_CL" + ], + "destinations": [ + "clv2ws1" + ], + "outputStream": "Custom-PQCEngine_CL", + "transformKql": "source | extend TimeGenerated = iff(isnull(TimeGenerated), now(), TimeGenerated) | project TimeGenerated, InstanceId, Hostname, EventType, Algorithm, Operation, PeerGroups, NegotiatedGroup, CipherSuite, ClientClass, PQCOffered, PQCNegotiated, Success, Detail, Metadata" + } + ] + } +} diff --git a/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Data_Connectors/QCryptonPQCEngine_CCF/QCryptonPQCEngine_PollingConfig.json b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Data_Connectors/QCryptonPQCEngine_CCF/QCryptonPQCEngine_PollingConfig.json new file mode 100644 index 00000000000..71d748f3d40 --- /dev/null +++ b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Data_Connectors/QCryptonPQCEngine_CCF/QCryptonPQCEngine_PollingConfig.json @@ -0,0 +1,51 @@ +{ + "type": "Microsoft.SecurityInsights/dataConnectors", + "apiVersion": "2025-03-01", + "name": "QCryptonPQCEngineCCP", + "location": "{{location}}", + "kind": "RestApiPoller", + "properties": { + "auth": { + "type": "APIKey", + "ApiKey": "[[parameters('apiKey')]", + "ApiKeyName": "X-API-Key", + "ApiKeyIdentifier": "", + "IsApiKeyInPostPayload": false + }, + "request": { + "apiEndpoint": "[[concat(parameters('apiServerUrl'),'/v1/engine/telemetry')]", + "httpMethod": "GET", + "rateLimitQPS": 2, + "queryWindowInMin": 60, + "queryTimeFormat": "yyyy-MM-ddTHH:mm:ssZ", + "retryCount": 3, + "timeoutInSeconds": 120, + "headers": { + "Accept": "application/json", + "User-Agent": "MicrosoftSentinel-QCryptonPQCEngineCCP" + }, + "queryParameters": { + "scanDateAfter": "{_QueryWindowStartTime}", + "scanDateBefore": "{_QueryWindowEndTime}" + } + }, + "response": { + "eventsJsonPaths": [ + "$.events" + ], + "format": "json" + }, + "paging": { + "pagingType": "NextPageToken", + "nextPageTokenJsonPath": "$.nextPageToken", + "nextPageParaName": "pageToken" + }, + "connectorDefinitionName": "QCryptonPQCEngineCCPDefinition", + "dataType": "PQCEngine_CL", + "dcrConfig": { + "streamName": "Custom-PQCEngine_CL", + "dataCollectionEndpoint": "{{dataCollectionEndpoint}}", + "dataCollectionRuleImmutableId": "{{dataCollectionRuleImmutableId}}" + } + } +} diff --git a/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Package/3.0.0.zip b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Package/3.0.0.zip new file mode 100644 index 00000000000..c7ba406e4b4 Binary files /dev/null and b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Package/3.0.0.zip differ diff --git a/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Package/createUiDefinition.json b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Package/createUiDefinition.json new file mode 100644 index 00000000000..a408b74aba2 --- /dev/null +++ b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Package/createUiDefinition.json @@ -0,0 +1,253 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#", + "handler": "Microsoft.Azure.CreateUIDef", + "version": "0.1.2-preview", + "parameters": { + "config": { + "isWizard": false, + "basics": { + "description": "\n\n**Note:** Please refer to the following before installing the solution: \n\n• Review the solution [Release Notes](https://github.com/Azure/Azure-Sentinel/tree/master/Solutions/QCryptonPQCEngine/ReleaseNotes.md)\n\n • There may be [known issues](https://aka.ms/sentinelsolutionsknownissues) pertaining to this Solution, please refer to them before installing.\n\nRuntime cryptographic telemetry from QCrypton PQC Engine, an OpenSSL 3.x provider for F5 BIG-IP that adds ML-KEM-768/1024 and ML-DSA-65/87 post-quantum algorithms. Ingests handshake negotiations, KEM operations, policy enforcement events, vulnerable algorithm detections, and client classification via the Codeless Connector Framework (RestApiPoller). Ships with 1 data connector, 6 analytic rules, workbook, and Teams-notification playbook.\n\n**Data Connectors:** 1, **Workbooks:** 1, **Analytic Rules:** 6, **Playbooks:** 1\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)", + "subscription": { + "resourceProviders": [ + "Microsoft.OperationsManagement/solutions", + "Microsoft.OperationalInsights/workspaces/providers/alertRules", + "Microsoft.Insights/workbooks", + "Microsoft.Logic/workflows" + ] + }, + "location": { + "metadata": { + "hidden": "Hiding location, we get it from the log analytics workspace" + }, + "visible": false + }, + "resourceGroup": { + "allowExisting": true + } + } + }, + "basics": [ + { + "name": "getLAWorkspace", + "type": "Microsoft.Solutions.ArmApiControl", + "toolTip": "This filters by workspaces that exist in the Resource Group selected", + "condition": "[greater(length(resourceGroup().name),0)]", + "request": { + "method": "GET", + "path": "[concat(subscription().id,'/providers/Microsoft.OperationalInsights/workspaces?api-version=2020-08-01')]" + } + }, + { + "name": "workspace", + "type": "Microsoft.Common.DropDown", + "label": "Workspace", + "placeholder": "Select a workspace", + "toolTip": "This dropdown will list only workspace that exists in the Resource Group selected", + "constraints": { + "allowedValues": "[map(filter(basics('getLAWorkspace').value, (filter) => contains(toLower(filter.id), toLower(resourceGroup().name))), (item) => parse(concat('{\"label\":\"', item.name, '\",\"value\":\"', item.name, '\"}')))]", + "required": true + }, + "visible": true + } + ], + "steps": [ + { + "name": "dataconnectors", + "label": "Data Connectors", + "bladeTitle": "Data Connectors", + "elements": [ + { + "name": "dataconnectors1-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "This Solution installs the data connector for QCrypton PQC Engine. You can get QCrypton PQC Engine custom log data in your Microsoft Sentinel workspace. After installing the solution, configure and enable this data connector by following guidance in Manage solution view." + } + }, + { + "name": "dataconnectors-link1", + "type": "Microsoft.Common.TextBlock", + "options": { + "link": { + "label": "Learn more about connecting data sources", + "uri": "https://docs.microsoft.com/azure/sentinel/connect-data-sources" + } + } + } + ] + }, + { + "name": "workbooks", + "label": "Workbooks", + "subLabel": { + "preValidation": "Configure the workbooks", + "postValidation": "Done" + }, + "bladeTitle": "Workbooks", + "elements": [ + { + "name": "workbooks-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "This solution installs the QCrypton PQC Engine — Post-Quantum Cryptography Operations Dashboard workbook to help you gain insights into the telemetry collected in Microsoft Sentinel. Runtime PQC operations dashboard for PQC Engine instances on F5 BIG-IP. Visualises client classification, key exchange group distribution, policy enforcement events, vulnerable algorithm detections, and per-instance metrics from QCrypton PQC Engine telemetry. After installing the solution, start using the workbook in Manage solution view." + } + }, + { + "name": "workbooks-link", + "type": "Microsoft.Common.TextBlock", + "options": { + "link": { + "label": "Learn more", + "uri": "https://docs.microsoft.com/azure/sentinel/tutorial-monitor-your-data" + } + } + } + ] + }, + { + "name": "analytics", + "label": "Analytics", + "subLabel": { + "preValidation": "Configure the analytics", + "postValidation": "Done" + }, + "bladeTitle": "Analytics", + "elements": [ + { + "name": "analytics-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "This solution installs the following analytic rule templates. After installing the solution, create and enable analytic rules in Manage solution view." + } + }, + { + "name": "analytics-link", + "type": "Microsoft.Common.TextBlock", + "options": { + "link": { + "label": "Learn more", + "uri": "https://docs.microsoft.com/azure/sentinel/tutorial-detect-threats-custom?WT.mc_id=Portal-Microsoft_Azure_CreateUIDef" + } + } + }, + { + "name": "analytic1", + "type": "Microsoft.Common.Section", + "label": "PQC Engine policy blocked a TLS handshake", + "elements": [ + { + "name": "analytic1-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "The PQC Engine crypto policy enforcement blocked a TLS handshake that did not meet minimum requirements. This may indicate a client attempting to connect with banned cipher suites, blocked key exchange groups, or TLS versions below the policy minimum." + } + } + ] + }, + { + "name": "analytic2", + "type": "Microsoft.Common.Section", + "label": "Vulnerable classical algorithm detected in TLS negotiation", + "elements": [ + { + "name": "analytic2-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "The PQC Engine vulnerability database flagged a quantum-vulnerable algorithm during a TLS handshake or cryptographic operation on F5 BIG-IP. Algorithms such as RSA-2048, ECDSA P-256, or Ed25519 are vulnerable to Shor's algorithm on a cryptographically relevant quantum computer." + } + } + ] + }, + { + "name": "analytic3", + "type": "Microsoft.Common.Section", + "label": "PQC downgrade on engine — client offered hybrid but classical negotiated", + "elements": [ + { + "name": "analytic3-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "A TLS handshake completed where the client offered post-quantum hybrid key exchange groups but the F5 BIG-IP negotiated a classical-only group. This may indicate PQC Engine misconfiguration, an intermediate device stripping PQC groups from the ClientHello, or the engine running in monitor mode." + } + } + ] + }, + { + "name": "analytic4", + "type": "Microsoft.Common.Section", + "label": "High percentage of classical-only clients on PQC Engine", + "elements": [ + { + "name": "analytic4-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "More than 50% of TLS handshakes on a PQC Engine instance in the last 24 hours were from classical-only clients that did not offer any post-quantum key exchange groups. These connections are not protected against harvest-now-decrypt-later attacks." + } + } + ] + }, + { + "name": "analytic5", + "type": "Microsoft.Common.Section", + "label": "KEM operation failure spike on PQC Engine", + "elements": [ + { + "name": "analytic5-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "An elevated rate of KEM (Key Encapsulation Mechanism) operation failures was detected on a PQC Engine instance. This may indicate incompatible ML-KEM implementations between client and server, corrupted key material, or memory constraints on the F5 BIG-IP." + } + } + ] + }, + { + "name": "analytic6", + "type": "Microsoft.Common.Section", + "label": "PQC Engine policy upgraded cipher selection", + "elements": [ + { + "name": "analytic6-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "The PQC Engine policy engine upgraded the cipher selection for one or more TLS handshakes. This occurs when the engine is in enforce mode and the initial negotiation would have used a weaker algorithm than the policy allows. This is an expected and positive signal when enforcement is enabled." + } + } + ] + } + ] + }, + { + "name": "playbooks", + "label": "Playbooks", + "subLabel": { + "preValidation": "Configure the playbooks", + "postValidation": "Done" + }, + "bladeTitle": "Playbooks", + "elements": [ + { + "name": "playbooks-text", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "This solution installs the Playbook templates to help implement your Security Orchestration, Automation and Response (SOAR) operations. After installing the solution, these will be deployed under Playbook Templates in the Automation blade in Microsoft Sentinel. They can be configured and managed from the Manage solution view in Content Hub." + } + }, + { + "name": "playbooks-link", + "type": "Microsoft.Common.TextBlock", + "options": { + "link": { + "label": "Learn more", + "uri": "https://docs.microsoft.com/azure/sentinel/tutorial-respond-threats-playbook?WT.mc_id=Portal-Microsoft_Azure_CreateUIDef" + } + } + } + ] + } + ], + "outputs": { + "workspace-location": "[first(map(filter(basics('getLAWorkspace').value, (filter) => and(contains(toLower(filter.id), toLower(resourceGroup().name)),equals(filter.name,basics('workspace')))), (item) => item.location))]", + "location": "[location()]", + "workspace": "[basics('workspace')]" + } + } +} diff --git a/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Package/mainTemplate.json b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Package/mainTemplate.json new file mode 100644 index 00000000000..95eec3a45f0 --- /dev/null +++ b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Package/mainTemplate.json @@ -0,0 +1,1820 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "author": "QCrypton, Inc.", + "comments": "Solution template for QCryptonPQCEngine" + }, + "parameters": { + "location": { + "type": "string", + "minLength": 1, + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Not used, but needed to pass arm-ttk test `Location-Should-Not-Be-Hardcoded`. We instead use the `workspace-location` which is derived from the LA workspace" + } + }, + "workspace-location": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "[concat('Region to deploy solution resources -- separate from location selection',parameters('location'))]" + } + }, + "workspace": { + "defaultValue": "", + "type": "string", + "metadata": { + "description": "Workspace name for Log Analytics where Microsoft Sentinel is setup" + } + }, + "resourceGroupName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "resource group name where Microsoft Sentinel is setup" + } + }, + "subscription": { + "type": "string", + "defaultValue": "[last(split(subscription().id, '/'))]", + "metadata": { + "description": "subscription id where Microsoft Sentinel is setup" + } + }, + "workbook1-name": { + "type": "string", + "defaultValue": "QCrypton PQC Engine Posture", + "minLength": 1, + "metadata": { + "description": "Name for the workbook" + } + } + }, + "variables": { + "_solutionName": "QCryptonPQCEngine", + "_solutionVersion": "3.0.0", + "solutionId": "qcryptoninc1788706847984.qcrypton-pqc-engine-sentinel", + "_solutionId": "[variables('solutionId')]", + "workspaceResourceId": "[resourceId('microsoft.OperationalInsights/Workspaces', parameters('workspace'))]", + "dataConnectorCCPVersion": "3.0.0", + "_dataConnectorContentIdConnectorDefinition1": "QCryptonPQCEngineCCPDefinition", + "dataConnectorTemplateNameConnectorDefinition1": "[concat(parameters('workspace'),'-dc-',uniquestring(variables('_dataConnectorContentIdConnectorDefinition1')))]", + "_dataConnectorContentIdConnections1": "QCryptonPQCEngineCCPDefinitionConnections", + "dataConnectorTemplateNameConnections1": "[concat(parameters('workspace'),'-dc-',uniquestring(variables('_dataConnectorContentIdConnections1')))]", + "dataCollectionEndpointId1": "[concat('/subscriptions/',parameters('subscription'),'/resourceGroups/',parameters('resourceGroupName'),'/providers/Microsoft.Insights/dataCollectionEndpoints/',parameters('workspace'))]", + "blanks": "[replace('b', 'b', '')]", + "workbookVersion1": "1.0.0", + "workbookContentId1": "QCryptonPQCEnginePostureWorkbook", + "workbookId1": "[resourceId('Microsoft.Insights/workbooks', variables('workbookContentId1'))]", + "workbookTemplateSpecName1": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-wb-',uniquestring(variables('_workbookContentId1'))))]", + "_workbookContentId1": "[variables('workbookContentId1')]", + "_workbookcontentProductId1": "[concat(take(variables('_solutionId'),50),'-','wb','-', uniqueString(concat(variables('_solutionId'),'-','Workbook','-',variables('_workbookContentId1'),'-', variables('workbookVersion1'))))]", + "analyticRuleObject1": { + "analyticRuleVersion1": "1.0.0", + "_analyticRulecontentId1": "7a1b2c3d-4e5f-4a6b-7c8d-9e0f1a2b3c4d", + "analyticRuleId1": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', '7a1b2c3d-4e5f-4a6b-7c8d-9e0f1a2b3c4d')]", + "analyticRuleTemplateSpecName1": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('7a1b2c3d-4e5f-4a6b-7c8d-9e0f1a2b3c4d')))]", + "_analyticRulecontentProductId1": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','7a1b2c3d-4e5f-4a6b-7c8d-9e0f1a2b3c4d','-', '1.0.0')))]" + }, + "analyticRuleObject2": { + "analyticRuleVersion2": "1.0.0", + "_analyticRulecontentId2": "8b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e", + "analyticRuleId2": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', '8b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e')]", + "analyticRuleTemplateSpecName2": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('8b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e')))]", + "_analyticRulecontentProductId2": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','8b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e','-', '1.0.0')))]" + }, + "analyticRuleObject3": { + "analyticRuleVersion3": "1.0.0", + "_analyticRulecontentId3": "9c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f", + "analyticRuleId3": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', '9c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f')]", + "analyticRuleTemplateSpecName3": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('9c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f')))]", + "_analyticRulecontentProductId3": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','9c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f','-', '1.0.0')))]" + }, + "analyticRuleObject4": { + "analyticRuleVersion4": "1.0.0", + "_analyticRulecontentId4": "ad4e5f6a-7b8c-4d9e-0f1a-2b3c4d5e6f7a", + "analyticRuleId4": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', 'ad4e5f6a-7b8c-4d9e-0f1a-2b3c4d5e6f7a')]", + "analyticRuleTemplateSpecName4": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('ad4e5f6a-7b8c-4d9e-0f1a-2b3c4d5e6f7a')))]", + "_analyticRulecontentProductId4": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','ad4e5f6a-7b8c-4d9e-0f1a-2b3c4d5e6f7a','-', '1.0.0')))]" + }, + "analyticRuleObject5": { + "analyticRuleVersion5": "1.0.0", + "_analyticRulecontentId5": "be5f6a7b-8c9d-4e0f-1a2b-3c4d5e6f7a8b", + "analyticRuleId5": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', 'be5f6a7b-8c9d-4e0f-1a2b-3c4d5e6f7a8b')]", + "analyticRuleTemplateSpecName5": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('be5f6a7b-8c9d-4e0f-1a2b-3c4d5e6f7a8b')))]", + "_analyticRulecontentProductId5": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','be5f6a7b-8c9d-4e0f-1a2b-3c4d5e6f7a8b','-', '1.0.0')))]" + }, + "analyticRuleObject6": { + "analyticRuleVersion6": "1.0.0", + "_analyticRulecontentId6": "cf6a7b8c-9d0e-4f1a-2b3c-4d5e6f7a8b9c", + "analyticRuleId6": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', 'cf6a7b8c-9d0e-4f1a-2b3c-4d5e6f7a8b9c')]", + "analyticRuleTemplateSpecName6": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('cf6a7b8c-9d0e-4f1a-2b3c-4d5e6f7a8b9c')))]", + "_analyticRulecontentProductId6": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','cf6a7b8c-9d0e-4f1a-2b3c-4d5e6f7a8b9c','-', '1.0.0')))]" + }, + "QCryptonPQCEngine-Notify": "QCryptonPQCEngine-Notify", + "_QCryptonPQCEngine-Notify": "[variables('QCryptonPQCEngine-Notify')]", + "playbookVersion1": "1.0", + "playbookContentId1": "QCryptonPQCEngine-Notify", + "_playbookContentId1": "[variables('playbookContentId1')]", + "playbookId1": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId1'))]", + "playbookTemplateSpecName1": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId1'))))]", + "_playbookcontentProductId1": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId1'),'-', variables('playbookVersion1'))))]", + "_solutioncontentProductId": "[concat(take(variables('_solutionId'),50),'-','sl','-', uniqueString(concat(variables('_solutionId'),'-','Solution','-',variables('_solutionId'),'-', variables('_solutionVersion'))))]" + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('dataConnectorTemplateNameConnectorDefinition1'), variables('dataConnectorCCPVersion'))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "contentId": "[variables('_dataConnectorContentIdConnectorDefinition1')]", + "displayName": "QCrypton PQC Engine", + "contentKind": "DataConnector", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('dataConnectorCCPVersion')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',variables('_dataConnectorContentIdConnectorDefinition1'))]", + "apiVersion": "2022-09-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectorDefinitions", + "location": "[parameters('workspace-location')]", + "kind": "Customizable", + "properties": { + "connectorUiConfig": { + "id": "QCryptonPQCEngineCCPDefinition", + "title": "QCrypton PQC Engine", + "publisher": "QCrypton, Inc.", + "descriptionMarkdown": "The QCrypton PQC Engine data connector ingests runtime cryptographic telemetry from PQC Engine instances deployed on F5 BIG-IP into Microsoft Sentinel through the QCrypton API. PQC Engine is an OpenSSL 3.x provider that adds ML-KEM-768/1024 and ML-DSA-65/87 post-quantum algorithms. This connector streams handshake negotiations, KEM operations, policy enforcement events, and vulnerable algorithm detections into the PQCEngine_CL table.", + "graphQueries": [ + { + "metricName": "Total PQC Engine events received", + "legend": "PQCEngine_CL", + "baseQuery": "PQCEngine_CL" + } + ], + "sampleQueries": [ + { + "description": "PQC adoption rate across handshakes in the last 24h", + "query": "PQCEngine_CL\n| where TimeGenerated > ago(24h)\n| where EventType == 'handshake'\n| summarize Total = count(), PQC = countif(PQCNegotiated == 1)\n| extend PQCPct = round(100.0 * PQC / Total, 1)\n| project Total, PQC, PQCPct" + }, + { + "description": "Policy block events in the last 24h", + "query": "PQCEngine_CL\n| where TimeGenerated > ago(24h)\n| where EventType == 'policy_block'\n| project TimeGenerated, Hostname, InstanceId, Algorithm, NegotiatedGroup, CipherSuite, ClientClass, Detail\n| order by TimeGenerated desc" + }, + { + "description": "Vulnerable algorithm detections", + "query": "PQCEngine_CL\n| where TimeGenerated > ago(24h)\n| where EventType == 'vuln_detected'\n| summarize Count = count() by Algorithm, Detail\n| order by Count desc" + } + ], + "dataTypes": [ + { + "name": "PQCEngine_CL", + "lastDataReceivedQuery": "PQCEngine_CL\n| summarize Time = max(TimeGenerated)\n| where isnotempty(Time)" + } + ], + "connectivityCriteria": [ + { + "type": "HasDataConnectors" + } + ], + "availability": { + "isPreview": false, + "status": 1 + }, + "permissions": { + "resourceProvider": [ + { + "provider": "Microsoft.OperationalInsights/workspaces", + "permissionsDisplayText": "Read and Write permissions are required.", + "providerDisplayName": "Workspace", + "scope": "Workspace", + "requiredPermissions": { + "write": true, + "read": true, + "delete": true, + "action": false + } + } + ], + "customs": [ + { + "name": "QCrypton API Key", + "description": "A QCrypton PQC Engine API key is required. Obtain one from the [QCrypton Portal](https://portal.qcrypton.com)." + } + ] + }, + "instructionSteps": [ + { + "title": "Connect QCrypton PQC Engine to Microsoft Sentinel", + "instructions": [ + { + "type": "Markdown", + "parameters": { + "content": "This connector polls the QCrypton PQC Engine API to retrieve runtime cryptographic telemetry and ingest it into the **PQCEngine_CL** table in your Log Analytics workspace." + } + }, + { + "type": "Markdown", + "parameters": { + "content": "#### 1. API Key\nObtain your QCrypton API key from the [QCrypton Portal](https://portal.qcrypton.com). Navigate to **Settings > API Keys** and generate a key with read access to engine telemetry." + } + }, + { + "type": "Markdown", + "parameters": { + "content": "#### 2. API Server URL\nEnter the base URL of your QCrypton API server. The default is `https://api.qcrypton.com`. If you use a dedicated or regional instance, enter the URL provided by QCrypton." + } + }, + { + "type": "Textbox", + "parameters": { + "label": "QCrypton API Key", + "placeholder": "Enter your QCrypton API key", + "type": "password", + "name": "apiKey", + "validations": { + "required": true + } + } + }, + { + "type": "Textbox", + "parameters": { + "label": "QCrypton API Server URL", + "placeholder": "https://api.qcrypton.com", + "type": "text", + "name": "apiServerUrl", + "description": "Enter the QCrypton API base URL. Do not include a trailing slash or path.", + "validations": { + "required": true + } + } + }, + { + "type": "ConnectionToggleButton", + "parameters": { + "connectLabel": "Connect", + "name": "toggle" + } + } + ] + } + ] + } + } + }, + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnectorDefinition1')))]", + "apiVersion": "2022-01-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "properties": { + "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectorDefinitions', variables('_dataConnectorContentIdConnectorDefinition1'))]", + "contentId": "[variables('_dataConnectorContentIdConnectorDefinition1')]", + "kind": "DataConnector", + "version": "[variables('dataConnectorCCPVersion')]", + "source": { + "sourceId": "[variables('_solutionId')]", + "name": "[variables('_solutionName')]", + "kind": "Solution" + }, + "author": { + "name": "QCrypton, Inc." + }, + "support": { + "name": "QCrypton, Inc.", + "email": "support@qcrypton.com", + "tier": "Partner", + "link": "https://www.qcrypton.com/support" + }, + "dependencies": { + "criteria": [ + { + "version": "[variables('dataConnectorCCPVersion')]", + "contentId": "[variables('_dataConnectorContentIdConnections1')]", + "kind": "ResourcesDataConnector" + } + ] + } + } + }, + { + "name": "QCryptonPQCEngineDCR", + "apiVersion": "2022-06-01", + "type": "Microsoft.Insights/dataCollectionRules", + "location": "[parameters('workspace-location')]", + "kind": "[variables('blanks')]", + "properties": { + "dataCollectionEndpointId": "[variables('dataCollectionEndpointId1')]", + "streamDeclarations": { + "Custom-PQCEngine_CL": { + "columns": [ + { + "name": "TimeGenerated", + "type": "datetime" + }, + { + "name": "InstanceId", + "type": "string" + }, + { + "name": "Hostname", + "type": "string" + }, + { + "name": "EventType", + "type": "string" + }, + { + "name": "Algorithm", + "type": "string" + }, + { + "name": "Operation", + "type": "string" + }, + { + "name": "PeerGroups", + "type": "string" + }, + { + "name": "NegotiatedGroup", + "type": "string" + }, + { + "name": "CipherSuite", + "type": "string" + }, + { + "name": "ClientClass", + "type": "string" + }, + { + "name": "PQCOffered", + "type": "int" + }, + { + "name": "PQCNegotiated", + "type": "int" + }, + { + "name": "Success", + "type": "int" + }, + { + "name": "Detail", + "type": "string" + }, + { + "name": "Metadata", + "type": "string" + } + ] + } + }, + "destinations": { + "logAnalytics": [ + { + "workspaceResourceId": "[variables('workspaceResourceId')]", + "name": "clv2ws1" + } + ] + }, + "dataFlows": [ + { + "streams": [ + "Custom-PQCEngine_CL" + ], + "destinations": [ + "clv2ws1" + ], + "outputStream": "Custom-PQCEngine_CL", + "transformKql": "source | extend TimeGenerated = iff(isnull(TimeGenerated), now(), TimeGenerated) | project TimeGenerated, InstanceId, Hostname, EventType, Algorithm, Operation, PeerGroups, NegotiatedGroup, CipherSuite, ClientClass, PQCOffered, PQCNegotiated, Success, Detail, Metadata" + } + ] + } + }, + { + "name": "PQCEngine_CL", + "apiVersion": "2022-10-01", + "type": "Microsoft.OperationalInsights/workspaces/tables", + "location": "[parameters('workspace-location')]", + "kind": null, + "properties": { + "retentionInDays": 90, + "schema": { + "name": "PQCEngine_CL", + "description": "Runtime cryptographic telemetry from QCrypton PQC Engine instances deployed on F5 BIG-IP. Contains handshake negotiations, KEM/signature operations, policy enforcement events, vulnerable algorithm detections, and client classification.", + "columns": [ + { + "name": "TimeGenerated", + "type": "datetime", + "description": "Timestamp when the event was generated by the PQC Engine." + }, + { + "name": "InstanceId", + "type": "string", + "description": "Unique identifier for the PQC Engine instance." + }, + { + "name": "Hostname", + "type": "string", + "description": "F5 BIG-IP hostname." + }, + { + "name": "EventType", + "type": "string", + "description": "Event type: handshake, kem_op, sig_op, policy_block, policy_upgrade, vuln_detected, kex_complete." + }, + { + "name": "Algorithm", + "type": "string", + "description": "Algorithm name e.g. mlkem768, mldsa65, RSA-2048." + }, + { + "name": "Operation", + "type": "string", + "description": "Cryptographic operation: encapsulate, decapsulate, sign, verify." + }, + { + "name": "PeerGroups", + "type": "string", + "description": "Comma-separated client offered groups." + }, + { + "name": "NegotiatedGroup", + "type": "string", + "description": "Selected key exchange group." + }, + { + "name": "CipherSuite", + "type": "string", + "description": "TLS cipher suite." + }, + { + "name": "ClientClass", + "type": "string", + "description": "Client classification: pqc_native, pqc_hybrid, classical, legacy." + }, + { + "name": "PQCOffered", + "type": "int", + "description": "Client offered PQC groups (1=yes, 0=no)." + }, + { + "name": "PQCNegotiated", + "type": "int", + "description": "PQC was negotiated (1=yes, 0=no)." + }, + { + "name": "Success", + "type": "int", + "description": "Operation success (1=ok, 0=failed)." + }, + { + "name": "Detail", + "type": "string", + "description": "Free-form reason/context." + }, + { + "name": "Metadata", + "type": "string", + "description": "Additional JSON metadata about the event." + } + ] + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "contentProductId": "[concat(take(variables('_solutionId'), 50),'-','dc','-', uniqueString(concat(variables('_solutionId'),'-','DataConnector','-',variables('_dataConnectorContentIdConnectorDefinition1'),'-', variables('dataConnectorCCPVersion'))))]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "version": "[variables('dataConnectorCCPVersion')]" + } + }, + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',variables('_dataConnectorContentIdConnectorDefinition1'))]", + "apiVersion": "2022-09-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectorDefinitions", + "location": "[parameters('workspace-location')]", + "kind": "Customizable", + "properties": { + "connectorUiConfig": { + "id": "QCryptonPQCEngineCCPDefinition", + "title": "QCrypton PQC Engine", + "publisher": "QCrypton, Inc.", + "descriptionMarkdown": "The QCrypton PQC Engine data connector ingests runtime cryptographic telemetry from PQC Engine instances deployed on F5 BIG-IP into Microsoft Sentinel through the QCrypton API. PQC Engine is an OpenSSL 3.x provider that adds ML-KEM-768/1024 and ML-DSA-65/87 post-quantum algorithms. This connector streams handshake negotiations, KEM operations, policy enforcement events, and vulnerable algorithm detections into the PQCEngine_CL table.", + "graphQueries": [ + { + "metricName": "Total PQC Engine events received", + "legend": "PQCEngine_CL", + "baseQuery": "PQCEngine_CL" + } + ], + "sampleQueries": [ + { + "description": "PQC adoption rate across handshakes in the last 24h", + "query": "PQCEngine_CL\n| where TimeGenerated > ago(24h)\n| where EventType == 'handshake'\n| summarize Total = count(), PQC = countif(PQCNegotiated == 1)\n| extend PQCPct = round(100.0 * PQC / Total, 1)\n| project Total, PQC, PQCPct" + }, + { + "description": "Policy block events in the last 24h", + "query": "PQCEngine_CL\n| where TimeGenerated > ago(24h)\n| where EventType == 'policy_block'\n| project TimeGenerated, Hostname, InstanceId, Algorithm, NegotiatedGroup, CipherSuite, ClientClass, Detail\n| order by TimeGenerated desc" + }, + { + "description": "Vulnerable algorithm detections", + "query": "PQCEngine_CL\n| where TimeGenerated > ago(24h)\n| where EventType == 'vuln_detected'\n| summarize Count = count() by Algorithm, Detail\n| order by Count desc" + } + ], + "dataTypes": [ + { + "name": "PQCEngine_CL", + "lastDataReceivedQuery": "PQCEngine_CL\n| summarize Time = max(TimeGenerated)\n| where isnotempty(Time)" + } + ], + "connectivityCriteria": [ + { + "type": "HasDataConnectors" + } + ], + "availability": { + "isPreview": false, + "status": 1 + }, + "permissions": { + "resourceProvider": [ + { + "provider": "Microsoft.OperationalInsights/workspaces", + "permissionsDisplayText": "Read and Write permissions are required.", + "providerDisplayName": "Workspace", + "scope": "Workspace", + "requiredPermissions": { + "write": true, + "read": true, + "delete": true, + "action": false + } + } + ], + "customs": [ + { + "name": "QCrypton API Key", + "description": "A QCrypton PQC Engine API key is required. Obtain one from the [QCrypton Portal](https://portal.qcrypton.com)." + } + ] + }, + "instructionSteps": [ + { + "title": "Connect QCrypton PQC Engine to Microsoft Sentinel", + "instructions": [ + { + "type": "Markdown", + "parameters": { + "content": "This connector polls the QCrypton PQC Engine API to retrieve runtime cryptographic telemetry and ingest it into the **PQCEngine_CL** table in your Log Analytics workspace." + } + }, + { + "type": "Markdown", + "parameters": { + "content": "#### 1. API Key\nObtain your QCrypton API key from the [QCrypton Portal](https://portal.qcrypton.com). Navigate to **Settings > API Keys** and generate a key with read access to engine telemetry." + } + }, + { + "type": "Markdown", + "parameters": { + "content": "#### 2. API Server URL\nEnter the base URL of your QCrypton API server. The default is `https://api.qcrypton.com`. If you use a dedicated or regional instance, enter the URL provided by QCrypton." + } + }, + { + "type": "Textbox", + "parameters": { + "label": "QCrypton API Key", + "placeholder": "Enter your QCrypton API key", + "type": "password", + "name": "apiKey", + "validations": { + "required": true + } + } + }, + { + "type": "Textbox", + "parameters": { + "label": "QCrypton API Server URL", + "placeholder": "https://api.qcrypton.com", + "type": "text", + "name": "apiServerUrl", + "description": "Enter the QCrypton API base URL. Do not include a trailing slash or path.", + "validations": { + "required": true + } + } + }, + { + "type": "ConnectionToggleButton", + "parameters": { + "connectLabel": "Connect", + "name": "toggle" + } + } + ] + } + ] + } + } + }, + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnectorDefinition1')))]", + "apiVersion": "2022-01-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "properties": { + "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectorDefinitions', variables('_dataConnectorContentIdConnectorDefinition1'))]", + "contentId": "[variables('_dataConnectorContentIdConnectorDefinition1')]", + "kind": "DataConnector", + "version": "[variables('dataConnectorCCPVersion')]", + "source": { + "sourceId": "[variables('_solutionId')]", + "name": "[variables('_solutionName')]", + "kind": "Solution" + }, + "author": { + "name": "QCrypton, Inc." + }, + "support": { + "name": "QCrypton, Inc.", + "email": "support@qcrypton.com", + "tier": "Partner", + "link": "https://www.qcrypton.com/support" + }, + "dependencies": { + "criteria": [ + { + "version": "[variables('dataConnectorCCPVersion')]", + "contentId": "[variables('_dataConnectorContentIdConnections1')]", + "kind": "ResourcesDataConnector" + } + ] + } + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('dataConnectorTemplateNameConnections1'), variables('dataConnectorCCPVersion'))]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "contentId": "[variables('_dataConnectorContentIdConnections1')]", + "displayName": "QCrypton PQC Engine", + "contentKind": "ResourcesDataConnector", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('dataConnectorCCPVersion')]", + "parameters": { + "guidValue": { + "defaultValue": "[[newGuid()]", + "type": "securestring" + }, + "innerWorkspace": { + "defaultValue": "[parameters('workspace')]", + "type": "securestring" + }, + "connectorDefinitionName": { + "defaultValue": "QCrypton PQC Engine", + "type": "securestring", + "minLength": 1 + }, + "workspace": { + "defaultValue": "[parameters('workspace')]", + "type": "securestring" + }, + "dcrConfig": { + "defaultValue": { + "dataCollectionEndpoint": "data collection Endpoint", + "dataCollectionRuleImmutableId": "data collection rule immutableId" + }, + "type": "object" + }, + "apiKey": { + "defaultValue": "apiKey", + "type": "securestring", + "minLength": 1 + }, + "apiServerUrl": { + "defaultValue": "apiServerUrl", + "type": "securestring", + "minLength": 1 + } + }, + "variables": { + "_dataConnectorContentIdConnections1": "[variables('_dataConnectorContentIdConnections1')]" + }, + "resources": [ + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnections1')))]", + "apiVersion": "2022-01-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "properties": { + "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectors', variables('_dataConnectorContentIdConnections1'))]", + "contentId": "[variables('_dataConnectorContentIdConnections1')]", + "kind": "ResourcesDataConnector", + "version": "[variables('dataConnectorCCPVersion')]", + "source": { + "sourceId": "[variables('_solutionId')]", + "name": "[variables('_solutionName')]", + "kind": "Solution" + }, + "author": { + "name": "QCrypton, Inc." + }, + "support": { + "name": "QCrypton, Inc.", + "email": "support@qcrypton.com", + "tier": "Partner", + "link": "https://www.qcrypton.com/support" + } + } + }, + { + "name": "[[concat(parameters('innerWorkspace'),'/Microsoft.SecurityInsights/', 'QCryptonPQCEngineCCP', parameters('guidValue'))]", + "apiVersion": "2023-02-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors", + "location": "[parameters('workspace-location')]", + "kind": "RestApiPoller", + "properties": { + "auth": { + "type": "APIKey", + "ApiKey": "[[parameters('apiKey')]", + "ApiKeyName": "X-API-Key", + "ApiKeyIdentifier": "", + "IsApiKeyInPostPayload": false + }, + "request": { + "apiEndpoint": "[[concat(parameters('apiServerUrl'),'/v1/engine/telemetry')]", + "httpMethod": "GET", + "rateLimitQPS": 2, + "queryWindowInMin": 60, + "queryTimeFormat": "yyyy-MM-ddTHH:mm:ssZ", + "retryCount": 3, + "timeoutInSeconds": 120, + "headers": { + "Accept": "application/json", + "User-Agent": "MicrosoftSentinel-QCryptonPQCEngineCCP" + }, + "queryParameters": { + "scanDateAfter": "{_QueryWindowStartTime}", + "scanDateBefore": "{_QueryWindowEndTime}" + } + }, + "response": { + "eventsJsonPaths": [ + "$.events" + ], + "format": "json" + }, + "paging": { + "pagingType": "NextPageToken", + "nextPageTokenJsonPath": "$.nextPageToken", + "nextPageParaName": "pageToken" + }, + "connectorDefinitionName": "QCryptonPQCEngineCCPDefinition", + "dataType": "PQCEngine_CL", + "dcrConfig": { + "streamName": "Custom-PQCEngine_CL", + "dataCollectionEndpoint": "[[parameters('dcrConfig').dataCollectionEndpoint]", + "dataCollectionRuleImmutableId": "[[parameters('dcrConfig').dataCollectionRuleImmutableId]" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "contentProductId": "[concat(take(variables('_solutionId'), 50),'-','rdc','-', uniqueString(concat(variables('_solutionId'),'-','ResourcesDataConnector','-',variables('_dataConnectorContentIdConnections1'),'-', variables('dataConnectorCCPVersion'))))]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "version": "[variables('dataConnectorCCPVersion')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('workbookTemplateSpecName1')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "QCryptonPQCEnginePosture Workbook with template version 3.0.0", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('workbookVersion1')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.Insights/workbooks", + "name": "[variables('workbookContentId1')]", + "location": "[parameters('workspace-location')]", + "kind": "shared", + "apiVersion": "2021-08-01", + "metadata": { + "description": "" + }, + "properties": { + "displayName": "[parameters('workbook1-name')]", + "serializedData": "{\"version\":\"Notebook/1.0\",\"items\":[{\"type\":1,\"content\":{\"json\":\"# QCrypton PQC Engine \u2014 Post-Quantum Cryptography Operations Dashboard\\n\\nRuntime cryptographic telemetry from PQC Engine instances on F5 BIG-IP. Tracks PQC adoption, policy enforcement, vulnerable algorithm detections, and KEM/signature operations. Data source: `PQCEngine_CL`.\"},\"name\":\"title\"},{\"type\":9,\"content\":{\"version\":\"KqlParameterItem/1.0\",\"parameters\":[{\"id\":\"timeRange\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"TimeRange\",\"type\":4,\"value\":{\"durationMs\":86400000},\"typeSettings\":{\"selectableValues\":[{\"durationMs\":3600000},{\"durationMs\":86400000},{\"durationMs\":604800000},{\"durationMs\":2592000000}]}}]},\"name\":\"params\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"PQCEngine_CL\\n| where TimeGenerated {TimeRange}\\n| where EventType == 'handshake'\\n| summarize Count = count() by ClientClass\\n| render piechart\",\"size\":0,\"title\":\"Client classification distribution\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"piechart\",\"customWidth\":\"50\"},\"name\":\"clientClassDist\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"PQCEngine_CL\\n| where TimeGenerated {TimeRange}\\n| where EventType in ('handshake', 'kex_complete')\\n| summarize Count = count() by NegotiatedGroup\\n| order by Count desc\\n| render piechart\",\"size\":0,\"title\":\"Negotiated key exchange groups\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"piechart\",\"customWidth\":\"50\"},\"name\":\"negotiatedGroups\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"PQCEngine_CL\\n| where TimeGenerated {TimeRange}\\n| where EventType == 'handshake'\\n| summarize PQCHybrid = countif(ClientClass == 'pqc_hybrid'), PQCNative = countif(ClientClass == 'pqc_native'), Classical = countif(ClientClass == 'classical'), Legacy = countif(ClientClass == 'legacy') by bin(TimeGenerated, 1h)\\n| render timechart\",\"size\":0,\"title\":\"PQC vs classical handshakes over time\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"timechart\"},\"name\":\"pqcVsClassical\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"PQCEngine_CL\\n| where TimeGenerated {TimeRange}\\n| where EventType in ('policy_block', 'policy_upgrade')\\n| summarize Count = count() by bin(TimeGenerated, 1h), EventType\\n| render timechart\",\"size\":0,\"title\":\"Policy enforcement events over time\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"timechart\"},\"name\":\"policyEvents\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"PQCEngine_CL\\n| where TimeGenerated {TimeRange}\\n| where EventType == 'handshake'\\n| summarize Total = count(), PQC = countif(PQCNegotiated == 1), Classical = countif(PQCNegotiated == 0), PolicyBlocks = countif(EventType == 'policy_block') by Hostname, InstanceId\\n| extend PQCPct = round(100.0 * PQC / Total, 1)\\n| project Hostname, InstanceId, Total, PQC, Classical, PQCPct\\n| order by Total desc\",\"size\":0,\"title\":\"Per-instance summary\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"perInstanceSummary\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"PQCEngine_CL\\n| where TimeGenerated {TimeRange}\\n| where EventType == 'vuln_detected'\\n| summarize Count = count() by Algorithm, Detail\\n| order by Count desc\",\"size\":0,\"title\":\"Vulnerable algorithms detected\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"vulnAlgorithms\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"PQCEngine_CL\\n| where TimeGenerated {TimeRange}\\n| where Success == 0\\n| summarize Count = count() by bin(TimeGenerated, 1h), EventType\\n| render timechart\",\"size\":0,\"title\":\"Failed operations over time\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"timechart\"},\"name\":\"failedOps\"}],\"fromTemplateId\":\"QCrypton-PQCEnginePosture\",\"$schema\":\"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"}\n", + "version": "1.0", + "sourceId": "[variables('workspaceResourceId')]", + "category": "sentinel" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Workbook-', last(split(variables('workbookId1'),'/'))))]", + "properties": { + "description": ".description", + "parentId": "[variables('workbookId1')]", + "contentId": "[variables('_workbookContentId1')]", + "kind": "Workbook", + "version": "[variables('workbookVersion1')]", + "source": { + "kind": "Solution", + "name": "QCryptonPQCEngine", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "QCrypton, Inc." + }, + "support": { + "name": "QCrypton, Inc.", + "email": "support@qcrypton.com", + "tier": "Partner", + "link": "https://www.qcrypton.com/support" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_workbookContentId1')]", + "contentKind": "Workbook", + "displayName": "[parameters('workbook1-name')]", + "contentProductId": "[variables('_workbookcontentProductId1')]", + "id": "[variables('_workbookcontentProductId1')]", + "version": "[variables('workbookVersion1')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleObject1').analyticRuleTemplateSpecName1]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "PolicyBlockDetected_AnalyticalRules Analytics Rule with template version 3.0.0", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleObject1').analyticRuleVersion1]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRuleObject1')._analyticRulecontentId1]", + "apiVersion": "2023-02-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "The PQC Engine crypto policy enforcement blocked a TLS handshake that did not meet minimum\nrequirements. This may indicate a client attempting to connect with banned cipher suites,\nblocked key exchange groups, or TLS versions below the policy minimum. Review the blocked\nalgorithm and client to determine if policy adjustment or client upgrade is needed.", + "displayName": "PQC Engine policy blocked a TLS handshake", + "enabled": false, + "query": "PQCEngine_CL\n| where TimeGenerated > ago(1h)\n| where EventType == \"policy_block\"\n| project TimeGenerated, Hostname, InstanceId, Algorithm, NegotiatedGroup, CipherSuite, ClientClass, Detail\n| order by TimeGenerated desc\n", + "queryFrequency": "PTPT1H", + "queryPeriod": "PTPT1H", + "severity": "High", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "QCryptonPQCEngine", + "dataTypes": [ + "PQCEngine_CL" + ] + } + ], + "tactics": [ + "InitialAccess" + ], + "techniques": [ + "T1190" + ], + "entityMappings": [ + { + "entityType": "Host", + "fieldMappings": [ + { + "identifier": "HostName", + "columnName": "Hostname" + } + ] + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleObject1').analyticRuleId1,'/'))))]", + "properties": { + "description": "QCryptonPQCEngine Analytics Rule 1", + "parentId": "[variables('analyticRuleObject1').analyticRuleId1]", + "contentId": "[variables('analyticRuleObject1')._analyticRulecontentId1]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleObject1').analyticRuleVersion1]", + "source": { + "kind": "Solution", + "name": "QCryptonPQCEngine", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "QCrypton, Inc." + }, + "support": { + "name": "QCrypton, Inc.", + "email": "support@qcrypton.com", + "tier": "Partner", + "link": "https://www.qcrypton.com/support" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('analyticRuleObject1')._analyticRulecontentId1]", + "contentKind": "AnalyticsRule", + "displayName": "PQC Engine policy blocked a TLS handshake", + "contentProductId": "[variables('analyticRuleObject1')._analyticRulecontentProductId1]", + "id": "[variables('analyticRuleObject1')._analyticRulecontentProductId1]", + "version": "[variables('analyticRuleObject1').analyticRuleVersion1]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleObject2').analyticRuleTemplateSpecName2]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "VulnerableAlgorithmDetected_AnalyticalRules Analytics Rule with template version 3.0.0", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleObject2').analyticRuleVersion2]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRuleObject2')._analyticRulecontentId2]", + "apiVersion": "2023-02-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "The PQC Engine vulnerability database flagged a quantum-vulnerable algorithm during a TLS\nhandshake or cryptographic operation on F5 BIG-IP. Algorithms such as RSA-2048, ECDSA P-256,\nor Ed25519 are vulnerable to Shor's algorithm on a cryptographically relevant quantum computer.\nMigrate to PQ-hybrid algorithms (X25519+ML-KEM-768) to protect against harvest-now-decrypt-later\nattacks.", + "displayName": "Vulnerable classical algorithm detected in TLS negotiation", + "enabled": false, + "query": "PQCEngine_CL\n| where TimeGenerated > ago(1h)\n| where EventType == \"vuln_detected\"\n| project TimeGenerated, Hostname, InstanceId, Algorithm, Operation, ClientClass, PQCOffered, Detail\n| order by TimeGenerated desc\n", + "queryFrequency": "PTPT1H", + "queryPeriod": "PTPT1H", + "severity": "High", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "QCryptonPQCEngine", + "dataTypes": [ + "PQCEngine_CL" + ] + } + ], + "tactics": [ + "Collection" + ], + "techniques": [ + "T1040" + ], + "entityMappings": [ + { + "entityType": "Host", + "fieldMappings": [ + { + "identifier": "HostName", + "columnName": "Hostname" + } + ] + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleObject2').analyticRuleId2,'/'))))]", + "properties": { + "description": "QCryptonPQCEngine Analytics Rule 2", + "parentId": "[variables('analyticRuleObject2').analyticRuleId2]", + "contentId": "[variables('analyticRuleObject2')._analyticRulecontentId2]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleObject2').analyticRuleVersion2]", + "source": { + "kind": "Solution", + "name": "QCryptonPQCEngine", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "QCrypton, Inc." + }, + "support": { + "name": "QCrypton, Inc.", + "email": "support@qcrypton.com", + "tier": "Partner", + "link": "https://www.qcrypton.com/support" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('analyticRuleObject2')._analyticRulecontentId2]", + "contentKind": "AnalyticsRule", + "displayName": "Vulnerable classical algorithm detected in TLS negotiation", + "contentProductId": "[variables('analyticRuleObject2')._analyticRulecontentProductId2]", + "id": "[variables('analyticRuleObject2')._analyticRulecontentProductId2]", + "version": "[variables('analyticRuleObject2').analyticRuleVersion2]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleObject3').analyticRuleTemplateSpecName3]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "PQCDowngradeOnEngine_AnalyticalRules Analytics Rule with template version 3.0.0", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleObject3').analyticRuleVersion3]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRuleObject3')._analyticRulecontentId3]", + "apiVersion": "2023-02-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "A TLS handshake completed where the client offered post-quantum hybrid key exchange groups but\nthe F5 BIG-IP negotiated a classical-only group. This may indicate PQC Engine misconfiguration,\nan intermediate device stripping PQC groups from the ClientHello, or the engine running in\nmonitor mode rather than enforce mode. Investigate the negotiated vs offered groups.", + "displayName": "PQC downgrade on engine \u2014 client offered hybrid but classical negotiated", + "enabled": false, + "query": "PQCEngine_CL\n| where TimeGenerated > ago(1h)\n| where EventType == \"handshake\"\n| where PQCOffered == 1 and PQCNegotiated == 0\n| project TimeGenerated, Hostname, InstanceId, NegotiatedGroup, PeerGroups, CipherSuite, ClientClass, Detail\n| order by TimeGenerated desc\n", + "queryFrequency": "PTPT1H", + "queryPeriod": "PTPT1H", + "severity": "High", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "QCryptonPQCEngine", + "dataTypes": [ + "PQCEngine_CL" + ] + } + ], + "tactics": [ + "InitialAccess", + "Collection" + ], + "techniques": [ + "T1557", + "T1040" + ], + "entityMappings": [ + { + "entityType": "Host", + "fieldMappings": [ + { + "identifier": "HostName", + "columnName": "Hostname" + } + ] + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleObject3').analyticRuleId3,'/'))))]", + "properties": { + "description": "QCryptonPQCEngine Analytics Rule 3", + "parentId": "[variables('analyticRuleObject3').analyticRuleId3]", + "contentId": "[variables('analyticRuleObject3')._analyticRulecontentId3]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleObject3').analyticRuleVersion3]", + "source": { + "kind": "Solution", + "name": "QCryptonPQCEngine", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "QCrypton, Inc." + }, + "support": { + "name": "QCrypton, Inc.", + "email": "support@qcrypton.com", + "tier": "Partner", + "link": "https://www.qcrypton.com/support" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('analyticRuleObject3')._analyticRulecontentId3]", + "contentKind": "AnalyticsRule", + "displayName": "PQC downgrade on engine \u2014 client offered hybrid but classical negotiated", + "contentProductId": "[variables('analyticRuleObject3')._analyticRulecontentProductId3]", + "id": "[variables('analyticRuleObject3')._analyticRulecontentProductId3]", + "version": "[variables('analyticRuleObject3').analyticRuleVersion3]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleObject4').analyticRuleTemplateSpecName4]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "HighClassicalClientRate_AnalyticalRules Analytics Rule with template version 3.0.0", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleObject4').analyticRuleVersion4]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRuleObject4')._analyticRulecontentId4]", + "apiVersion": "2023-02-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "More than 50% of TLS handshakes on a PQC Engine instance in the last 24 hours were from\nclassical-only clients that did not offer any post-quantum key exchange groups. These\nconnections are not protected against harvest-now-decrypt-later attacks. Consider requiring\nPQC-capable TLS libraries or upgrading connecting services to OpenSSL 3.5+ or BoringSSL with\nML-KEM support.", + "displayName": "High percentage of classical-only clients on PQC Engine", + "enabled": false, + "query": "PQCEngine_CL\n| where TimeGenerated > ago(1d)\n| where EventType == \"handshake\"\n| summarize Total = count(), Classical = countif(ClientClass in (\"classical\", \"legacy\")) by Hostname, InstanceId\n| extend ClassicalPct = round(100.0 * Classical / Total, 1)\n| where ClassicalPct > 50\n| project Hostname, InstanceId, Total, Classical, ClassicalPct\n| order by ClassicalPct desc\n", + "queryFrequency": "PP1D", + "queryPeriod": "PP1D", + "severity": "Informational", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "QCryptonPQCEngine", + "dataTypes": [ + "PQCEngine_CL" + ] + } + ], + "tactics": [ + "Discovery" + ], + "techniques": [ + "T1082" + ], + "entityMappings": [ + { + "entityType": "Host", + "fieldMappings": [ + { + "identifier": "HostName", + "columnName": "Hostname" + } + ] + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleObject4').analyticRuleId4,'/'))))]", + "properties": { + "description": "QCryptonPQCEngine Analytics Rule 4", + "parentId": "[variables('analyticRuleObject4').analyticRuleId4]", + "contentId": "[variables('analyticRuleObject4')._analyticRulecontentId4]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleObject4').analyticRuleVersion4]", + "source": { + "kind": "Solution", + "name": "QCryptonPQCEngine", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "QCrypton, Inc." + }, + "support": { + "name": "QCrypton, Inc.", + "email": "support@qcrypton.com", + "tier": "Partner", + "link": "https://www.qcrypton.com/support" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('analyticRuleObject4')._analyticRulecontentId4]", + "contentKind": "AnalyticsRule", + "displayName": "High percentage of classical-only clients on PQC Engine", + "contentProductId": "[variables('analyticRuleObject4')._analyticRulecontentProductId4]", + "id": "[variables('analyticRuleObject4')._analyticRulecontentProductId4]", + "version": "[variables('analyticRuleObject4').analyticRuleVersion4]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleObject5').analyticRuleTemplateSpecName5]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "KEMOperationFailureSpike_AnalyticalRules Analytics Rule with template version 3.0.0", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleObject5').analyticRuleVersion5]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRuleObject5')._analyticRulecontentId5]", + "apiVersion": "2023-02-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "An elevated rate of KEM (Key Encapsulation Mechanism) operation failures was detected on a\nPQC Engine instance. This may indicate incompatible ML-KEM implementations between client and\nserver, corrupted key material, memory constraints on the F5 BIG-IP, or a misconfigured PQC\nEngine provider. Investigate the failing algorithm and operation type.", + "displayName": "KEM operation failure spike on PQC Engine", + "enabled": false, + "query": "PQCEngine_CL\n| where TimeGenerated > ago(1h)\n| where EventType == \"kem_op\"\n| where Success == 0\n| summarize FailureCount = count(), Algorithms = make_set(Algorithm, 5), Operations = make_set(Operation, 5) by Hostname, InstanceId\n| where FailureCount > 5\n| project Hostname, InstanceId, FailureCount, Algorithms, Operations\n| order by FailureCount desc\n", + "queryFrequency": "PTPT1H", + "queryPeriod": "PTPT1H", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 5, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "QCryptonPQCEngine", + "dataTypes": [ + "PQCEngine_CL" + ] + } + ], + "tactics": [ + "Impact" + ], + "techniques": [ + "T1499" + ], + "entityMappings": [ + { + "entityType": "Host", + "fieldMappings": [ + { + "identifier": "HostName", + "columnName": "Hostname" + } + ] + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleObject5').analyticRuleId5,'/'))))]", + "properties": { + "description": "QCryptonPQCEngine Analytics Rule 5", + "parentId": "[variables('analyticRuleObject5').analyticRuleId5]", + "contentId": "[variables('analyticRuleObject5')._analyticRulecontentId5]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleObject5').analyticRuleVersion5]", + "source": { + "kind": "Solution", + "name": "QCryptonPQCEngine", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "QCrypton, Inc." + }, + "support": { + "name": "QCrypton, Inc.", + "email": "support@qcrypton.com", + "tier": "Partner", + "link": "https://www.qcrypton.com/support" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('analyticRuleObject5')._analyticRulecontentId5]", + "contentKind": "AnalyticsRule", + "displayName": "KEM operation failure spike on PQC Engine", + "contentProductId": "[variables('analyticRuleObject5')._analyticRulecontentProductId5]", + "id": "[variables('analyticRuleObject5')._analyticRulecontentProductId5]", + "version": "[variables('analyticRuleObject5').analyticRuleVersion5]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleObject6').analyticRuleTemplateSpecName6]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "PolicyUpgradeActivity_AnalyticalRules Analytics Rule with template version 3.0.0", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleObject6').analyticRuleVersion6]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRuleObject6')._analyticRulecontentId6]", + "apiVersion": "2023-02-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "The PQC Engine policy engine upgraded the cipher selection for one or more TLS handshakes.\nThis occurs when the engine is in enforce mode and the initial negotiation would have used a\nweaker algorithm than the policy allows. The engine intervened to select a stronger (typically\nPQ-hybrid) algorithm. This is an expected and positive signal when enforcement is enabled.", + "displayName": "PQC Engine policy upgraded cipher selection", + "enabled": false, + "query": "PQCEngine_CL\n| where TimeGenerated > ago(1d)\n| where EventType == \"policy_upgrade\"\n| summarize UpgradeCount = count(), Algorithms = make_set(Algorithm, 10) by Hostname, InstanceId\n| project Hostname, InstanceId, UpgradeCount, Algorithms\n| order by UpgradeCount desc\n", + "queryFrequency": "PP1D", + "queryPeriod": "PP1D", + "severity": "Informational", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "QCryptonPQCEngine", + "dataTypes": [ + "PQCEngine_CL" + ] + } + ], + "tactics": [ + "DefenseEvasion" + ], + "techniques": [ + "T1600" + ], + "entityMappings": [ + { + "entityType": "Host", + "fieldMappings": [ + { + "identifier": "HostName", + "columnName": "Hostname" + } + ] + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleObject6').analyticRuleId6,'/'))))]", + "properties": { + "description": "QCryptonPQCEngine Analytics Rule 6", + "parentId": "[variables('analyticRuleObject6').analyticRuleId6]", + "contentId": "[variables('analyticRuleObject6')._analyticRulecontentId6]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleObject6').analyticRuleVersion6]", + "source": { + "kind": "Solution", + "name": "QCryptonPQCEngine", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "QCrypton, Inc." + }, + "support": { + "name": "QCrypton, Inc.", + "email": "support@qcrypton.com", + "tier": "Partner", + "link": "https://www.qcrypton.com/support" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('analyticRuleObject6')._analyticRulecontentId6]", + "contentKind": "AnalyticsRule", + "displayName": "PQC Engine policy upgraded cipher selection", + "contentProductId": "[variables('analyticRuleObject6')._analyticRulecontentProductId6]", + "id": "[variables('analyticRuleObject6')._analyticRulecontentProductId6]", + "version": "[variables('analyticRuleObject6').analyticRuleVersion6]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('playbookTemplateSpecName1')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "QCryptonPQCEngine-Notify Playbook with template version 3.0.0", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('playbookVersion1')]", + "parameters": { + "PlaybookName": { + "type": "string", + "defaultValue": "QCryptonPQCEngine-Notify", + "metadata": { + "description": "Name of the Logic App playbook." + } + }, + "TeamsGroupId": { + "type": "string", + "metadata": { + "description": "Target Teams group (team) ID." + } + }, + "TeamsChannelId": { + "type": "string", + "metadata": { + "description": "Target Teams channel ID." + } + } + }, + "variables": { + "AzureSentinelConnectionName": "[[concat('azuresentinel-', parameters('PlaybookName'))]", + "TeamsConnectionName": "[[concat('teams-', parameters('PlaybookName'))]", + "connection-1": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", + "_connection-1": "[[variables('connection-1')]", + "connection-2": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/teams')]", + "_connection-2": "[[variables('connection-2')]", + "workspace-location-inline": "[concat('[resourceGroup().locatio', 'n]')]", + "workspace-name": "[parameters('workspace')]", + "workspaceResourceId": "[[resourceId('microsoft.OperationalInsights/Workspaces', variables('workspace-name'))]" + }, + "resources": [ + { + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('AzureSentinelConnectionName')]", + "location": "[[variables('workspace-location-inline')]", + "kind": "V1", + "properties": { + "displayName": "[[variables('AzureSentinelConnectionName')]", + "api": { + "id": "[[variables('_connection-1')]" + } + } + }, + { + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('TeamsConnectionName')]", + "location": "[[variables('workspace-location-inline')]", + "kind": "V1", + "properties": { + "displayName": "[[variables('TeamsConnectionName')]", + "api": { + "id": "[[variables('_connection-2')]" + } + } + }, + { + "type": "Microsoft.Logic/workflows", + "apiVersion": "2019-05-01", + "name": "[[parameters('PlaybookName')]", + "location": "[[variables('workspace-location-inline')]", + "identity": { + "type": "SystemAssigned" + }, + "dependsOn": [ + "[[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]", + "[[resourceId('Microsoft.Web/connections', variables('TeamsConnectionName'))]" + ], + "properties": { + "state": "Enabled", + "definition": { + "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "$connections": { + "type": "Object" + } + }, + "triggers": { + "Microsoft_Sentinel_incident": { + "type": "ApiConnectionWebhook", + "inputs": { + "body": { + "callback_url": "@{listCallbackUrl()}" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "path": "/incident-creation" + } + } + }, + "actions": { + "Post_message_to_Teams": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['teams']['connectionId']" + } + }, + "method": "post", + "path": "/v3/beta/teams/@{encodeURIComponent(parameters('TeamsGroupId'))}/channels/@{encodeURIComponent(parameters('TeamsChannelId'))}/messages", + "body": { + "body": { + "contentType": "html", + "content": "QCrypton PQC Engine alert: @{triggerBody()?['object']?['properties']?['title']}
Severity: @{triggerBody()?['object']?['properties']?['severity']}
Incident: Open in Microsoft Sentinel" + } + } + } + } + } + }, + "parameters": { + "$connections": { + "value": { + "azuresentinel": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]", + "connectionName": "[[variables('AzureSentinelConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]" + }, + "teams": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('TeamsConnectionName'))]", + "connectionName": "[[variables('TeamsConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/teams')]" + } + } + } + } + }, + "tags": { + "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Playbook-', last(split(variables('playbookId1'),'/'))))]", + "properties": { + "parentId": "[variables('playbookId1')]", + "contentId": "[variables('_playbookContentId1')]", + "kind": "Playbook", + "version": "[variables('playbookVersion1')]", + "source": { + "kind": "Solution", + "name": "QCryptonPQCEngine", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "QCrypton, Inc." + }, + "support": { + "name": "QCrypton, Inc.", + "email": "support@qcrypton.com", + "tier": "Partner", + "link": "https://www.qcrypton.com/support" + } + } + } + ], + "metadata": { + "title": "QCrypton PQC Engine \u2014 notify on policy block or vulnerable algorithm alert", + "description": "Logic App playbook: on Microsoft Sentinel incident trigger, post a card to a Microsoft Teams channel summarizing the PQC Engine alert (policy block, vulnerable algorithm, or downgrade detection).", + "prerequisites": "A Teams channel + webhook, or a Teams connection API auth.", + "postDeployment": [ + "After deployment, authorize the Teams connection in the Logic App designer." + ], + "lastUpdateTime": "2026-11-01T00:00:00Z", + "entities": [ + "Host" + ], + "tags": [ + "Notification", + "PQC", + "F5", + "OpenSSL" + ], + "releaseNotes": { + "version": "1.0", + "title": "[variables('blanks')]", + "notes": [ + "Initial version" + ] + } + } + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_playbookContentId1')]", + "contentKind": "Playbook", + "displayName": "QCryptonPQCEngine-Notify", + "contentProductId": "[variables('_playbookcontentProductId1')]", + "id": "[variables('_playbookcontentProductId1')]", + "version": "[variables('playbookVersion1')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentPackages", + "apiVersion": "2023-04-01-preview", + "location": "[parameters('workspace-location')]", + "properties": { + "version": "3.0.0", + "kind": "Solution", + "contentSchemaVersion": "3.0.0", + "displayName": "QCrypton PQC Engine", + "publisherDisplayName": "QCrypton, Inc.", + "descriptionHtml": "

Note: Please refer to the following before installing the solution:

\n

\u2022 Review the solution Release Notes

\n

\u2022 There may be known issues pertaining to this Solution, please refer to them before installing.

\n

Runtime cryptographic telemetry from QCrypton PQC Engine, an OpenSSL 3.x provider for F5 BIG-IP that adds ML-KEM-768/1024 and ML-DSA-65/87 post-quantum algorithms. Ingests handshake negotiations, KEM operations, policy enforcement events, vulnerable algorithm detections, and client classification into the PQCEngine_CL table via the Codeless Connector Framework (RestApiPoller). Ships with 1 data connector, 6 analytic rules, workbook, and Teams-notification playbook.

\n

Underlying Microsoft Technologies used:

\n

This solution takes a dependency on the following technologies, and some of these dependencies either may be in Preview state or might result in additional ingestion or operational costs:

\n

\u2022 Microsoft Sentinel Codeless Connector Framework

\n

Data Connectors: 1, Workbooks: 1, Analytic Rules: 6, Playbooks: 1

\n

Learn more about Microsoft Sentinel | Learn more about Solutions

\n", + "contentKind": "Solution", + "contentProductId": "[variables('_solutioncontentProductId')]", + "id": "[variables('_solutioncontentProductId')]", + "icon": "", + "contentId": "[variables('_solutionId')]", + "parentId": "[variables('_solutionId')]", + "source": { + "kind": "Solution", + "name": "QCryptonPQCEngine", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "QCrypton, Inc." + }, + "support": { + "name": "QCrypton, Inc.", + "email": "support@qcrypton.com", + "tier": "Partner", + "link": "https://www.qcrypton.com/support" + }, + "dependencies": { + "operator": "AND", + "criteria": [ + { + "kind": "DataConnector", + "contentId": "[variables('_dataConnectorContentIdConnections1')]", + "version": "[variables('dataConnectorCCPVersion')]" + }, + { + "kind": "Workbook", + "contentId": "[variables('_workbookContentId1')]", + "version": "[variables('workbookVersion1')]" + }, + { + "kind": "AnalyticsRule", + "contentId": "[variables('analyticRuleObject1')._analyticRulecontentId1]", + "version": "[variables('analyticRuleObject1').analyticRuleVersion1]" + }, + { + "kind": "AnalyticsRule", + "contentId": "[variables('analyticRuleObject2')._analyticRulecontentId2]", + "version": "[variables('analyticRuleObject2').analyticRuleVersion2]" + }, + { + "kind": "AnalyticsRule", + "contentId": "[variables('analyticRuleObject3')._analyticRulecontentId3]", + "version": "[variables('analyticRuleObject3').analyticRuleVersion3]" + }, + { + "kind": "AnalyticsRule", + "contentId": "[variables('analyticRuleObject4')._analyticRulecontentId4]", + "version": "[variables('analyticRuleObject4').analyticRuleVersion4]" + }, + { + "kind": "AnalyticsRule", + "contentId": "[variables('analyticRuleObject5')._analyticRulecontentId5]", + "version": "[variables('analyticRuleObject5').analyticRuleVersion5]" + }, + { + "kind": "AnalyticsRule", + "contentId": "[variables('analyticRuleObject6')._analyticRulecontentId6]", + "version": "[variables('analyticRuleObject6').analyticRuleVersion6]" + }, + { + "kind": "Playbook", + "contentId": "[variables('_QCryptonPQCEngine-Notify')]", + "version": "[variables('playbookVersion1')]" + } + ] + }, + "firstPublishDate": "2026-11-01", + "providers": [ + "QCrypton, Inc." + ], + "categories": { + "domains": [ + "Security - Cloud Security", + "Security - Network", + "Security - Threat Protection" + ] + } + }, + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('_solutionId'))]" + } + ], + "outputs": {} +} \ No newline at end of file diff --git a/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Package/testParameters.json b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Package/testParameters.json new file mode 100644 index 00000000000..554801e41b7 --- /dev/null +++ b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Package/testParameters.json @@ -0,0 +1,38 @@ +{ + "location": { + "type": "string", + "minLength": 1, + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Not used, but needed to pass arm-ttk test `Location-Should-Not-Be-Hardcoded`. We instead use the `workspace-location` which is derived from the LA workspace" + } + }, + "workspace-location": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "[concat('Region to deploy solution resources -- separate from location selection',parameters('location'))]" + } + }, + "workspace": { + "defaultValue": "", + "type": "string", + "metadata": { + "description": "Workspace name for Log Analytics where Microsoft Sentinel is setup" + } + }, + "resourceGroupName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "resource group name where Microsoft Sentinel is setup" + } + }, + "subscription": { + "type": "string", + "defaultValue": "[last(split(subscription().id, '/'))]", + "metadata": { + "description": "subscription id where Microsoft Sentinel is setup" + } + } +} diff --git a/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Playbooks/QCryptonPQCEngine-Notify/README.md b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Playbooks/QCryptonPQCEngine-Notify/README.md new file mode 100644 index 00000000000..1185899d36c --- /dev/null +++ b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Playbooks/QCryptonPQCEngine-Notify/README.md @@ -0,0 +1,39 @@ +# QCryptonPQCEngine-Notify + +## Summary + +This playbook posts a notification to a Microsoft Teams channel when a Microsoft Sentinel incident is created from a QCrypton PQC Engine analytic rule (policy block, vulnerable algorithm, or PQC downgrade detection). + +### Prerequisites + +1. A Microsoft Teams team and channel where notifications should be posted. +2. The Teams Group ID and Channel ID for the target channel. + +### Deployment instructions + +1. Click the **Deploy to Azure** button below to launch the ARM template deployment wizard. +2. Fill in the required parameters: + - **PlaybookName**: Name of the Logic App (default: `QCryptonPQCEngine-Notify`) + - **TeamsGroupId**: The target Teams group (team) ID + - **TeamsChannelId**: The target Teams channel ID + +[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FQCryptonPQCEngine%2Fpqc-engine%2Fsentinel-solution%2FPlaybooks%2FQCryptonPQCEngine-Notify%2Fazuredeploy.json) + +### Post-deployment instructions + +#### a. Authorize connections + +Once deployment is complete, authorize each API connection: + +1. Navigate to the Logic App in the Azure Portal. +2. Click **API connections** in the left menu. +3. For each connection (Azure Sentinel, Teams): + - Click the connection resource + - Click **Edit API connection** + - Click **Authorize** + - Sign in and click **Save** + +#### b. Configure automation in Microsoft Sentinel + +1. In Microsoft Sentinel, go to **Automation**. +2. Create an automation rule that triggers this playbook when an incident is created from one of the PQC Engine analytic rules. diff --git a/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Playbooks/QCryptonPQCEngine-Notify/azuredeploy.json b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Playbooks/QCryptonPQCEngine-Notify/azuredeploy.json new file mode 100644 index 00000000000..a5a12ecd711 --- /dev/null +++ b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Playbooks/QCryptonPQCEngine-Notify/azuredeploy.json @@ -0,0 +1,130 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "title": "QCrypton PQC Engine — notify on policy block or vulnerable algorithm alert", + "description": "Logic App playbook: on Microsoft Sentinel incident trigger, post a card to a Microsoft Teams channel summarizing the PQC Engine alert (policy block, vulnerable algorithm, or downgrade detection).", + "prerequisites": "A Teams channel + webhook, or a Teams connection API auth.", + "postDeployment": ["After deployment, authorize the Teams connection in the Logic App designer."], + "lastUpdateTime": "2026-11-01T00:00:00.000Z", + "entities": ["Host"], + "tags": ["Notification", "PQC", "F5", "OpenSSL"], + "support": { + "tier": "Community", + "armtemplate": "Generated from https://github.com/qcrypton/pqc-engine" + }, + "author": { "name": "QCrypton, Inc." } + }, + "parameters": { + "PlaybookName": { + "type": "string", + "defaultValue": "QCryptonPQCEngine-Notify", + "metadata": { "description": "Name of the Logic App playbook." } + }, + "TeamsGroupId": { + "type": "string", + "metadata": { "description": "Target Teams group (team) ID." } + }, + "TeamsChannelId": { + "type": "string", + "metadata": { "description": "Target Teams channel ID." } + } + }, + "variables": { + "AzureSentinelConnectionName": "[concat('azuresentinel-', parameters('PlaybookName'))]", + "TeamsConnectionName": "[concat('teams-', parameters('PlaybookName'))]" + }, + "resources": [ + { + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[variables('AzureSentinelConnectionName')]", + "location": "[resourceGroup().location]", + "kind": "V1", + "properties": { + "displayName": "[variables('AzureSentinelConnectionName')]", + "customParameterValues": {}, + "api": { + "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/azuresentinel')]" + } + } + }, + { + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[variables('TeamsConnectionName')]", + "location": "[resourceGroup().location]", + "kind": "V1", + "properties": { + "displayName": "[variables('TeamsConnectionName')]", + "customParameterValues": {}, + "api": { + "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/teams')]" + } + } + }, + { + "type": "Microsoft.Logic/workflows", + "apiVersion": "2019-05-01", + "name": "[parameters('PlaybookName')]", + "location": "[resourceGroup().location]", + "identity": { "type": "SystemAssigned" }, + "dependsOn": [ + "[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]", + "[resourceId('Microsoft.Web/connections', variables('TeamsConnectionName'))]" + ], + "properties": { + "state": "Enabled", + "definition": { + "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "$connections": { "defaultValue": {}, "type": "Object" } + }, + "triggers": { + "Microsoft_Sentinel_incident": { + "type": "ApiConnectionWebhook", + "inputs": { + "body": { "callback_url": "@{listCallbackUrl()}" }, + "host": { "connection": { "name": "@parameters('$connections')['azuresentinel']['connectionId']" } }, + "path": "/incident-creation" + } + } + }, + "actions": { + "Post_message_to_Teams": { + "type": "ApiConnection", + "inputs": { + "host": { "connection": { "name": "@parameters('$connections')['teams']['connectionId']" } }, + "method": "post", + "path": "/v3/beta/teams/@{encodeURIComponent(parameters('TeamsGroupId'))}/channels/@{encodeURIComponent(parameters('TeamsChannelId'))}/messages", + "body": { + "body": { + "contentType": "html", + "content": "QCrypton PQC Engine alert: @{triggerBody()?['object']?['properties']?['title']}
Severity: @{triggerBody()?['object']?['properties']?['severity']}
Incident: Open in Microsoft Sentinel" + } + } + } + } + } + }, + "parameters": { + "$connections": { + "value": { + "azuresentinel": { + "connectionId": "[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]", + "connectionName": "[variables('AzureSentinelConnectionName')]", + "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/azuresentinel')]" + }, + "teams": { + "connectionId": "[resourceId('Microsoft.Web/connections', variables('TeamsConnectionName'))]", + "connectionName": "[variables('TeamsConnectionName')]", + "id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/teams')]" + } + } + } + } + } + } + ] +} diff --git a/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/ReleaseNotes.md b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/ReleaseNotes.md new file mode 100644 index 00000000000..b3dc7462918 --- /dev/null +++ b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/ReleaseNotes.md @@ -0,0 +1,31 @@ +# QCrypton PQC Engine for Microsoft Sentinel — Release Notes + +## v1.0.0 (01-11-2026) + +Initial release of the QCrypton PQC Engine Sentinel Content Hub solution. + +### Components + +- **1 Data Connector** — Codeless Connector Framework (RestApiPoller) polling QCrypton API for PQC Engine runtime telemetry +- **6 Analytic Rules:** + - PQC Engine policy blocked a TLS handshake (High) + - Vulnerable classical algorithm detected in TLS negotiation (High) + - PQC downgrade on engine — client offered hybrid but classical negotiated (High) + - High percentage of classical-only clients on PQC Engine (Informational) + - KEM operation failure spike on PQC Engine (Medium) + - PQC Engine policy upgraded cipher selection (Informational) +- **1 Workbook** — Post-Quantum Cryptography Operations Dashboard with client classification, key exchange groups, policy enforcement, and per-instance metrics +- **1 Playbook** — Teams notification on Sentinel incidents + +### Custom Table + +- **PQCEngine_CL** — Runtime cryptographic telemetry: handshake negotiations, KEM/signature operations, policy enforcement events, vulnerable algorithm detections, and client classification + +### Algorithms Tracked + +- ML-KEM-768 (FIPS 203, NIST Level 3) +- ML-KEM-1024 (FIPS 203, NIST Level 5) +- ML-DSA-65 (FIPS 204, NIST Level 3) +- ML-DSA-87 (FIPS 204, NIST Level 5) +- X25519+ML-KEM-768 (hybrid, TLS codepoint 0x11EC) +- secp384r1+ML-KEM-1024 (hybrid, Level 5) diff --git a/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/SolutionMetadata.json b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/SolutionMetadata.json new file mode 100644 index 00000000000..4a8cae6bcdc --- /dev/null +++ b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/SolutionMetadata.json @@ -0,0 +1,16 @@ +{ + "publisherId": "qcryptoninc1788706847984", + "offerId": "qcrypton-pqc-engine-sentinel", + "firstPublishDate": "2026-11-01", + "providers": ["QCrypton, Inc."], + "categories": { + "domains": ["Security - Cloud Security", "Security - Network", "Security - Threat Protection"], + "verticals": [] + }, + "support": { + "name": "QCrypton, Inc.", + "email": "support@qcrypton.com", + "tier": "Partner", + "link": "https://www.qcrypton.com/support" + } +} diff --git a/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Workbooks/Images/Preview/QCryptonPQCEnginePostureBlack1.png b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Workbooks/Images/Preview/QCryptonPQCEnginePostureBlack1.png new file mode 100644 index 00000000000..7b4154ee59b Binary files /dev/null and b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Workbooks/Images/Preview/QCryptonPQCEnginePostureBlack1.png differ diff --git a/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Workbooks/Images/Preview/QCryptonPQCEnginePostureWhite1.png b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Workbooks/Images/Preview/QCryptonPQCEnginePostureWhite1.png new file mode 100644 index 00000000000..85d16f66e9a Binary files /dev/null and b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Workbooks/Images/Preview/QCryptonPQCEnginePostureWhite1.png differ diff --git a/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Workbooks/QCryptonPQCEnginePosture.json b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Workbooks/QCryptonPQCEnginePosture.json new file mode 100644 index 00000000000..72dae1fa11d --- /dev/null +++ b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/Workbooks/QCryptonPQCEnginePosture.json @@ -0,0 +1,130 @@ +{ + "version": "Notebook/1.0", + "items": [ + { + "type": 1, + "content": { + "json": "# QCrypton PQC Engine — Post-Quantum Cryptography Operations Dashboard\n\nRuntime cryptographic telemetry from PQC Engine instances on F5 BIG-IP. Tracks PQC adoption, policy enforcement, vulnerable algorithm detections, and KEM/signature operations. Data source: `PQCEngine_CL`." + }, + "name": "title" + }, + { + "type": 9, + "content": { + "version": "KqlParameterItem/1.0", + "parameters": [ + { + "id": "timeRange", + "version": "KqlParameterItem/1.0", + "name": "TimeRange", + "type": 4, + "value": { "durationMs": 86400000 }, + "typeSettings": { + "selectableValues": [ + { "durationMs": 3600000 }, + { "durationMs": 86400000 }, + { "durationMs": 604800000 }, + { "durationMs": 2592000000 } + ] + } + } + ] + }, + "name": "params" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "PQCEngine_CL\n| where TimeGenerated {TimeRange}\n| where EventType == 'handshake'\n| summarize Count = count() by ClientClass\n| render piechart", + "size": 0, + "title": "Client classification distribution", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "visualization": "piechart", + "customWidth": "50" + }, + "name": "clientClassDist" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "PQCEngine_CL\n| where TimeGenerated {TimeRange}\n| where EventType in ('handshake', 'kex_complete')\n| summarize Count = count() by NegotiatedGroup\n| order by Count desc\n| render piechart", + "size": 0, + "title": "Negotiated key exchange groups", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "visualization": "piechart", + "customWidth": "50" + }, + "name": "negotiatedGroups" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "PQCEngine_CL\n| where TimeGenerated {TimeRange}\n| where EventType == 'handshake'\n| summarize PQCHybrid = countif(ClientClass == 'pqc_hybrid'), PQCNative = countif(ClientClass == 'pqc_native'), Classical = countif(ClientClass == 'classical'), Legacy = countif(ClientClass == 'legacy') by bin(TimeGenerated, 1h)\n| render timechart", + "size": 0, + "title": "PQC vs classical handshakes over time", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "visualization": "timechart" + }, + "name": "pqcVsClassical" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "PQCEngine_CL\n| where TimeGenerated {TimeRange}\n| where EventType in ('policy_block', 'policy_upgrade')\n| summarize Count = count() by bin(TimeGenerated, 1h), EventType\n| render timechart", + "size": 0, + "title": "Policy enforcement events over time", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "visualization": "timechart" + }, + "name": "policyEvents" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "PQCEngine_CL\n| where TimeGenerated {TimeRange}\n| where EventType == 'handshake'\n| summarize Total = count(), PQC = countif(PQCNegotiated == 1), Classical = countif(PQCNegotiated == 0), PolicyBlocks = countif(EventType == 'policy_block') by Hostname, InstanceId\n| extend PQCPct = round(100.0 * PQC / Total, 1)\n| project Hostname, InstanceId, Total, PQC, Classical, PQCPct\n| order by Total desc", + "size": 0, + "title": "Per-instance summary", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces" + }, + "name": "perInstanceSummary" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "PQCEngine_CL\n| where TimeGenerated {TimeRange}\n| where EventType == 'vuln_detected'\n| summarize Count = count() by Algorithm, Detail\n| order by Count desc", + "size": 0, + "title": "Vulnerable algorithms detected", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces" + }, + "name": "vulnAlgorithms" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "PQCEngine_CL\n| where TimeGenerated {TimeRange}\n| where Success == 0\n| summarize Count = count() by bin(TimeGenerated, 1h), EventType\n| render timechart", + "size": 0, + "title": "Failed operations over time", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "visualization": "timechart" + }, + "name": "failedOps" + } + ], + "styleSettings": {}, + "fromTemplateId": "QCrypton-PQCEnginePosture", + "$schema": "https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json" +} diff --git a/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/build-package.sh b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/build-package.sh new file mode 100755 index 00000000000..35e1cf34c48 --- /dev/null +++ b/Solutions/QCryptonPQCEngine/pqc-engine/sentinel-solution/build-package.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash +# Regenerates Package/mainTemplate.json + createUiDefinition.json via the official +# Azure/Azure-Sentinel createSolutionV3.ps1 tool, then runs ARM-TTK with the same +# false-positive filters Microsoft's own PR pipeline uses. +# +# Requires: pwsh (>=7.4), git, Install-Module powershell-yaml +# +# To prepare the Azure-Sentinel fork for PR submission: +# cd ~/Phd/azure/Azure-Sentinel +# git fetch upstream +# git checkout -b feature/qcrypton-pqc-engine upstream/master +set -euo pipefail + +SRC="$(cd "$(dirname "$0")" && pwd)" +WORK="${WORK:-/tmp/sentinel-build}" +SENTINEL_REPO="$WORK/Azure-Sentinel" +BRANCH="feature/qcrypton-pqc-engine" +SOLUTION_NAME="QCryptonPQCEngine" +STAGE="$SENTINEL_REPO/Solutions/$SOLUTION_NAME" + +command -v pwsh >/dev/null || { echo "pwsh not found"; exit 1; } +command -v git >/dev/null || { echo "git not found"; exit 1; } +pwsh -NoProfile -Command "if (-not (Get-Module -ListAvailable powershell-yaml)) { Install-Module powershell-yaml -Scope CurrentUser -Force -AllowClobber }" + +mkdir -p "$WORK" +if [ ! -d "$SENTINEL_REPO/.git" ]; then + git clone --depth 1 --filter=blob:none --sparse https://github.com/Azure/Azure-Sentinel.git "$SENTINEL_REPO" + (cd "$SENTINEL_REPO" && git sparse-checkout set Tools/Create-Azure-Sentinel-Solution .script) +fi + +rm -rf "$STAGE" +mkdir -p "$STAGE/Data" "$STAGE/Data Connectors" "$STAGE/Analytic Rules" \ + "$STAGE/Workbooks" "$STAGE/Playbooks/QCryptonPQCEngine-Notify" + +cp "$SRC/Data_Connectors/QCryptonPQCEngine_CCF/"*.json "$STAGE/Data Connectors/" +cp "$SRC/Analytic_Rules/"*.yaml "$STAGE/Analytic Rules/" +cp "$SRC/Workbooks/QCryptonPQCEnginePosture.json" "$STAGE/Workbooks/" +cp "$SRC/Playbooks/QCryptonPQCEngine-Notify/azuredeploy.json" "$STAGE/Playbooks/QCryptonPQCEngine-Notify/" +cp "$SRC/SolutionMetadata.json" "$STAGE/" +cp "$SRC/ReleaseNotes.md" "$STAGE/" + +cat > "$STAGE/Data/Solution_$SOLUTION_NAME.json" <", + "Description": "Runtime cryptographic telemetry from QCrypton PQC Engine, an OpenSSL 3.x provider for F5 BIG-IP that adds ML-KEM-768/1024 and ML-DSA-65/87 post-quantum algorithms. Ships with data connector, 6 analytic rules, workbook, and Teams-notification playbook.", + "Data Connectors": ["Data Connectors/QCryptonPQCEngine_ConnectorDefinition.json"], + "Workbooks": ["Workbooks/QCryptonPQCEnginePosture.json"], + "Analytic Rules": [ + "Analytic Rules/PolicyBlockDetected.yaml", + "Analytic Rules/VulnerableAlgorithmDetected.yaml", + "Analytic Rules/PQCDowngradeOnEngine.yaml", + "Analytic Rules/HighClassicalClientRate.yaml", + "Analytic Rules/KEMOperationFailureSpike.yaml", + "Analytic Rules/PolicyUpgradeActivity.yaml" + ], + "Playbooks": ["Playbooks/QCryptonPQCEngine-Notify/azuredeploy.json"], + "Metadata": "SolutionMetadata.json", + "BasePath": "$STAGE", + "Version": "1.0.0", + "TemplateSpec": true, + "Is1PConnector": false +} +JSON + +echo ">>> Running createSolutionV3.ps1..." +( cd "$SENTINEL_REPO" && pwsh -NoProfile -File "Tools/Create-Azure-Sentinel-Solution/V3/createSolutionV3.ps1" \ + -SolutionDataFolderPath "$STAGE/Data" ) >/tmp/v3-build.log 2>&1 || true +grep -E "Fail=|Failed" /tmp/v3-build.log | tail -5 || true + +echo ">>> Running ARM-TTK (Microsoft's filtered runner)..." +(cd "$SENTINEL_REPO" && pwsh -NoProfile -File .script/local-validation/run-arm-ttk.ps1 -SolutionPath "$STAGE") \ + | tee /tmp/arm-ttk.log | tail -5 +grep "ARM-TTK-SUMMARY" /tmp/arm-ttk.log + +echo ">>> Post-processing: friendly display name..." +python3 -c " +import json, sys +p = '$STAGE/Package/mainTemplate.json' +d = json.load(open(p)) +for r in d['resources']: + if r.get('type', '').endswith('contentPackages'): + r['properties']['displayName'] = 'QCrypton PQC Engine' +json.dump(d, open(p, 'w'), indent=2) +print(' displayName set to: QCrypton PQC Engine') +" + +echo ">>> Syncing Package back to $SRC/Package..." +rm -rf "$SRC/Package" +cp -r "$STAGE/Package" "$SRC/Package" +echo ">>> Done. Package contents:" +ls "$SRC/Package" diff --git a/Workbooks/Images/Preview/QCryptonPQCEnginePostureBlack1.png b/Workbooks/Images/Preview/QCryptonPQCEnginePostureBlack1.png new file mode 100644 index 00000000000..7b4154ee59b Binary files /dev/null and b/Workbooks/Images/Preview/QCryptonPQCEnginePostureBlack1.png differ diff --git a/Workbooks/Images/Preview/QCryptonPQCEnginePostureWhite1.png b/Workbooks/Images/Preview/QCryptonPQCEnginePostureWhite1.png new file mode 100644 index 00000000000..85d16f66e9a Binary files /dev/null and b/Workbooks/Images/Preview/QCryptonPQCEnginePostureWhite1.png differ diff --git a/Workbooks/QCryptonPQCEnginePosture.json b/Workbooks/QCryptonPQCEnginePosture.json new file mode 100644 index 00000000000..72dae1fa11d --- /dev/null +++ b/Workbooks/QCryptonPQCEnginePosture.json @@ -0,0 +1,130 @@ +{ + "version": "Notebook/1.0", + "items": [ + { + "type": 1, + "content": { + "json": "# QCrypton PQC Engine — Post-Quantum Cryptography Operations Dashboard\n\nRuntime cryptographic telemetry from PQC Engine instances on F5 BIG-IP. Tracks PQC adoption, policy enforcement, vulnerable algorithm detections, and KEM/signature operations. Data source: `PQCEngine_CL`." + }, + "name": "title" + }, + { + "type": 9, + "content": { + "version": "KqlParameterItem/1.0", + "parameters": [ + { + "id": "timeRange", + "version": "KqlParameterItem/1.0", + "name": "TimeRange", + "type": 4, + "value": { "durationMs": 86400000 }, + "typeSettings": { + "selectableValues": [ + { "durationMs": 3600000 }, + { "durationMs": 86400000 }, + { "durationMs": 604800000 }, + { "durationMs": 2592000000 } + ] + } + } + ] + }, + "name": "params" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "PQCEngine_CL\n| where TimeGenerated {TimeRange}\n| where EventType == 'handshake'\n| summarize Count = count() by ClientClass\n| render piechart", + "size": 0, + "title": "Client classification distribution", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "visualization": "piechart", + "customWidth": "50" + }, + "name": "clientClassDist" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "PQCEngine_CL\n| where TimeGenerated {TimeRange}\n| where EventType in ('handshake', 'kex_complete')\n| summarize Count = count() by NegotiatedGroup\n| order by Count desc\n| render piechart", + "size": 0, + "title": "Negotiated key exchange groups", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "visualization": "piechart", + "customWidth": "50" + }, + "name": "negotiatedGroups" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "PQCEngine_CL\n| where TimeGenerated {TimeRange}\n| where EventType == 'handshake'\n| summarize PQCHybrid = countif(ClientClass == 'pqc_hybrid'), PQCNative = countif(ClientClass == 'pqc_native'), Classical = countif(ClientClass == 'classical'), Legacy = countif(ClientClass == 'legacy') by bin(TimeGenerated, 1h)\n| render timechart", + "size": 0, + "title": "PQC vs classical handshakes over time", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "visualization": "timechart" + }, + "name": "pqcVsClassical" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "PQCEngine_CL\n| where TimeGenerated {TimeRange}\n| where EventType in ('policy_block', 'policy_upgrade')\n| summarize Count = count() by bin(TimeGenerated, 1h), EventType\n| render timechart", + "size": 0, + "title": "Policy enforcement events over time", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "visualization": "timechart" + }, + "name": "policyEvents" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "PQCEngine_CL\n| where TimeGenerated {TimeRange}\n| where EventType == 'handshake'\n| summarize Total = count(), PQC = countif(PQCNegotiated == 1), Classical = countif(PQCNegotiated == 0), PolicyBlocks = countif(EventType == 'policy_block') by Hostname, InstanceId\n| extend PQCPct = round(100.0 * PQC / Total, 1)\n| project Hostname, InstanceId, Total, PQC, Classical, PQCPct\n| order by Total desc", + "size": 0, + "title": "Per-instance summary", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces" + }, + "name": "perInstanceSummary" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "PQCEngine_CL\n| where TimeGenerated {TimeRange}\n| where EventType == 'vuln_detected'\n| summarize Count = count() by Algorithm, Detail\n| order by Count desc", + "size": 0, + "title": "Vulnerable algorithms detected", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces" + }, + "name": "vulnAlgorithms" + }, + { + "type": 3, + "content": { + "version": "KqlItem/1.0", + "query": "PQCEngine_CL\n| where TimeGenerated {TimeRange}\n| where Success == 0\n| summarize Count = count() by bin(TimeGenerated, 1h), EventType\n| render timechart", + "size": 0, + "title": "Failed operations over time", + "queryType": 0, + "resourceType": "microsoft.operationalinsights/workspaces", + "visualization": "timechart" + }, + "name": "failedOps" + } + ], + "styleSettings": {}, + "fromTemplateId": "QCrypton-PQCEnginePosture", + "$schema": "https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json" +} diff --git a/Workbooks/WorkbooksMetadata.json b/Workbooks/WorkbooksMetadata.json index 02c3df1f0eb..c566cf37085 100644 --- a/Workbooks/WorkbooksMetadata.json +++ b/Workbooks/WorkbooksMetadata.json @@ -11922,5 +11922,25 @@ "IT Operations" ] } -} +}, + { + "workbookKey": "QCryptonPQCEnginePostureWorkbook", + "logoFileName": "qcrypton.svg", + "description": "Runtime PQC operations dashboard for QCrypton PQC Engine instances on F5 BIG-IP. Visualises client classification, key exchange group distribution, policy enforcement events, vulnerable algorithm detections, and per-instance metrics from PQC Engine telemetry.", + "dataTypesDependencies": [ + "PQCEngine_CL" + ], + "dataConnectorsDependencies": [ + "QCryptonPQCEngineCCPDefinition" + ], + "previewImagesFileNames": [ + "QCryptonPQCEnginePostureWhite1.png", + "QCryptonPQCEnginePostureBlack1.png" + ], + "version": "1.0.0", + "title": "QCrypton PQC Engine Posture", + "templateRelativePath": "QCryptonPQCEnginePosture.json", + "subtitle": "", + "provider": "QCrypton, Inc." + } ]