From 0a34c23bbeef23a3519e9d06b7bbf9b4ca4f9245 Mon Sep 17 00:00:00 2001 From: Bhagya lakshmi Kukula Date: Fri, 30 Oct 2026 10:36:11 -0400 Subject: [PATCH] workdayemailactivity --- .../DataConnectionRules.json | 66 +++ .../DataConnectorDefination.json | 108 ++++ .../Workday_Email_CCF/PollerConnector.json | 519 ++++++++++++++++++ .../Workday_Email_CCF/PollingConfig.json | 65 +++ Solutions/Workday_Email_CCF/README.md | 85 +++ .../connection-template.json | 150 +++++ Solutions/Workday_Email_CCF/data.tf | 40 ++ Solutions/Workday_Email_CCF/description.json | 31 ++ .../environment/config.dev.tfbackend | 5 + .../environment/config.nonprod.tfbackend | 5 + .../environment/config.poc.tfbackend | 5 + .../environment/config.prod.tfbackend | 4 + .../environment/dev-north-europe.tfvars | 30 + .../environment/nonprod-north-europe.tfvars | 30 + .../environment/poc-north-europe.tfvars | 33 ++ .../environment/prod-north-europe.tfvars | 30 + Solutions/Workday_Email_CCF/locals.tf | 32 ++ Solutions/Workday_Email_CCF/main.tf | 180 ++++++ Solutions/Workday_Email_CCF/outputs.tf | 44 ++ Solutions/Workday_Email_CCF/providers.tf | 12 + Solutions/Workday_Email_CCF/variables.tf | 103 ++++ Solutions/Workday_Email_CCF/versions.tf | 14 + 22 files changed, 1591 insertions(+) create mode 100644 Solutions/Workday_Email_CCF/DataConnectionRules.json create mode 100644 Solutions/Workday_Email_CCF/DataConnectorDefination.json create mode 100644 Solutions/Workday_Email_CCF/PollerConnector.json create mode 100644 Solutions/Workday_Email_CCF/PollingConfig.json create mode 100644 Solutions/Workday_Email_CCF/README.md create mode 100644 Solutions/Workday_Email_CCF/connection-template.json create mode 100644 Solutions/Workday_Email_CCF/data.tf create mode 100644 Solutions/Workday_Email_CCF/description.json create mode 100644 Solutions/Workday_Email_CCF/environment/config.dev.tfbackend create mode 100644 Solutions/Workday_Email_CCF/environment/config.nonprod.tfbackend create mode 100644 Solutions/Workday_Email_CCF/environment/config.poc.tfbackend create mode 100644 Solutions/Workday_Email_CCF/environment/config.prod.tfbackend create mode 100644 Solutions/Workday_Email_CCF/environment/dev-north-europe.tfvars create mode 100644 Solutions/Workday_Email_CCF/environment/nonprod-north-europe.tfvars create mode 100644 Solutions/Workday_Email_CCF/environment/poc-north-europe.tfvars create mode 100644 Solutions/Workday_Email_CCF/environment/prod-north-europe.tfvars create mode 100644 Solutions/Workday_Email_CCF/locals.tf create mode 100644 Solutions/Workday_Email_CCF/main.tf create mode 100644 Solutions/Workday_Email_CCF/outputs.tf create mode 100644 Solutions/Workday_Email_CCF/providers.tf create mode 100644 Solutions/Workday_Email_CCF/variables.tf create mode 100644 Solutions/Workday_Email_CCF/versions.tf diff --git a/Solutions/Workday_Email_CCF/DataConnectionRules.json b/Solutions/Workday_Email_CCF/DataConnectionRules.json new file mode 100644 index 00000000000..b7925d3f794 --- /dev/null +++ b/Solutions/Workday_Email_CCF/DataConnectionRules.json @@ -0,0 +1,66 @@ +[ + { + "name": "workdayEmailDCR", + "apiVersion": "2021-09-01-preview", + "type": "Microsoft.Insights/dataCollectionRules", + "location": "{{location}}", + "properties": { + "streamDeclarations": { + "Custom-ASimAuditEventLogs": { + "columns": [ + { + "name": "DateTimeStamp", + "type": "string" + }, + { + "name": "EmailIDAfter", + "type": "string" + }, + { + "name": "EmailIDBefore", + "type": "string" + }, + { + "name": "Employee_ID", + "type": "string" + }, + { + "name": "Login_ID", + "type": "string" + }, + { + "name": "TargetID", + "type": "string" + }, + { + "name": "Worker", + "type": "string" + } + ] + } + }, + "dataSources": {}, + "destinations": { + "logAnalytics": [ + { + "workspaceResourceId": "{{workspaceResourceId}}", + "name": "clv2ws1" + } + ] + }, + "dataFlows": [ + { + "streams": [ + "Custom-ASimAuditEventLogs" + ], + "destinations": [ + "clv2ws1" + ], + "transformKql": "source\n| extend TimeGenerated = todatetime(DateTimeStamp), EventStartTime = todatetime(DateTimeStamp), EventEndTime = todatetime(DateTimeStamp)\n| project-rename OldValue = EmailIDBefore, NewValue = EmailIDAfter, ActorUserId = Employee_ID, ActorUsername = Login_ID, EventOriginalUid = TargetID, Object = Worker\n| extend EventCount = toint(1), EventSchema = \"AuditEvent\", EventResult = \"Success\", EventProduct = \"Workday\", EventVendor = \"Workday\", EventSchemaVersion = \"0.1\", ObjectType = \"Other\", EventType = \"Set\", Operation = \"Email Activity\", Dvc = \"Workday\"", + "outputStream": "Microsoft-ASimAuditEventLogs" + } + ], + "dataCollectionEndpointId": "[concat('/subscriptions/',variables('subscriptionID'),'/resourceGroups/',resourceGroup().name,'/providers/Microsoft.Insights/dataCollectionEndpoints/',{{dataCollectionEndpointId}}" + } + } +] diff --git a/Solutions/Workday_Email_CCF/DataConnectorDefination.json b/Solutions/Workday_Email_CCF/DataConnectorDefination.json new file mode 100644 index 00000000000..576efb9b5f1 --- /dev/null +++ b/Solutions/Workday_Email_CCF/DataConnectorDefination.json @@ -0,0 +1,108 @@ +{ + "name": "WorkdayEmailCCPDefinition", + "apiVersion": "2022-09-01-preview", + "type": "Microsoft.SecurityInsights/dataConnectorDefinitions", + "location": "{{location}}", + "kind": "Customizable", + "properties": { + "connectorUiConfig": { + "id": "WorkdayEmailCCPDefinition", + "title": "Workday Email Activity", + "publisher": "Microsoft", + "descriptionMarkdown": "The [Workday](https://www.workday.com/) Email Activity data connector provides the capability to ingest Email Activity reports from [Workday Custom Reports API](https://community.workday.com/sites/default/files/file-hosting/restapi/index.html) into Microsoft Sentinel.", + "graphQueriesTableName": "ASimAuditEventLogs", + "graphQueries": [ + { + "metricName": "Total data received", + "legend": "Workday Email Activity logs", + "baseQuery": "{{graphQueriesTableName}}\n| where EventProduct == \"Workday\" and Operation == \"Email Activity\"" + } + ], + "sampleQueries": [ + { + "description": "Get a sample of Workday Email Activity logs", + "query": "{{graphQueriesTableName}}\n | where EventProduct == \"Workday\" and Operation == \"Email Activity\" | take 10" + } + ], + "dataTypes": [ + { + "name": "{{graphQueriesTableName}}", + "lastDataReceivedQuery": "{{graphQueriesTableName}}\n | where EventProduct == \"Workday\" and Operation == \"Email Activity\" |summarize Time = max (TimeGenerated)\n|where isnotempty(Time)" + } + ], + "availability": { + "isPreview": false + }, + "connectivityCriteria": [ + { + "type": "HasDataConnectors" + } + ], + "permissions": { + "resourceProvider": [ + { + "provider": "Microsoft.OperationalInsights/workspaces", + "permissionsDisplayText": "Read and Write permissions are required.", + "providerDisplayName": "Workspace", + "scope": "Workspace", + "requiredPermissions": { + "write": true, + "read": true, + "delete": true + } + } + ], + "customs": [ + { + "name": "Workday Custom Report API access", + "description": "Access to the Workday Custom Report API through OAuth is required. The API Client needs access to the ISU_MS_Sentinel integration system user and the CR_Sentinel_Email_ID_Change custom report." + } + ] + }, + "instructionSteps": [ + { + "description": "1) In Workday, access the \"Edit Tenant Setup - Security\" task, verify \"OAuth 2.0 Settings\" section, make sure that the \"OAuth 2.0 Clients Enabled\" check box is ticked. \n 2) Access the \"Register API Client\" task.\n 3) Define the Client Name, select the \"Client Grant Type\": \"Authorization Code Grant\" and then select \"Access Token Type\": \"Bearer\"\n 4) Enter the \"Redirection URI\" found in the form below \n 5) In section \"Scope (Functional Areas)\", select the appropriate scope for the custom report and click OK at the bottom \n 6) Copy the Client ID and Client Secret before navigating away from the page, and store it securely. \n 7) In Sentinel, in the connector page - provide required Token, Authorization and Email Activity Report Endpoints, along with Client ID and Client Secret from previous step. Then click \"Connect\". \n", + "instructions": [ + { + "type": "Textbox", + "parameters": { + "label": "Token Endpoint", + "placeholder": "https://wd3-impl-services1.workday.com/ccx/oauth2/stellantis1/token", + "type": "text", + "name": "tokenEndpoint" + } + }, + { + "type": "Textbox", + "parameters": { + "label": "Authorization Endpoint", + "placeholder": "https://wd3-impl.workday.com/stellantis1/authorize?redirect=n", + "type": "text", + "name": "authorizationEndpoint" + } + }, + { + "type": "Textbox", + "parameters": { + "label": "Email Activity Report Endpoint", + "placeholder": "https://wd3-impl-services1.workday.com/ccx/service/customreport2/stellantis1/ISU_MS_Sentinel/CR_Sentinel_Email_ID_Change?format=json", + "type": "text", + "name": "apiEndpoint" + } + }, + { + "type": "OAuthForm", + "parameters": { + "clientIdLabel": "MDMyMTA4YTEtMTliZC00NmVmLTg2MjEtNTIzNmYyZDQ0YzQz", + "clientSecretLabel": "12b8tuixrlokjvgzvvp8stwr4kgz5bmpo93gnypglnfe2zyo3qv8hln1c1c7nhrdvzuja0ihqzfa7ep7y7587xpsd6txugrsib50", + "connectButtonLabel": "Connect", + "disconnectButtonLabel": "Disconnect" + } + } + ], + "title": "Connect to Workday to start collecting Email Activity logs in Microsoft Sentinel" + } + ] + } + } +} diff --git a/Solutions/Workday_Email_CCF/PollerConnector.json b/Solutions/Workday_Email_CCF/PollerConnector.json new file mode 100644 index 00000000000..b9fae98f0fb --- /dev/null +++ b/Solutions/Workday_Email_CCF/PollerConnector.json @@ -0,0 +1,519 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "workspace": { + "defaultValue": "", + "type": "string", + "metadata": { + "description": "Workspace name for Log Analytics where Microsoft Sentinel is setup" + } + } + }, + "variables": { + "DCRName": "WorkdayEmailDCR", + "workspaceResourceId": "[resourceId('microsoft.OperationalInsights/Workspaces', parameters('workspace'))]", + "_solutionName": "Workday Email Activity solution", + "_solutionVersion": "1.0.0", + "_solutionAuthor": "Microsoft", + "_packageIcon": "icon icon icon icon", + "_solutionId": "azuresentinel.azure-sentinel-solution-azuresentinel.azure-sentinel-workday-email", + "dataConnectorVersionConnectorDefinition": "1.0.0", + "dataConnectorVersionConnections": "1.0.0", + "_solutionTier": "Microsoft", + "_dataConnectorContentIdConnectorDefinition": "WorkdayEmailTemplateConnectorDefinition", + "dataConnectorTemplateNameConnectorDefinition": "[concat(parameters('workspace'),'-dc-',uniquestring(variables('_dataConnectorContentIdConnectorDefinition')))]", + "_dataConnectorContentIdConnections": "WorkdayEmailTemplateConnections", + "dataConnectorTemplateNameConnections": "[concat(parameters('workspace'),'-dc-',uniquestring(variables('_dataConnectorContentIdConnections')))]", + "asimTableName": "ASimAuditEventLogs", + "location": "[resourceGroup().location]", + "subscriptionId": "[last(split(subscription().id, '/'))]" + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('dataConnectorTemplateNameConnectorDefinition'), variables('dataConnectorVersionConnectorDefinition'))]", + "location": "[variables('location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "contentId": "[variables('_dataConnectorContentIdConnectorDefinition')]", + "displayName": "[concat(variables('_solutionName'), variables('dataConnectorTemplateNameConnectorDefinition'))]", + "contentKind": "DataConnector", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('dataConnectorVersionConnectorDefinition')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnectorDefinition')))]", + "apiVersion": "2022-01-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "properties": { + "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectorDefinitions', variables('_dataConnectorContentIdConnectorDefinition'))]", + "contentId": "[variables('_dataConnectorContentIdConnectorDefinition')]", + "kind": "DataConnector", + "version": "[variables('dataConnectorVersionConnectorDefinition')]", + "source": { + "sourceId": "[variables('_solutionId')]", + "name": "[variables('_solutionName')]", + "kind": "Solution" + }, + "author": { + "name": "[variables('_solutionAuthor')]" + }, + "support": { + "name": "[variables('_solutionAuthor')]", + "tier": "[variables('_solutionTier')]" + }, + "dependencies": { + "criteria": [ + { + "version": "[variables('dataConnectorVersionConnections')]", + "contentId": "[variables('_dataConnectorContentIdConnections')]", + "kind": "ResourcesDataConnector" + } + ] + } + } + }, + { + "name": "[variables('DCRName')]", + "apiVersion": "2021-09-01-preview", + "type": "Microsoft.Insights/dataCollectionRules", + "location": "[variables('location')]", + "properties": { + "dataCollectionEndpointId": "[concat('/subscriptions/',variables('subscriptionID'),'/resourceGroups/',resourceGroup().name,'/providers/Microsoft.Insights/dataCollectionEndpoints/',parameters('workspace'))]", + "streamDeclarations": { + "[concat('Custom-', variables('asimTableName'))]": { + "columns": [ + { + "name": "DateTimeStamp", + "type": "string" + }, + { + "name": "EmailIDAfter", + "type": "string" + }, + { + "name": "EmailIDBefore", + "type": "string" + }, + { + "name": "Employee_ID", + "type": "string" + }, + { + "name": "Login_ID", + "type": "string" + }, + { + "name": "TargetID", + "type": "string" + }, + { + "name": "Worker", + "type": "string" + } + ] + } + }, + "destinations": { + "logAnalytics": [ + { + "workspaceResourceId": "[variables('workspaceResourceId')]", + "name": "clv2ws1" + } + ] + }, + "dataFlows": [ + { + "streams": [ + "[concat('Custom-', variables('asimTableName'))]" + ], + "destinations": [ + "clv2ws1" + ], + "transformKql": "source\n| extend TimeGenerated = todatetime(DateTimeStamp), EventStartTime = todatetime(DateTimeStamp), EventEndTime = todatetime(DateTimeStamp)\n| project-rename OldValue = EmailIDBefore, NewValue = EmailIDAfter, ActorUserId = Employee_ID, ActorUsername = Login_ID, EventOriginalUid = TargetID, Object = Worker\n| extend EventCount = toint(1), EventSchema = \"AuditEvent\", EventResult = \"Success\", EventProduct = \"Workday\", EventVendor = \"Workday\", EventSchemaVersion = \"0.1\", ObjectType = \"Other\", EventType = \"Set\", Operation = \"Email Activity\", Dvc = \"Workday\"", + "outputStream": "[concat('Microsoft-', variables('asimTableName'))]" + } + ] + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "contentProductId": "[concat(substring(variables('_solutionId'), 0, 50),'-','dc','-', uniqueString(concat(variables('_solutionId'),'-','DataConnector','-',variables('_dataConnectorContentIdConnectorDefinition'),'-', variables('dataConnectorVersionConnectorDefinition'))))]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "version": "[variables('_solutionVersion')]" + } + }, + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',variables('_dataConnectorContentIdConnectorDefinition'))]", + "apiVersion": "2022-09-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectorDefinitions", + "location": "[variables('location')]", + "kind": "Customizable", + "properties": { + "connectorUiConfig": { + "title": "Workday Email Activity (Preview)", + "publisher": "Microsoft", + "descriptionMarkdown": "The [Workday](https://www.workday.com/) Email Activity data connector provides the capability to ingest Email Activity reports from [Workday Custom Reports API](https://community.workday.com/sites/default/files/file-hosting/restapi/index.html) into Microsoft Sentinel.", + "graphQueriesTableName": "ASimAuditEventLogs", + "graphQueries": [ + { + "metricName": "Total data received", + "legend": "Workday Email Activity logs", + "baseQuery": "{{graphQueriesTableName}}\n| where EventProduct == \"Workday\" and Operation == \"Email Activity\"" + } + ], + "sampleQueries": [ + { + "description": "Get a sample of Workday Email Activity logs", + "query": "{{graphQueriesTableName}}\n | where EventProduct == \"Workday\" and Operation == \"Email Activity\" | take 10" + } + ], + "dataTypes": [ + { + "name": "{{graphQueriesTableName}}", + "lastDataReceivedQuery": "{{graphQueriesTableName}}\n | where EventProduct == \"Workday\" and Operation == \"Email Activity\" |summarize Time = max (TimeGenerated)\n|where isnotempty(Time)" + } + ], + "connectivityCriteria": [ + { + "type": "HasDataConnectors" + } + ], + "availability": { + "isPreview": false + }, + "permissions": { + "resourceProvider": [ + { + "provider": "Microsoft.OperationalInsights/workspaces", + "permissionsDisplayText": "Read and Write permissions are required.", + "providerDisplayName": "Workspace", + "scope": "Workspace", + "requiredPermissions": { + "write": true, + "read": true, + "delete": true + } + } + ], + "customs": [ + { + "name": "Workday Custom Report API access", + "description": "Access to the Workday Custom Report API through OAuth is required. The API Client needs access to the ISU_MS_Sentinel integration system user and the CR_Sentinel_Email_ID_Change custom report." + } + ] + }, + "instructionSteps": [ + { + "description": "1) In Workday, access the \"Edit Tenant Setup - Security\" task.\n2) In the \"OAuth 2.0 Settings\" section, select the \"OAuth 2.0 Clients Enabled\" check box.\n3) Access the \"Register API Client\" task.\n4) Enter the Client Name.\n5) Select the \"Client Grant Type\": \"Authorization Code\".\n6) Select the \"Access Token Type\": \"Bearer\".\n7) Enter the \"Redirection URI\": https://portal.azure.com/TokenAuthorize/ExtensionName/Microsoft_Azure_Security_Insights\n8) From the \"Scope (Functional Areas)\" prompt, select the appropriate scope for the custom report.\n9) Copy the Client ID and Secret before navigating away from the page, and store it securely.\n10) Provide the required information below and click \"Connect\".\n", + "instructions": [ + { + "type": "Textbox", + "parameters": { + "label": "Token Endpoint", + "placeholder": "https://wd3-impl-services1.workday.com/ccx/oauth2/{tenantName}/token", + "type": "text", + "name": "tokenEndpoint" + } + }, + { + "type": "Textbox", + "parameters": { + "label": "Authorization Endpoint", + "placeholder": "https://impl.workday.com/{tenantName}/authorize", + "type": "text", + "name": "authorizationEndpoint" + } + }, + { + "type": "Textbox", + "parameters": { + "label": "Email Activity Report Endpoint", + "placeholder": "https://wd3-impl-services1.workday.com/ccx/service/customreport2/{tenantName}/ISU_MS_Sentinel/CR_Sentinel_Email_ID_Change", + "type": "text", + "name": "apiEndpoint" + } + }, + { + "type": "OAuthForm", + "parameters": { + "clientIdLabel": "Client ID", + "clientSecretLabel": "Client Secret", + "connectButtonLabel": "Connect", + "disconnectButtonLabel": "Disconnect" + } + } + ], + "title": "Connect to Workday to start collecting Email Activity logs in Microsoft Sentinel" + } + ] + } + } + }, + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnectorDefinition')))]", + "apiVersion": "2022-01-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "properties": { + "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectorDefinitions', variables('_dataConnectorContentIdConnectorDefinition'))]", + "contentId": "[variables('_dataConnectorContentIdConnectorDefinition')]", + "kind": "DataConnector", + "version": "[variables('dataConnectorVersionConnectorDefinition')]", + "source": { + "sourceId": "[variables('_solutionId')]", + "name": "[variables('_solutionName')]", + "kind": "Solution" + }, + "author": { + "name": "[variables('_solutionAuthor')]" + }, + "support": { + "name": "[variables('_solutionAuthor')]", + "tier": "[variables('_solutionTier')]" + }, + "dependencies": { + "criteria": [ + { + "version": "[variables('dataConnectorVersionConnections')]", + "contentId": "[variables('_dataConnectorContentIdConnections')]", + "kind": "ResourcesDataConnector" + } + ] + } + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('dataConnectorTemplateNameConnections'), variables('dataConnectorVersionConnections'))]", + "location": "[variables('location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "contentId": "[variables('_dataConnectorContentIdConnections')]", + "displayName": "[concat(variables('_solutionName'), variables('dataConnectorTemplateNameConnections'))]", + "contentKind": "ResourcesDataConnector", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('dataConnectorVersionConnections')]", + "parameters": { + "clientSecret": { + "defaultValue": "-NA-", + "type": "string", + "minLength": 1, + "metadata": { + "description": "clientSecret" + } + }, + "clientId": { + "defaultValue": "-NA-", + "type": "string", + "minLength": 1, + "metadata": { + "description": "ClientId" + } + }, + "authorizationCode": { + "defaultValue": "-NA-", + "type": "string", + "minLength": 1, + "metadata": { + "description": "authorization code" + } + }, + "tokenEndpoint": { + "defaultValue": "", + "type": "string", + "metadata": { + "description": "Token endpoint for Workday OAuth 2.0 authentication." + } + }, + "authorizationEndpoint": { + "defaultValue": "", + "type": "string", + "metadata": { + "description": "Authorization endpoint for Workday OAuth 2.0." + } + }, + "apiEndpoint": { + "defaultValue": "https://wd3-impl-services1.workday.com/ccx/service/customreport2/{tenantName}/ISU_MS_Sentinel/CR_Sentinel_Email_ID_Change", + "type": "string", + "metadata": { + "description": "Workday Email Activity Custom Report endpoint." + } + }, + "connectorDefinitionName": { + "defaultValue": "", + "type": "string", + "minLength": 1, + "metadata": { + "description": "connectorDefinitionName" + } + }, + "workspace": { + "defaultValue": "[parameters('workspace')]", + "type": "string" + }, + "dcrConfig": { + "type": "object", + "defaultValue": { + "dataCollectionEndpoint": "data collection Endpoint", + "dataCollectionRuleImmutableId": "data collection rule immutableId" + } + } + }, + "variables": { + "_dataConnectorContentIdConnections": "[variables('_dataConnectorContentIdConnections')]" + }, + "resources": [ + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnections')))]", + "apiVersion": "2022-01-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "properties": { + "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectors', variables('_dataConnectorContentIdConnections'))]", + "contentId": "[variables('_dataConnectorContentIdConnections')]", + "kind": "ResourcesDataConnector", + "version": "[variables('dataConnectorVersionConnections')]", + "source": { + "sourceId": "[variables('_solutionId')]", + "name": "[variables('_solutionName')]", + "kind": "Solution" + }, + "author": { + "name": "[variables('_solutionAuthor')]" + }, + "support": { + "name": "[variables('_solutionAuthor')]", + "tier": "[variables('_solutionTier')]" + } + } + }, + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', 'WorkdayEmail')]", + "apiVersion": "2022-12-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors", + "location": "[variables('location')]", + "kind": "RestApiPoller", + "properties": { + "connectorDefinitionName": "[[parameters('connectorDefinitionName')]", + "dataType": "[variables('asimTableName')]", + "dcrConfig": { + "dataCollectionEndpoint": "[[parameters('dcrConfig').dataCollectionEndpoint]", + "dataCollectionRuleImmutableId": "[[parameters('dcrConfig').dataCollectionRuleImmutableId]", + "streamName": "[concat('Custom-',variables('asimTableName'))]" + }, + "auth": { + "type": "OAuth2", + "ClientSecret": "[[parameters('clientSecret')]", + "ClientId": "[[parameters('clientId')]", + "AuthorizationCode": "[[parameters('authorizationCode')]", + "GrantType": "authorization_code", + "TokenEndpoint": "[[parameters('tokenEndpoint')]", + "tokenEndpointHeaders": { + "Accept": "application/json", + "Content-Type": "application/x-www-form-urlencoded" + }, + "authorizationEndpoint": "[[parameters('authorizationEndpoint')]", + "redirectUri": "https://portal.azure.com/TokenAuthorize/ExtensionName/Microsoft_Azure_Security_Insights" + }, + "request": { + "apiEndpoint": "[[parameters('apiEndpoint')]", + "rateLimitQPS": 10, + "queryWindowInMin": 5, + "httpMethod": "GET", + "retryCount": 3, + "timeoutInSeconds": 60, + "headers": { + "Accept": "application/json" + }, + "StartTimeAttributeName": "After_Date_Time", + "EndTimeAttributeName": "Before_Date_Time", + "queryParameters": { + "After_Date_Time": "{_QueryWindowStartTime}", + "Before_Date_Time": "{_QueryWindowEndTime}", + "format": "json" + } + }, + "paging": { + "pagingType": "Offset", + "pageSize": 1000, + "PageSizeParaName": "limit", + "OffsetParaName": "offset" + }, + "response": { + "eventsJsonPaths": [ + "$.Report_Entry" + ] + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "contentProductId": "[concat(substring(variables('_solutionId'), 0, 50),'-','rdc','-', uniqueString(concat(variables('_solutionId'),'-','ResourcesDataConnector','-',variables('_dataConnectorContentIdConnections'),'-', variables('dataConnectorVersionConnections'))))]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "version": "[variables('_solutionVersion')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentPackages", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('_solutionId'))]", + "location": "[variables('location')]", + "apiVersion": "2023-04-01-preview", + "properties": { + "version": "[variables('_solutionVersion')]", + "kind": "Solution", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_solutionId')]", + "source": { + "kind": "Solution", + "name": "[variables('_solutionName')]", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "[variables('_solutionAuthor')]" + }, + "support": { + "name": "[variables('_solutionAuthor')]" + }, + "dependencies": { + "operator": "AND", + "criteria": [ + { + "kind": "DataConnector", + "contentId": "[variables('dataConnectorVersionConnectorDefinition')]", + "version": "[variables('_dataConnectorContentIdConnectorDefinition')]" + } + ] + }, + "firstPublishDate": "2026-05-13", + "providers": [ + "[variables('_solutionAuthor')]" + ], + "contentKind": "Solution", + "packageId": "[variables('_solutionId')]", + "contentProductId": "[concat(substring(variables('_solutionId'), 0, 50),'-','sl','-', uniqueString(concat(variables('_solutionId'),'-','Solution','-',variables('_solutionId'),'-', variables('_solutionVersion'))))]", + "displayName": "[variables('_solutionName')]", + "publisherDisplayName": "[variables('_solutionId')]", + "descriptionHtml": "Workday Email Activity connector for Microsoft Sentinel", + "icon": "[variables('_packageIcon')]" + } + } + ] +} diff --git a/Solutions/Workday_Email_CCF/PollingConfig.json b/Solutions/Workday_Email_CCF/PollingConfig.json new file mode 100644 index 00000000000..502cc1b27a5 --- /dev/null +++ b/Solutions/Workday_Email_CCF/PollingConfig.json @@ -0,0 +1,65 @@ +[ + { + "name": "WorkdayEmailCCPPolling", + "apiVersion": "2022-10-01-preview", + "type": "Microsoft.SecurityInsights/dataConnectors", + "location": "{{location}}", + "kind": "RestApiPoller", + "properties": { + "connectorDefinitionName":"WorkdayEmailCCPDefinition", + "dcrConfig": { + "dataCollectionEndpoint": "{{dataCollectionEndpoint}}", + "dataCollectionRuleImmutableId": "{{dataCollectionRuleImmutableId}}", + "streamName": "Custom-ASimAuditEventLogs" + }, + "dataType": "Workday Email Activity Logs API", + "response": { + "eventsJsonPaths": [ + "$.Report_Entry" + ] + }, + "paging": { + "pagingType": "Offset", + "pageSize": 100, + "PageSizeParaName": "limit", + "OffsetParaName": "offset" + }, + "auth": { + "type": "OAuth2", + "ClientSecret": "{{clientSecret}}", + "ClientId": "{{clientId}}", + "AuthorizationCode": "{{authorizationCode}}", + "GrantType": "authorization_code", + "TokenEndpoint": "{{tokenEndpoint}}", + "tokenEndpointHeaders": { + "Accept": "application/json", + "Content-Type": "application/x-www-form-urlencoded" + }, + "authorizationEndpoint": "{{authorizationEndpoint}}", + "authorizationEndpointQueryParameters": { + "redirect": "n" + }, + "redirectUri": "{{redirectUri}}" + }, + "request": { + "apiEndpoint": "{{apiEndpoint}}", + "rateLimitQPS": 10, + "queryWindowInMin": "[[int(parameters('queryWindow')[0])]", + "httpMethod": "GET", + "retryCount": 3, + "timeoutInSeconds": 60, + "headers": { + "Accept": "application/json" + }, + "StartTimeAttributeName": "After_Date_Time", + "EndTimeAttributeName": "Before_Date_Time", + "queryParameters": { + "After_Date_Time": "{_QueryWindowStartTime}", + "Before_Date_Time": "{_QueryWindowEndTime}", + "format": "json" + } + }, + "isActive": true + } + } +] diff --git a/Solutions/Workday_Email_CCF/README.md b/Solutions/Workday_Email_CCF/README.md new file mode 100644 index 00000000000..4612d958fc5 --- /dev/null +++ b/Solutions/Workday_Email_CCF/README.md @@ -0,0 +1,85 @@ +# Workday Email ID Change Connector + +This module deploys the Workday Email ID Change data connector to Microsoft Sentinel. It ingests Email ID Change reports from the Workday Custom Report API into the `ASimAuditEventLogs` table using the ASIM Audit Event schema. + +## What This Module Does + +This Terraform module provisions the Workday Email ID Change data connector for Microsoft Sentinel with the following capabilities: + +1. **Deploys the Workday Email Solution** — Registers the content package, connector definition, and connection templates in Microsoft Sentinel via `PollerConnector.json` +2. **Creates Data Collection Resources** — Provisions a Data Collection Endpoint (DCE) and Data Collection Rule (DCR) with KQL transformation to map Workday Email ID Change fields to the ASIM Audit Event schema +3. **Deploys Connector Pollers** — Creates RestApiPoller data connectors that poll the Workday Custom Report API using OAuth 2.0 authorization code flow +4. **Fetches Secrets from Key Vault** — Securely retrieves Client ID and Client Secret from an existing Azure Key Vault +5. **Supports Multiple Environments** — Separate configurations for poc, dev, nonprod, and prod + +## Architecture + +``` +Key Vault (existing) + ├── workday-email-client-id + └── workday-email-client-secret + │ + ▼ +Terraform (main.tf) + ├── ARM Deployment: PollerConnector.json (Solution + Connector Definition) + ├── DCE: Data Collection Endpoint + ├── DCR: Data Collection Rule (KQL transform → ASimAuditEventLogs) + └── ARM Deployment: connection-template.json (RestApiPoller) + │ + ▼ +Workday Custom Report API (CR_Sentinel_Email_ID_Change) → Microsoft Sentinel (ASimAuditEventLogs) +``` + +## Data Mapping (KQL Transform) + +| Workday Field | ASIM Field | Description | +|---|---|---| +| `DateTimeStamp` | `TimeGenerated`, `EventStartTime`, `EventEndTime` | Timestamp of the email change event | +| `EmailIDBefore` | `OldValue` | Previous email address | +| `EmailIDAfter` | `NewValue` | New email address | +| `Employee_ID` | `ActorUserId` | Employee identifier | +| `Login_ID` | `ActorUsername` | Login identifier | +| `TargetID` | `EventOriginalUid` | Workday target object ID | +| `Worker` | `Object` | Worker name whose email was changed | + +Static enrichments: `EventType=Set`, `Operation=Email ID Change`, `EventProduct=Workday`, `EventVendor=Workday`, `EventSchema=AuditEvent`, `EventSchemaVersion=0.1` + +## Directory Structure + +``` +connectors/workday-email/ +├── main.tf # Resource definitions (solution, DCE, DCR, connectors) +├── variables.tf # Variable definitions with validations +├── locals.tf # Local values (naming, computed resource names) +├── data.tf # Data sources (resource group, workspace, Key Vault, secrets) +├── outputs.tf # Output definitions +├── providers.tf # Provider configuration +├── versions.tf # Terraform and provider version constraints +├── PollerConnector.json # ARM template for Workday Email solution deployment +├── connection-template.json # ARM template for RestApiPoller data connectors +├── DataConnectionRules.json # Data connection rules definition +├── DataConnectorDefination.json # Data connector definition +├── PollingConfig.json # Polling configuration +├── description.json # Connector description metadata +├── README.md # This file +└── environment/ # Environment-specific configurations + ├── poc-north-europe.tfvars # POC environment variables + ├── dev-north-europe.tfvars # Development environment variables + ├── nonprod-north-europe.tfvars # Non-production environment variables + ├── prod-north-europe.tfvars # Production environment variables + ├── config.poc.tfbackend # POC backend configuration + ├── config.dev.tfbackend # Dev backend configuration + ├── config.nonprod.tfbackend # Non-prod backend configuration + └── config.prod.tfbackend # Production backend configuration +``` + +## Prerequisites + +- Terraform >= 1.3.0 +- Azure CLI installed and authenticated +- Existing Microsoft Sentinel workspace +- Azure Key Vault with Workday Email API credentials stored as secrets +- Required RBAC permissions: + - **Key Vault Secrets User** — On the Key Vault containing Workday credentials + - **Contributor** — On the resource group containing Microsoft Sentinel + - **Storage Blob Data Contributor** — On the storage account for Terraform state diff --git a/Solutions/Workday_Email_CCF/connection-template.json b/Solutions/Workday_Email_CCF/connection-template.json new file mode 100644 index 00000000000..c9c9ba46068 --- /dev/null +++ b/Solutions/Workday_Email_CCF/connection-template.json @@ -0,0 +1,150 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "workspace": { + "type": "string", + "metadata": { + "description": "Workspace name for Log Analytics where Microsoft Sentinel is setup" + } + }, + "workspace-location": { + "type": "string", + "metadata": { + "description": "Region where the workspace is deployed" + } + }, + "connectorInstanceName": { + "type": "string", + "metadata": { + "description": "Unique identifier for this connector instance" + } + }, + "tokenEndpoint": { + "type": "securestring", + "metadata": { + "description": "Token endpoint for Workday OAuth 2.0 authentication" + } + }, + "authorizationEndpoint": { + "type": "securestring", + "metadata": { + "description": "Authorization endpoint for Workday OAuth 2.0" + } + }, + "apiEndpoint": { + "type": "string", + "metadata": { + "description": "Workday Email Activity Custom Report API endpoint" + } + }, + "clientId": { + "type": "securestring", + "metadata": { + "description": "Workday API Client ID" + } + }, + "clientSecret": { + "type": "securestring", + "metadata": { + "description": "Workday API Client Secret" + } + }, + "authorizationCode": { + "type": "securestring", + "defaultValue": "-NA-", + "metadata": { + "description": "Workday OAuth 2.0 Authorization Code" + } + }, + "queryWindowInMin": { + "type": "int", + "defaultValue": 5, + "metadata": { + "description": "Query window interval in minutes" + } + }, + "dataCollectionEndpoint": { + "type": "string", + "metadata": { + "description": "Data Collection Endpoint URL" + } + }, + "dataCollectionRuleImmutableId": { + "type": "string", + "metadata": { + "description": "Data Collection Rule Immutable ID" + } + } + }, + "variables": { + "connectorDefinitionId": "WorkdayEmailTemplateConnectorDefinition", + "asimTableName": "ASimAuditEventLogs" + }, + "resources": [ + { + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', 'WorkdayEmailPoller-', parameters('connectorInstanceName'))]", + "apiVersion": "2022-12-01-preview", + "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors", + "location": "[parameters('workspace-location')]", + "kind": "RestApiPoller", + "properties": { + "connectorDefinitionName": "[variables('connectorDefinitionId')]", + "dataType": "[variables('asimTableName')]", + "dcrConfig": { + "dataCollectionEndpoint": "[parameters('dataCollectionEndpoint')]", + "dataCollectionRuleImmutableId": "[parameters('dataCollectionRuleImmutableId')]", + "streamName": "[concat('Custom-', variables('asimTableName'))]" + }, + "auth": { + "type": "OAuth2", + "ClientSecret": "[parameters('clientSecret')]", + "ClientId": "[parameters('clientId')]", + "AuthorizationCode": "[parameters('authorizationCode')]", + "GrantType": "authorization_code", + "TokenEndpoint": "[parameters('tokenEndpoint')]", + "tokenEndpointHeaders": { + "Accept": "application/json", + "Content-Type": "application/x-www-form-urlencoded" + }, + "authorizationEndpoint": "[parameters('authorizationEndpoint')]", + "authorizationEndpointQueryParameters": { + "redirect": "n" + }, + "redirectUri": "https://portal.azure.com/TokenAuthorize/ExtensionName/Microsoft_Azure_Security_Insights" + }, + "request": { + "apiEndpoint": "[parameters('apiEndpoint')]", + "rateLimitQPS": 10, + "queryWindowInMin": "[parameters('queryWindowInMin')]", + "httpMethod": "GET", + "retryCount": 3, + "timeoutInSeconds": 60, + "headers": { + "Accept": "application/json" + }, + "StartTimeAttributeName": "After_Date_Time", + "EndTimeAttributeName": "Before_Date_Time", + "queryParameters": { + "After_Date_Time": "{_QueryWindowStartTime}", + "Before_Date_Time": "{_QueryWindowEndTime}", + "format": "json" + } + }, + "paging": { + "pagingType": "Offset", + "pageSize": 100, + "PageSizeParaName": "limit", + "OffsetParaName": "offset" + }, + "response": { + "eventsJsonPaths": [ + "$.Report_Entry" + ], + "format": "json" + }, + "isActive": true + } + } + ] +} diff --git a/Solutions/Workday_Email_CCF/data.tf b/Solutions/Workday_Email_CCF/data.tf new file mode 100644 index 00000000000..ab2b0fd3535 --- /dev/null +++ b/Solutions/Workday_Email_CCF/data.tf @@ -0,0 +1,40 @@ +# ============================================================================= +# Data Sources +# ============================================================================= + +# Data source to get the existing resource group +data "azurerm_resource_group" "sentinel_rg" { + name = local.resource_group_name +} + +# Data source to get the Log Analytics workspace +data "azurerm_log_analytics_workspace" "sentinel" { + name = local.workspace_name + resource_group_name = local.resource_group_name +} + +# Data source to get the Key Vault +data "azurerm_key_vault" "secrets" { + name = var.key_vault_name + resource_group_name = var.key_vault_resource_group != "" ? var.key_vault_resource_group : local.resource_group_name +} + +# Data source to get the existing Workday Data Collection Endpoint (shared with workday connector) +data "azurerm_monitor_data_collection_endpoint" "workday_dce" { + name = local.dce_name + resource_group_name = local.resource_group_name +} + +# Fetch Workday Email Client ID from Key Vault for each connector +data "azurerm_key_vault_secret" "client_id" { + for_each = var.connectors + name = each.value.client_id_secret_name + key_vault_id = data.azurerm_key_vault.secrets.id +} + +# Fetch Workday Email Client Secret from Key Vault for each connector +data "azurerm_key_vault_secret" "client_secret" { + for_each = var.connectors + name = each.value.client_secret_secret_name + key_vault_id = data.azurerm_key_vault.secrets.id +} diff --git a/Solutions/Workday_Email_CCF/description.json b/Solutions/Workday_Email_CCF/description.json new file mode 100644 index 00000000000..b1acac94d0f --- /dev/null +++ b/Solutions/Workday_Email_CCF/description.json @@ -0,0 +1,31 @@ +{ + "connector": "Workday Email Activity", + "deployment_method": "terraform", + "deployment_reason": "Deploys solution skeleton (content package, connector definition, DCE, DCR) via Terraform. Connection is established manually through the Sentinel portal due to OAuth 2.0 authorization code flow requiring browser-based authentication.", + "workspace_region": "north-europe", + "tables": [ + "ASimAuditEventLogs" + ], + "connector_configuration": { + "connector_type": "RestApiPoller (CCP)", + "auth_type": "OAuth 2.0 Authorization Code", + "data_collection_endpoint": "dce-workday-{env}-ne", + "data_collection_rule": "dcr-workday-email-{env}-ne", + "query_window_in_min": 5 + }, + "retention": { + "analytics_tier": { + "retention": "3 months", + "billing": false + }, + "datalake_tier": { + "retention": "12 months" + } + }, + "scope_collected": { + "dev": "Workday Implementation Tenant", + "nonprod": "Workday Production Tenant", + "prod": "Workday Production Tenant" + }, + "deployment_history": [] +} diff --git a/Solutions/Workday_Email_CCF/environment/config.dev.tfbackend b/Solutions/Workday_Email_CCF/environment/config.dev.tfbackend new file mode 100644 index 00000000000..da0a5d2beaa --- /dev/null +++ b/Solutions/Workday_Email_CCF/environment/config.dev.tfbackend @@ -0,0 +1,5 @@ +resource_group_name = "rg-sentinel-tfb-dev" +storage_account_name = "sasentineltfbdev" +container_name = "sc-sentinel-container-dev" +key = "connectors/workday-email/dev.tfstate" +use_azuread_auth = true diff --git a/Solutions/Workday_Email_CCF/environment/config.nonprod.tfbackend b/Solutions/Workday_Email_CCF/environment/config.nonprod.tfbackend new file mode 100644 index 00000000000..35ed2d63f6f --- /dev/null +++ b/Solutions/Workday_Email_CCF/environment/config.nonprod.tfbackend @@ -0,0 +1,5 @@ +resource_group_name = "rg-sentinel-tfb-nonprod" +storage_account_name = "sasentineltfbnonprod2" +container_name = "sc-sentinel-container-nonprod" +key = "connectors/workday-email/nonprod.tfstate" +use_azuread_auth = true diff --git a/Solutions/Workday_Email_CCF/environment/config.poc.tfbackend b/Solutions/Workday_Email_CCF/environment/config.poc.tfbackend new file mode 100644 index 00000000000..c4519612c97 --- /dev/null +++ b/Solutions/Workday_Email_CCF/environment/config.poc.tfbackend @@ -0,0 +1,5 @@ +resource_group_name = "rg-sentinel-tfb-poctest" +storage_account_name = "sasentineltfbpoctest" +container_name = "sc-sentinel-container-poctest" +key = "connectors/workday-email/poc.tfstate" +use_azuread_auth = true diff --git a/Solutions/Workday_Email_CCF/environment/config.prod.tfbackend b/Solutions/Workday_Email_CCF/environment/config.prod.tfbackend new file mode 100644 index 00000000000..d37e11962bf --- /dev/null +++ b/Solutions/Workday_Email_CCF/environment/config.prod.tfbackend @@ -0,0 +1,4 @@ +resource_group_name = "rg-sentinel-tfb-prod" +storage_account_name = "sasentineltfbprod" +container_name = "sc-sentinel-container-prod" +key = "connectors/workday-email/prod.tfstate" diff --git a/Solutions/Workday_Email_CCF/environment/dev-north-europe.tfvars b/Solutions/Workday_Email_CCF/environment/dev-north-europe.tfvars new file mode 100644 index 00000000000..aa46f496415 --- /dev/null +++ b/Solutions/Workday_Email_CCF/environment/dev-north-europe.tfvars @@ -0,0 +1,30 @@ +# Dev environment configuration +environment = "dev" +prefix = "sentinel" +location_short = "ne" + +# location, workspace, and resource_group_name are computed dynamically from +# environment + location passed via -var="location=..." from the pipeline + +tags = { + Environment = "dev" + Project = "azure-sentinel" + Connector = "Workday-Email" +} + +# Key Vault Configuration +key_vault_name = "kv-SOCINFRAD-dev-001" +key_vault_resource_group = "rg-socinfra-dev-001" + +# Workday Email Connector Instances +connectors = { + "workday-email" = { + instance_name = "WorkdayEmail" + token_endpoint = "https://wd3-impl-services1.workday.com/ccx/oauth2/{tenantName}/token" + authorization_endpoint = "https://impl.workday.com/{tenantName}/authorize" + api_endpoint = "https://wd3-impl-services1.workday.com/ccx/service/customreport2/{tenantName}/ISU_MS_Sentinel/CR_Sentinel_Email_ID_Change" + client_id_secret_name = "workday-client-id" + client_secret_secret_name = "workday-client-secret" + query_window_in_min = 5 + } +} diff --git a/Solutions/Workday_Email_CCF/environment/nonprod-north-europe.tfvars b/Solutions/Workday_Email_CCF/environment/nonprod-north-europe.tfvars new file mode 100644 index 00000000000..180021bae5e --- /dev/null +++ b/Solutions/Workday_Email_CCF/environment/nonprod-north-europe.tfvars @@ -0,0 +1,30 @@ +# Nonprod environment configuration +environment = "nonprod" +prefix = "sentinel" +location_short = "ne" + +# location, workspace, and resource_group_name are computed dynamically from +# environment + location passed via -var="location=..." from the pipeline + +tags = { + Environment = "nonprod" + Project = "azure-sentinel" + Connector = "Workday-Email" +} + +# Key Vault Configuration +key_vault_name = "kv-SOCINFRAP-preprod-001" +key_vault_resource_group = "rg-socinfra-preprod-001" + +# Workday Email Connector Instances +connectors = { + "workday-email" = { + instance_name = "WorkdayEmail" + token_endpoint = "https://services1.myworkday.com/ccx/oauth2/{tenantName}/token" + authorization_endpoint = "https://www.myworkday.com/{tenantName}/authorize" + api_endpoint = "https://services1.myworkday.com/ccx/service/customreport2/{tenantName}/ISU_MS_Sentinel/CR_Sentinel_Email_ID_Change" + client_id_secret_name = "workday-client-id" + client_secret_secret_name = "workday-client-secret" + query_window_in_min = 5 + } +} diff --git a/Solutions/Workday_Email_CCF/environment/poc-north-europe.tfvars b/Solutions/Workday_Email_CCF/environment/poc-north-europe.tfvars new file mode 100644 index 00000000000..9da63c1dc27 --- /dev/null +++ b/Solutions/Workday_Email_CCF/environment/poc-north-europe.tfvars @@ -0,0 +1,33 @@ +# POC environment configuration +environment = "poc" +prefix = "sentinel" +location_short = "ne" + +# location, workspace, and resource_group_name are computed dynamically from +# environment + location passed via -var="location=..." from the pipeline + +tags = { + Environment = "poc" + Project = "azure-sentinel" + Connector = "Workday-Email" +} + +# Key Vault Configuration - Use DEV Key Vault +key_vault_name = "kv-SOCINFRAD-dev-001" +key_vault_resource_group = "rg-socinfra-dev-001" + +# Deploy the actual data connector pollers with credentials from Key Vault +deploy_connections = true + +# Workday Email Connector Instances +connectors = { + "workday-email" = { + instance_name = "WorkdayEmail" + token_endpoint = "https://wd3-impl-services1.workday.com/ccx/oauth2/{tenantName}/token" + authorization_endpoint = "https://impl.workday.com/{tenantName}/authorize" + api_endpoint = "https://wd3-impl-services1.workday.com/ccx/service/customreport2/{tenantName}/ISU_MS_Sentinel/CR_Sentinel_Email_ID_Change" + client_id_secret_name = "workday-client-id" + client_secret_secret_name = "workday-client-secret" + query_window_in_min = 5 + } +} diff --git a/Solutions/Workday_Email_CCF/environment/prod-north-europe.tfvars b/Solutions/Workday_Email_CCF/environment/prod-north-europe.tfvars new file mode 100644 index 00000000000..0cf80f29230 --- /dev/null +++ b/Solutions/Workday_Email_CCF/environment/prod-north-europe.tfvars @@ -0,0 +1,30 @@ +# Prod environment configuration +environment = "prd" +prefix = "sentinel" +location_short = "ne" + +# location, workspace, and resource_group_name are computed dynamically from +# environment + location passed via -var="location=..." from the pipeline + +tags = { + Environment = "prod" + Project = "azure-sentinel" + Connector = "Workday-Email" +} + +# Key Vault Configuration +key_vault_name = "kv-SOCINFRA-prod-001" +key_vault_resource_group = "rg-socinfra-prod-001" + +# Workday Email Connector Instances +connectors = { + "workday-email" = { + instance_name = "WorkdayEmail" + token_endpoint = "https://services1.myworkday.com/ccx/oauth2/{tenantName}/token" + authorization_endpoint = "https://www.myworkday.com/{tenantName}/authorize" + api_endpoint = "https://services1.myworkday.com/ccx/service/customreport2/{tenantName}/ISU_MS_Sentinel/CR_Sentinel_Email_ID_Change" + client_id_secret_name = "workday-client-id" + client_secret_secret_name = "workday-client-secret" + query_window_in_min = 5 + } +} diff --git a/Solutions/Workday_Email_CCF/locals.tf b/Solutions/Workday_Email_CCF/locals.tf new file mode 100644 index 00000000000..539f8db08ce --- /dev/null +++ b/Solutions/Workday_Email_CCF/locals.tf @@ -0,0 +1,32 @@ +# ============================================================================= +# Local Values +# ============================================================================= + +locals { + # Format location with hyphens for resource names (same as infrastructure) + formatted_location = replace( + replace( + replace( + replace(var.location, "francecentral", "france-central"), + "eastus", "east-us" + ), + "northeurope", "north-europe" + ), + "westeurope", "west-europe" + ) + + # Compute resource names if not provided (must match infrastructure naming) + computed_workspace_name = "${var.prefix}-${var.environment}-${local.formatted_location}" + computed_resource_group = "${var.prefix}-rg-${var.environment}-${local.formatted_location}" + + # Use provided values or fall back to computed + workspace_name = var.workspace != "" ? var.workspace : local.computed_workspace_name + resource_group_name = var.resource_group_name != "" ? var.resource_group_name : local.computed_resource_group + + # Reference the existing Workday DCE (shared with workday connector) + dce_name = var.data_collection_endpoint_name != "" ? var.data_collection_endpoint_name : "dce-workday-${var.environment}-${var.location_short}" + dcr_name = var.data_collection_rule_name != "" ? var.data_collection_rule_name : "dcr-workday-email-${var.environment}-${var.location_short}" + + # Use location from the actual workspace (DCR must be in same region as workspace) + actual_workspace_location = data.azurerm_log_analytics_workspace.sentinel.location +} diff --git a/Solutions/Workday_Email_CCF/main.tf b/Solutions/Workday_Email_CCF/main.tf new file mode 100644 index 00000000000..b6a1a0870c1 --- /dev/null +++ b/Solutions/Workday_Email_CCF/main.tf @@ -0,0 +1,180 @@ +# ============================================================================= +# Workday Email Activity Sentinel Connector - Resource Definitions +# ============================================================================= +# File layout: +# providers.tf -> Provider configuration +# locals.tf -> Local values (naming, computed resource names) +# data.tf -> Data sources (resource group, workspace, Key Vault, secrets) +# variables.tf -> Input variables +# outputs.tf -> Output values +# versions.tf -> Required providers and versions +# main.tf -> Resource definitions (this file) +# ============================================================================= + +# -------------------------------------------------------------------------- +# Deploy the Workday Email Solution ARM Template (PollerConnector.json) +# This registers the content package, connector definition, DCR, and +# connection templates in Microsoft Sentinel. +# -------------------------------------------------------------------------- + +resource "azurerm_resource_group_template_deployment" "workday_email_solution" { + name = "workday-email-solution-deployment" + resource_group_name = data.azurerm_resource_group.sentinel_rg.name + deployment_mode = "Incremental" + template_content = file("${path.module}/PollerConnector.json") + + parameters_content = jsonencode({ + "workspace" = { + value = local.workspace_name + } + }) + + tags = var.tags + + lifecycle { + ignore_changes = [template_content] + } +} + +# -------------------------------------------------------------------------- +# Data Collection Rule for Workday Email Activity +# Maps raw Workday custom report fields to ASIM AuditEvent schema via KQL +# -------------------------------------------------------------------------- + +resource "azurerm_monitor_data_collection_rule" "workday_email" { + for_each = var.create_data_collection_resources ? var.connectors : {} + name = "${local.dcr_name}" + resource_group_name = data.azurerm_resource_group.sentinel_rg.name + location = local.actual_workspace_location + description = "Data Collection Rule for Workday Email Activity ${each.value.instance_name} Connector" + + tags = merge(var.tags, { + createdBy = "Sentinel" + }) + + data_collection_endpoint_id = data.azurerm_monitor_data_collection_endpoint.workday_dce.id + + # Declare the incoming custom stream with Workday Email Activity report columns + stream_declaration { + stream_name = "Custom-ASimAuditEventLogs" + column { + name = "DateTimeStamp" + type = "string" + } + column { + name = "EmailIDAfter" + type = "string" + } + column { + name = "EmailIDBefore" + type = "string" + } + column { + name = "Employee_ID" + type = "string" + } + column { + name = "Login_ID" + type = "string" + } + column { + name = "TargetID" + type = "string" + } + column { + name = "Worker" + type = "string" + } + } + + destinations { + log_analytics { + workspace_resource_id = data.azurerm_log_analytics_workspace.sentinel.id + name = "clv2ws1" + } + } + + data_flow { + streams = ["Custom-ASimAuditEventLogs"] + destinations = ["clv2ws1"] + transform_kql = <<-KQL + source + | extend TimeGenerated = todatetime(DateTimeStamp), EventStartTime = todatetime(DateTimeStamp), EventEndTime = todatetime(DateTimeStamp) + | project-rename OldValue = EmailIDBefore, NewValue = EmailIDAfter, ActorUserId = Employee_ID, ActorUsername = Login_ID, EventOriginalUid = TargetID, Object = Worker + | extend EventCount = toint(1), EventSchema = "AuditEvent", EventResult = "Success", EventProduct = "Workday", EventVendor = "Workday", EventSchemaVersion = "0.1", ObjectType = "Other", EventType = "Set", Operation = "Email Activity", Dvc = "Workday" + KQL + output_stream = "Microsoft-ASimAuditEventLogs" + } +} + +# -------------------------------------------------------------------------- +# Deploy Workday Email Data Connector Pollers (RestApiPoller resources) +# These are the actual connectors that poll the Workday Custom Report API +# -------------------------------------------------------------------------- + +resource "azurerm_resource_group_template_deployment" "workday_email_connection" { + for_each = var.deploy_connections ? var.connectors : {} + name = "workday-email-connection-${each.key}" + resource_group_name = data.azurerm_resource_group.sentinel_rg.name + deployment_mode = "Incremental" + + template_content = templatefile("${path.module}/connection-template.json", {}) + + parameters_content = jsonencode({ + "workspace" = { + value = local.workspace_name + } + "workspace-location" = { + value = local.actual_workspace_location + } + "connectorInstanceName" = { + value = each.value.instance_name + } + "tokenEndpoint" = { + value = each.value.token_endpoint + } + "authorizationEndpoint" = { + value = each.value.authorization_endpoint + } + "apiEndpoint" = { + value = each.value.api_endpoint + } + "clientId" = { + value = data.azurerm_key_vault_secret.client_id[each.key].value + } + "clientSecret" = { + value = data.azurerm_key_vault_secret.client_secret[each.key].value + } + "authorizationCode" = { + value = "-NA-" + } + "queryWindowInMin" = { + value = each.value.query_window_in_min + } + "dataCollectionEndpoint" = { + value = data.azurerm_monitor_data_collection_endpoint.workday_dce.logs_ingestion_endpoint + } + "dataCollectionRuleImmutableId" = { + value = azurerm_monitor_data_collection_rule.workday_email[each.key].immutable_id + } + }) + + tags = var.tags + + lifecycle { + precondition { + condition = data.azurerm_key_vault_secret.client_id[each.key].value != null && data.azurerm_key_vault_secret.client_id[each.key].value != "" + error_message = "Client ID for connector '${each.key}' is null or empty. Check Key Vault secret '${each.value.client_id_secret_name}'." + } + precondition { + condition = data.azurerm_key_vault_secret.client_secret[each.key].value != null && data.azurerm_key_vault_secret.client_secret[each.key].value != "" + error_message = "Client Secret for connector '${each.key}' is null or empty. Check Key Vault secret '${each.value.client_secret_secret_name}'." + } + + } + + depends_on = [ + azurerm_resource_group_template_deployment.workday_email_solution, + azurerm_monitor_data_collection_rule.workday_email + ] +} diff --git a/Solutions/Workday_Email_CCF/outputs.tf b/Solutions/Workday_Email_CCF/outputs.tf new file mode 100644 index 00000000000..50db2f3be48 --- /dev/null +++ b/Solutions/Workday_Email_CCF/outputs.tf @@ -0,0 +1,44 @@ +output "solution_deployment_id" { + description = "The ID of the Workday Email solution ARM template deployment" + value = azurerm_resource_group_template_deployment.workday_email_solution.id +} + +output "solution_deployment_name" { + description = "The name of the Workday Email solution ARM template deployment" + value = azurerm_resource_group_template_deployment.workday_email_solution.name +} + +output "connection_deployment_ids" { + description = "The IDs of the Workday Email connection ARM template deployments" + value = { for k, v in azurerm_resource_group_template_deployment.workday_email_connection : k => v.id } +} + +output "connection_deployment_names" { + description = "The names of the Workday Email connection ARM template deployments" + value = { for k, v in azurerm_resource_group_template_deployment.workday_email_connection : k => v.name } +} + +output "connectors_deployed" { + description = "List of connector instance names deployed" + value = [for k, v in var.connectors : v.instance_name] +} + +output "data_collection_endpoint_id" { + description = "The ID of the existing Workday Data Collection Endpoint (shared)" + value = data.azurerm_monitor_data_collection_endpoint.workday_dce.id +} + +output "data_collection_endpoint_url" { + description = "The logs ingestion endpoint URL" + value = data.azurerm_monitor_data_collection_endpoint.workday_dce.logs_ingestion_endpoint +} + +output "data_collection_rule_ids" { + description = "The IDs of the Data Collection Rules" + value = var.create_data_collection_resources ? { for k, v in azurerm_monitor_data_collection_rule.workday_email : k => v.id } : {} +} + +output "data_collection_rule_immutable_ids" { + description = "The immutable IDs of the Data Collection Rules" + value = var.create_data_collection_resources ? { for k, v in azurerm_monitor_data_collection_rule.workday_email : k => v.immutable_id } : {} +} diff --git a/Solutions/Workday_Email_CCF/providers.tf b/Solutions/Workday_Email_CCF/providers.tf new file mode 100644 index 00000000000..2f54ceca160 --- /dev/null +++ b/Solutions/Workday_Email_CCF/providers.tf @@ -0,0 +1,12 @@ +# ============================================================================= +# Provider Configuration +# ============================================================================= + +provider "azurerm" { + features { + resource_group { + prevent_deletion_if_contains_resources = false + } + } + subscription_id = var.subscription_id +} diff --git a/Solutions/Workday_Email_CCF/variables.tf b/Solutions/Workday_Email_CCF/variables.tf new file mode 100644 index 00000000000..9aed748aa64 --- /dev/null +++ b/Solutions/Workday_Email_CCF/variables.tf @@ -0,0 +1,103 @@ +variable "location" { + description = "Azure region for deployment" + type = string + default = "francecentral" +} + +variable "location_short" { + description = "Short code for the Azure region (e.g., ne for northeurope, eu for eastus)" + type = string + default = "ne" +} + +variable "environment" { + description = "Environment name (e.g., poc, nonprod, prod)" + type = string + default = "poc" +} + +variable "prefix" { + description = "Prefix for resource names" + type = string + default = "sentinel" +} + +variable "workspace" { + description = "Workspace name for Log Analytics where Microsoft Sentinel is setup. If empty, computed from location and environment." + type = string + default = "" +} + +variable "resource_group_name" { + description = "Resource group name where Microsoft Sentinel is setup. If empty, computed from location and environment." + type = string + default = "" +} + +variable "subscription_id" { + description = "Subscription ID where Microsoft Sentinel is setup" + type = string +} + +variable "connectors" { + description = "Map of Workday Email Activity connector instances to deploy" + type = map(object({ + instance_name = string + token_endpoint = string + authorization_endpoint = string + api_endpoint = string + client_id_secret_name = string + client_secret_secret_name = string + query_window_in_min = optional(number, 5) + })) + + validation { + condition = alltrue([ + for k, v in var.connectors : length(v.instance_name) >= 1 && length(v.instance_name) <= 20 + ]) + error_message = "Each connector instance_name must be between 1 and 20 characters long." + } +} + +variable "tags" { + description = "Tags to apply to deployed resources" + type = map(string) + default = {} +} + +# Key Vault configuration for secrets +variable "key_vault_name" { + description = "Name of the Azure Key Vault containing Workday Email secrets" + type = string +} + +variable "key_vault_resource_group" { + description = "Resource group of the Azure Key Vault. If not specified, uses the same resource group as the deployment." + type = string + default = "" +} + +# Data Collection configuration +variable "create_data_collection_resources" { + description = "Whether to create DCE and DCR resources. Set to false if they already exist." + type = bool + default = true +} + +variable "deploy_connections" { + description = "Whether to deploy the Workday Email data connector pollers (RestApiPoller resources). Set to true to deploy connections with credentials from Key Vault." + type = bool + default = false +} + +variable "data_collection_endpoint_name" { + description = "Name of the existing Data Collection Endpoint (shared with workday connector). If not specified, defaults to dce-workday-{env}-{location}." + type = string + default = "" +} + +variable "data_collection_rule_name" { + description = "Name of the Data Collection Rule. If not specified, defaults to dcr-workday-email-{env}-{location}." + type = string + default = "" +} diff --git a/Solutions/Workday_Email_CCF/versions.tf b/Solutions/Workday_Email_CCF/versions.tf new file mode 100644 index 00000000000..747ab4cf13c --- /dev/null +++ b/Solutions/Workday_Email_CCF/versions.tf @@ -0,0 +1,14 @@ +terraform { + required_version = ">= 1.3.0" + + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = ">= 4.0.0" + } + } + + backend "azurerm" { + # Backend configuration provided via -backend-config flag + } +}