# Copyright (c) Microsoft Corporation. # Licensed under the MIT License. # E2E Test: Stream Analytics/DataExfiltration_Audit # Real Azure Policy: "Stream Analytics job should connect to trusted inputs # and outputs" # Source: regolator/policyDefinitions/Stream Analytics/DataExfiltration_Audit.json # # Features exercised: # - anyOf tree (2 top-level branches for outputs and streamingjobs) # - Multiple datasource type checks with notIn on sub-resource types # - Count with where clause on wildcard array (storageAccounts[*].accountName) # - notIn operator with parameterised Array # - Long alias paths with dots and hyphens (e.g. datasource.Microsoft-Storage-Blob.storageAccounts[*]) # - exists "true" + notIn combined check aliases: test_aliases.json policy_definition: | { "properties": { "displayName": "Stream Analytics job should connect to trusted inputs and outputs", "policyType": "BuiltIn", "mode": "All", "parameters": { "effect": { "type": "String", "allowedValues": ["Deny", "Disabled", "Audit"], "defaultValue": "Audit" }, "allowedEventHubNamespaces": { "type": "Array", "defaultValue": [] }, "allowedSQLServers": { "type": "Array", "defaultValue": [] }, "allowedStorageAccounts": { "type": "Array", "defaultValue": [] }, "allowedCosmosAccounts": { "type": "Array", "defaultValue": [] }, "allowedAzureFunctionAccounts": { "type": "Array", "defaultValue": [] }, "allowedIoTHubNamespaces": { "type": "Array", "defaultValue": [] }, "allowedMLWebServiceEndpoints": { "type": "Array", "defaultValue": [] } }, "policyRule": { "if": { "anyOf": [ { "allOf": [ { "field": "type", "equals": "Microsoft.StreamAnalytics/streamingjobs/outputs" }, { "anyOf": [ { "allOf": [ { "field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.type", "equals": "Microsoft.EventHub/EventHub" }, { "field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.Microsoft-ServiceBus-EventHub.serviceBusNamespace", "notIn": "[parameters('allowedEventHubNamespaces')]" } ] }, { "allOf": [ { "field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.type", "equals": "Microsoft.Sql/Server/Database" }, { "field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.Microsoft-Sql-Server-Database.server", "notIn": "[parameters('allowedSQLServers')]" } ] }, { "allOf": [ { "field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.type", "equals": "Microsoft.Storage/Table" }, { "field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.Microsoft-Storage-Table.accountName", "notIn": "[parameters('allowedStorageAccounts')]" } ] }, { "allOf": [ { "field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.type", "equals": "Microsoft.Storage/DocumentDB" }, { "field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.Microsoft-Storage-DocumentDB.accountId", "notIn": "[parameters('allowedCosmosAccounts')]" } ] }, { "allOf": [ { "field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.type", "equals": "Microsoft.AzureFunction" }, { "field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.Microsoft-AzureFunction.functionAppName", "notIn": "[parameters('allowedAzureFunctionAccounts')]" } ] }, { "allOf": [ { "field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.type", "equals": "Microsoft.Storage/Blob" }, { "count": { "field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.Microsoft-Storage-Blob.storageAccounts[*]", "where": { "field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.Microsoft-Storage-Blob.storageAccounts[*].accountName", "notIn": "[parameters('allowedStorageAccounts')]" } }, "greater": 0 } ] }, { "field": "Microsoft.StreamAnalytics/streamingjobs/outputs/datasource.type", "notIn": [ "Microsoft.EventHub/EventHub", "Microsoft.Sql/Server/Database", "Microsoft.Storage/Table", "Microsoft.Storage/DocumentDB", "Microsoft.AzureFunction", "Microsoft.Storage/Blob" ] } ] } ] }, { "allOf": [ { "field": "type", "equals": "Microsoft.StreamAnalytics/streamingjobs" }, { "anyOf": [ { "allOf": [ { "field": "Microsoft.StreamAnalytics/streamingjobs/jobStorageAccount", "exists": "true" }, { "field": "Microsoft.StreamAnalytics/streamingjobs/jobStorageAccount.accountName", "notIn": "[parameters('allowedStorageAccounts')]" } ] } ] } ] } ] }, "then": { "effect": "[parameters('effect')]" } } } } cases: # ========================================================================= # OUTPUT: EventHub output to allowed namespace → pass # ========================================================================= - note: pass_output_eventhub_allowed resource: type: "Microsoft.StreamAnalytics/streamingjobs/outputs" name: "output1" properties: datasource: type: "Microsoft.EventHub/EventHub" Microsoft-ServiceBus-EventHub: serviceBusNamespace: "my-eh-namespace" parameters: allowedEventHubNamespaces: - "my-eh-namespace" want_undefined: true # ========================================================================= # OUTPUT: EventHub output to disallowed namespace → Audit # ========================================================================= - note: audit_output_eventhub_disallowed resource: type: "Microsoft.StreamAnalytics/streamingjobs/outputs" name: "output2" properties: datasource: type: "Microsoft.EventHub/EventHub" Microsoft-ServiceBus-EventHub: serviceBusNamespace: "rogue-namespace" parameters: allowedEventHubNamespaces: - "trusted-namespace" want_effect: "Audit" # ========================================================================= # OUTPUT: SQL output to allowed server → pass # ========================================================================= - note: pass_output_sql_allowed resource: type: "Microsoft.StreamAnalytics/streamingjobs/outputs" name: "output-sql" properties: datasource: type: "Microsoft.Sql/Server/Database" Microsoft-Sql-Server-Database: server: "sql-server-approved" parameters: allowedSQLServers: - "sql-server-approved" want_undefined: true # ========================================================================= # OUTPUT: Blob storage with disallowed account in storageAccounts[*] → Audit # ========================================================================= - note: audit_output_blob_disallowed resource: type: "Microsoft.StreamAnalytics/streamingjobs/outputs" name: "output-blob" properties: datasource: type: "Microsoft.Storage/Blob" Microsoft-Storage-Blob: storageAccounts: - accountName: "rogue-storage" - accountName: "trusted-storage" parameters: allowedStorageAccounts: - "trusted-storage" want_effect: "Audit" # ========================================================================= # OUTPUT: Blob storage with all accounts allowed → pass # ========================================================================= - note: pass_output_blob_all_allowed resource: type: "Microsoft.StreamAnalytics/streamingjobs/outputs" name: "output-blob-ok" properties: datasource: type: "Microsoft.Storage/Blob" Microsoft-Storage-Blob: storageAccounts: - accountName: "trusted-storage" parameters: allowedStorageAccounts: - "trusted-storage" want_undefined: true # ========================================================================= # OUTPUT: SQL output to disallowed server → Audit # ========================================================================= - note: audit_output_sql_disallowed resource: type: "Microsoft.StreamAnalytics/streamingjobs/outputs" name: "output-sql-bad" properties: datasource: type: "Microsoft.Sql/Server/Database" Microsoft-Sql-Server-Database: server: "rogue-sql-server" parameters: allowedSQLServers: - "trusted-sql-server" want_effect: "Audit" # ========================================================================= # OUTPUT: Table output to disallowed account → Audit # ========================================================================= - note: audit_output_table_disallowed resource: type: "Microsoft.StreamAnalytics/streamingjobs/outputs" name: "output-table" properties: datasource: type: "Microsoft.Storage/Table" Microsoft-Storage-Table: accountName: "rogue-storage" parameters: allowedStorageAccounts: - "trusted-storage" want_effect: "Audit" # ========================================================================= # OUTPUT: CosmosDB output to disallowed account → Audit # ========================================================================= - note: audit_output_cosmosdb_disallowed resource: type: "Microsoft.StreamAnalytics/streamingjobs/outputs" name: "output-cosmosdb" properties: datasource: type: "Microsoft.Storage/DocumentDB" Microsoft-Storage-DocumentDB: accountId: "rogue-cosmos-account" parameters: allowedCosmosAccounts: - "trusted-cosmos-account" want_effect: "Audit" # ========================================================================= # OUTPUT: AzureFunction output to disallowed function app → Audit # ========================================================================= - note: audit_output_function_disallowed resource: type: "Microsoft.StreamAnalytics/streamingjobs/outputs" name: "output-function" properties: datasource: type: "Microsoft.AzureFunction" Microsoft-AzureFunction: functionAppName: "rogue-function-app" parameters: allowedAzureFunctionAccounts: - "trusted-function-app" want_effect: "Audit" # ========================================================================= # OUTPUT: Unknown datasource type → Audit (not in known list) # ========================================================================= - note: audit_output_unknown_type resource: type: "Microsoft.StreamAnalytics/streamingjobs/outputs" name: "output-unknown" properties: datasource: type: "Microsoft.SomeNewService/SomeType" want_effect: "Audit" # ========================================================================= # STREAMINGJOB: jobStorageAccount with disallowed account → Audit # ========================================================================= - note: audit_job_storage_disallowed resource: type: "Microsoft.StreamAnalytics/streamingjobs" name: "job1" properties: jobStorageAccount: accountName: "rogue-storage" parameters: allowedStorageAccounts: - "trusted-storage" want_effect: "Audit" # ========================================================================= # STREAMINGJOB: jobStorageAccount with allowed account → pass # ========================================================================= - note: pass_job_storage_allowed resource: type: "Microsoft.StreamAnalytics/streamingjobs" name: "job2" properties: jobStorageAccount: accountName: "trusted-storage" parameters: allowedStorageAccounts: - "trusted-storage" want_undefined: true # ========================================================================= # STREAMINGJOB: no jobStorageAccount → pass (exists "true" fails) # ========================================================================= - note: pass_job_no_storage resource: type: "Microsoft.StreamAnalytics/streamingjobs" name: "job3" properties: {} want_undefined: true # ========================================================================= # Wrong type entirely → pass # ========================================================================= - note: pass_wrong_type resource: type: "Microsoft.Compute/virtualMachines" name: "vm1" properties: {} want_undefined: true