From 1077ec729497616dfff806368d437532a057e9a6 Mon Sep 17 00:00:00 2001 From: Guy Afik <53861351+GuyAfik@users.noreply.github.com> Date: Tue, 20 Jun 2023 18:56:05 +0300 Subject: [PATCH 1/9] [TestIsMaliciousIndicatorFound] - add sleep for indexing indicators (#27584) --- .../playbook-TestIsMaliciousIndicatorFound.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Packs/CommonScripts/TestPlaybooks/playbook-TestIsMaliciousIndicatorFound.yml b/Packs/CommonScripts/TestPlaybooks/playbook-TestIsMaliciousIndicatorFound.yml index 6f0b23cb9eaa..2612fc9484ef 100644 --- a/Packs/CommonScripts/TestPlaybooks/playbook-TestIsMaliciousIndicatorFound.yml +++ b/Packs/CommonScripts/TestPlaybooks/playbook-TestIsMaliciousIndicatorFound.yml @@ -1345,7 +1345,7 @@ tasks: - "35" scriptarguments: seconds: - simple: "4" + simple: "8" separatecontext: false view: |- { @@ -1413,7 +1413,7 @@ tasks: - "37" scriptarguments: seconds: - simple: "4" + simple: "8" separatecontext: false view: |- { @@ -1480,7 +1480,7 @@ tasks: - "39" scriptarguments: seconds: - simple: "4" + simple: "8" separatecontext: false view: |- { @@ -1547,7 +1547,7 @@ tasks: - "41" scriptarguments: seconds: - simple: "4" + simple: "8" separatecontext: false view: |- { @@ -1842,7 +1842,7 @@ tasks: - "46" scriptarguments: seconds: - simple: "4" + simple: "8" separatecontext: false view: |- { From db1ebc1da7b3c4aac4e182ed34084c1da9be9a14 Mon Sep 17 00:00:00 2001 From: Koby Meir Date: Tue, 20 Jun 2023 21:25:37 +0300 Subject: [PATCH 2/9] Microsoft usgov support (#27025) https://jira-hq.paloaltonetworks.local/browse/CIAC-818 Adding support for All Azure clouds in Azure Key Vault, Azure Sentinel, Azure Kubernetes Service Adding support for all endpoints in Microsoft Defender for Endpoints --- Packs/ApiModules/.secrets-ignore | 9 +- .../MicrosoftApiModule/MicrosoftApiModule.py | 604 ++++++++++++- .../MicrosoftApiModule/MicrosoftApiModule.yml | 2 +- .../MicrosoftApiModule_test.py | 38 +- Packs/AzureKeyVault/.pack-ignore | 76 ++ Packs/AzureKeyVault/.secrets-ignore | 9 +- .../AzureKeyVault/AzureKeyVault.py | 97 ++- .../AzureKeyVault/AzureKeyVault.yml | 27 +- .../Integrations/AzureKeyVault/README.md | 179 ++-- Packs/AzureKeyVault/ReleaseNotes/1_1_20.md | 7 + Packs/AzureKeyVault/pack_metadata.json | 2 +- Packs/AzureKubernetesServices/.pack-ignore | 19 +- .../AzureKubernetesServices.py | 39 +- .../AzureKubernetesServices.yml | 68 +- .../AzureKubernetesServices_test.py | 5 +- .../AzureKubernetesServices/README.md | 86 +- .../ReleaseNotes/1_1_13.md | 11 + .../pack_metadata.json | 2 +- Packs/AzureSentinel/.pack-ignore | 49 ++ Packs/AzureSentinel/.secrets-ignore | 7 +- .../AzureSentinel/AzureSentinel.py | 153 ++-- .../AzureSentinel/AzureSentinel.yml | 54 +- .../AzureSentinel/AzureSentinel_test.py | 135 ++- .../Integrations/AzureSentinel/README.md | 378 +++++--- Packs/AzureSentinel/ReleaseNotes/1_5_8.md | 2 +- Packs/AzureSentinel/ReleaseNotes/1_5_9.md | 9 + Packs/AzureSentinel/pack_metadata.json | 2 +- .../.pack-ignore | 54 +- .../.secrets-ignore | 7 + .../Microsoft365DefenderEventCollector.py | 61 +- .../Microsoft365DefenderEventCollector.yml | 60 +- ...Microsoft365DefenderEventCollector_test.py | 31 +- .../README.md | 50 +- ...crosoftDefenderAdvancedThreatProtection.py | 256 +++--- ...rosoftDefenderAdvancedThreatProtection.yml | 50 +- ...ftDefenderAdvancedThreatProtection_test.py | 45 +- .../README.md | 809 +++++++++++++++--- .../README.md | 23 + .../ReleaseNotes/1_15_27.md | 12 + .../pack_metadata.json | 2 +- 40 files changed, 2720 insertions(+), 809 deletions(-) create mode 100644 Packs/AzureKeyVault/ReleaseNotes/1_1_20.md create mode 100644 Packs/AzureKubernetesServices/ReleaseNotes/1_1_13.md create mode 100644 Packs/AzureSentinel/ReleaseNotes/1_5_9.md create mode 100644 Packs/MicrosoftDefenderAdvancedThreatProtection/ReleaseNotes/1_15_27.md diff --git a/Packs/ApiModules/.secrets-ignore b/Packs/ApiModules/.secrets-ignore index 768fc3cde7b8..e02ca5b3bbba 100644 --- a/Packs/ApiModules/.secrets-ignore +++ b/Packs/ApiModules/.secrets-ignore @@ -1766,4 +1766,11 @@ dummy2@gmail.com dummy3@gmail.com dummy4@gmail.com dummy5@gmail.com -user1@dummy.com \ No newline at end of file +user1@dummy.com +https://gallery.azure.com +https://management.core.windows.net +https://portal.azure.cn +https://portal.azure.com +https://portal.azure.us +https://vault.azure.cn +https://vault.azure.net diff --git a/Packs/ApiModules/Scripts/MicrosoftApiModule/MicrosoftApiModule.py b/Packs/ApiModules/Scripts/MicrosoftApiModule/MicrosoftApiModule.py index ce6f1d0e9d8c..0613da0d7d69 100644 --- a/Packs/ApiModules/Scripts/MicrosoftApiModule/MicrosoftApiModule.py +++ b/Packs/ApiModules/Scripts/MicrosoftApiModule/MicrosoftApiModule.py @@ -15,13 +15,13 @@ class Scopes: graph = 'https://graph.microsoft.com/.default' security_center = 'https://api.securitycenter.windows.com/.default' security_center_apt_service = 'https://securitycenter.onmicrosoft.com/windowsatpservice/.default' - management_azure = 'https://management.azure.com/.default' + management_azure = 'https://management.azure.com/.default' # resource_manager class Resources: graph = 'https://graph.microsoft.com/' security_center = 'https://api.securitycenter.microsoft.com/' - management_azure = 'https://management.azure.com/' + management_azure = 'https://management.azure.com/' # resource_manager manage_office = 'https://manage.office.com/' @@ -36,33 +36,567 @@ class Resources: DEVICE_CODE = 'urn:ietf:params:oauth:grant-type:device_code' REGEX_SEARCH_URL = r'(?Phttps?://[^\s]+)' SESSION_STATE = 'session_state' + +# Deprecated, prefer using AZURE_CLOUDS TOKEN_RETRIEVAL_ENDPOINTS = { 'com': 'https://login.microsoftonline.com', + 'gcc': 'https://login.microsoftonline.us', 'gcc-high': 'https://login.microsoftonline.us', 'dod': 'https://login.microsoftonline.us', 'de': 'https://login.microsoftonline.de', 'cn': 'https://login.chinacloudapi.cn', } + +# Deprecated, prefer using AZURE_CLOUDS GRAPH_ENDPOINTS = { 'com': 'https://graph.microsoft.com', + 'gcc': 'https://graph.microsoft.us', 'gcc-high': 'https://graph.microsoft.us', 'dod': 'https://dod-graph.microsoft.us', 'de': 'https://graph.microsoft.de', 'cn': 'https://microsoftgraph.chinacloudapi.cn' } + +# Deprecated, prefer using AZURE_CLOUDS GRAPH_BASE_ENDPOINTS = { 'https://graph.microsoft.com': 'com', + # can't create an entry here for 'gcc' as the url is the same for both 'gcc' and 'gcc-high' 'https://graph.microsoft.us': 'gcc-high', 'https://dod-graph.microsoft.us': 'dod', 'https://graph.microsoft.de': 'de', 'https://microsoftgraph.chinacloudapi.cn': 'cn' } +MICROSOFT_DEFENDER_FOR_ENDPOINT_TYPE = { + "Worldwide": "com", + "US Geo Proximity": "geo-us", + "EU Geo Proximity": "geo-eu", + "UK Geo Proximity": "geo-uk", + "US GCC": "gcc", + "US GCC-High": "gcc-high", + "DoD": "dod", +} + +MICROSOFT_DEFENDER_FOR_ENDPOINT_TYPE_CUSTOM = "Custom" +MICROSOFT_DEFENDER_FOR_ENDPOINT_DEFAULT_ENDPOINT_TYPE = "com" + +# https://learn.microsoft.com/en-us/microsoft-365/security/defender/api-supported?view=o365-worldwide#endpoint-uris +# https://learn.microsoft.com/en-us/microsoft-365/security/defender-endpoint/gov?view=o365-worldwide#api +MICROSOFT_DEFENDER_FOR_ENDPOINT_API = { + "com": "https://api.securitycenter.microsoft.com", + "geo-us": "https://api.securitycenter.microsoft.com", + "geo-eu": "https://api-eu.securitycenter.microsoft.com", + "geo-uk": "https://api-uk.securitycenter.microsoft.com", + "gcc": "https://api-gcc.securitycenter.microsoft.us", + "gcc-high": "https://api-gcc.securitycenter.microsoft.us", + "dod": "https://api-gov.securitycenter.microsoft.us", +} + +# https://learn.microsoft.com/en-us/graph/deployments#app-registration-and-token-service-root-endpoints +MICROSOFT_DEFENDER_FOR_ENDPOINT_TOKEN_RETRIVAL_ENDPOINTS = { + 'com': 'https://login.microsoftonline.com', + 'geo-us': 'https://login.microsoftonline.com', + 'geo-eu': 'https://login.microsoftonline.com', + 'geo-uk': 'https://login.microsoftonline.com', + 'gcc': 'https://login.microsoftonline.us', + 'gcc-high': 'https://login.microsoftonline.us', + 'dod': 'https://login.microsoftonline.us', +} + +# https://learn.microsoft.com/en-us/graph/deployments#microsoft-graph-and-graph-explorer-service-root-endpoints +MICROSOFT_DEFENDER_FOR_ENDPOINT_GRAPH_ENDPOINTS = { + 'com': 'https://graph.microsoft.com', + 'geo-us': 'https://graph.microsoft.com', + 'geo-eu': 'https://graph.microsoft.com', + 'geo-uk': 'https://graph.microsoft.com', + 'gcc': 'https://graph.microsoft.com', + 'gcc-high': 'https://graph.microsoft.us', + 'dod': 'https://dod-graph.microsoft.us', +} + +MICROSOFT_DEFENDER_FOR_ENDPOINT_APT_SERVICE_ENDPOINTS = { + 'com': 'https://securitycenter.onmicrosoft.com', + 'geo-us': 'https://securitycenter.onmicrosoft.com', + 'geo-eu': 'https://securitycenter.onmicrosoft.com', + 'geo-uk': 'https://securitycenter.onmicrosoft.com', + 'gcc': 'https://securitycenter.onmicrosoft.us', + 'gcc-high': 'https://securitycenter.onmicrosoft.us', + 'dod': 'https://securitycenter.onmicrosoft.us', +} + # Azure Managed Identities MANAGED_IDENTITIES_TOKEN_URL = 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01' MANAGED_IDENTITIES_SYSTEM_ASSIGNED = 'SYSTEM_ASSIGNED' +class CloudEndpointNotSetException(Exception): + pass + + +class CloudSuffixNotSetException(Exception): + pass + + +class AzureCloudEndpoints: # pylint: disable=too-few-public-methods,too-many-instance-attributes + + def __init__(self, # pylint: disable=unused-argument + management=None, + resource_manager=None, + sql_management=None, + batch_resource_id=None, + gallery=None, + active_directory=None, + active_directory_resource_id=None, + active_directory_graph_resource_id=None, + microsoft_graph_resource_id=None, + active_directory_data_lake_resource_id=None, + vm_image_alias_doc=None, + media_resource_id=None, + ossrdbms_resource_id=None, + log_analytics_resource_id=None, + app_insights_resource_id=None, + app_insights_telemetry_channel_resource_id=None, + synapse_analytics_resource_id=None, + attestation_resource_id=None, + portal=None, + keyvault=None): + # Attribute names are significant. They are used when storing/retrieving clouds from config + self.management = management + self.resource_manager = resource_manager + self.sql_management = sql_management + self.batch_resource_id = batch_resource_id + self.gallery = gallery + self.active_directory = active_directory + self.active_directory_resource_id = active_directory_resource_id + self.active_directory_graph_resource_id = active_directory_graph_resource_id + self.microsoft_graph_resource_id = microsoft_graph_resource_id + self.active_directory_data_lake_resource_id = active_directory_data_lake_resource_id + self.vm_image_alias_doc = vm_image_alias_doc + self.media_resource_id = media_resource_id + self.ossrdbms_resource_id = ossrdbms_resource_id + self.log_analytics_resource_id = log_analytics_resource_id + self.app_insights_resource_id = app_insights_resource_id + self.app_insights_telemetry_channel_resource_id = app_insights_telemetry_channel_resource_id + self.synapse_analytics_resource_id = synapse_analytics_resource_id + self.attestation_resource_id = attestation_resource_id + self.portal = portal + self.keyvault = keyvault + + def has_endpoint_set(self, endpoint_name): + try: + # Can't simply use hasattr here as we override __getattribute__ below. + # Python 3 hasattr() only returns False if an AttributeError is raised, but we raise + # CloudEndpointNotSetException. This exception is not a subclass of AttributeError. + getattr(self, endpoint_name) + return True + except Exception: # pylint: disable=broad-except + return False + + def __getattribute__(self, name): + val = object.__getattribute__(self, name) + if val is None: + raise CloudEndpointNotSetException("The endpoint '{}' for this cloud is not set but is used.") + return val + + +class AzureCloudSuffixes: # pylint: disable=too-few-public-methods,too-many-instance-attributes + + def __init__(self, # pylint: disable=unused-argument + storage_endpoint=None, + storage_sync_endpoint=None, + keyvault_dns=None, + mhsm_dns=None, + sql_server_hostname=None, + azure_datalake_store_file_system_endpoint=None, + azure_datalake_analytics_catalog_and_job_endpoint=None, + acr_login_server_endpoint=None, + mysql_server_endpoint=None, + postgresql_server_endpoint=None, + mariadb_server_endpoint=None, + synapse_analytics_endpoint=None, + attestation_endpoint=None): + # Attribute names are significant. They are used when storing/retrieving clouds from config + self.storage_endpoint = storage_endpoint + self.storage_sync_endpoint = storage_sync_endpoint + self.keyvault_dns = keyvault_dns + self.mhsm_dns = mhsm_dns + self.sql_server_hostname = sql_server_hostname + self.mysql_server_endpoint = mysql_server_endpoint + self.postgresql_server_endpoint = postgresql_server_endpoint + self.mariadb_server_endpoint = mariadb_server_endpoint + self.azure_datalake_store_file_system_endpoint = azure_datalake_store_file_system_endpoint + self.azure_datalake_analytics_catalog_and_job_endpoint = azure_datalake_analytics_catalog_and_job_endpoint + self.acr_login_server_endpoint = acr_login_server_endpoint + self.synapse_analytics_endpoint = synapse_analytics_endpoint + self.attestation_endpoint = attestation_endpoint + + def __getattribute__(self, name): + val = object.__getattribute__(self, name) + if val is None: + raise CloudSuffixNotSetException("The suffix '{}' for this cloud is not set but is used.") + return val + + +class AzureCloud: # pylint: disable=too-few-public-methods + """ Represents an Azure Cloud instance """ + + def __init__(self, + origin, + name, + abbreviation, + endpoints=None, + suffixes=None): + self.name = name + self.abbreviation = abbreviation + self.origin = origin + self.endpoints = endpoints or AzureCloudEndpoints() + self.suffixes = suffixes or AzureCloudSuffixes() + + +AZURE_WORLDWIDE_CLOUD = AzureCloud( + 'Embedded', + 'AzureCloud', + 'com', + endpoints=AzureCloudEndpoints( + management='https://management.core.windows.net/', + resource_manager='https://management.azure.com/', + sql_management='https://management.core.windows.net:8443/', + batch_resource_id='https://batch.core.windows.net/', + gallery='https://gallery.azure.com/', + active_directory='https://login.microsoftonline.com', + active_directory_resource_id='https://management.core.windows.net/', + active_directory_graph_resource_id='https://graph.windows.net/', + microsoft_graph_resource_id='https://graph.microsoft.com/', + active_directory_data_lake_resource_id='https://datalake.azure.net/', + vm_image_alias_doc='https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/arm-compute/quickstart-templates/aliases.json', # noqa: E501 + media_resource_id='https://rest.media.azure.net', + ossrdbms_resource_id='https://ossrdbms-aad.database.windows.net', + app_insights_resource_id='https://api.applicationinsights.io', + log_analytics_resource_id='https://api.loganalytics.io', + app_insights_telemetry_channel_resource_id='https://dc.applicationinsights.azure.com/v2/track', + synapse_analytics_resource_id='https://dev.azuresynapse.net', + attestation_resource_id='https://attest.azure.net', + portal='https://portal.azure.com', + keyvault='https://vault.azure.net', + ), + suffixes=AzureCloudSuffixes( + storage_endpoint='core.windows.net', + storage_sync_endpoint='afs.azure.net', + keyvault_dns='.vault.azure.net', + mhsm_dns='.managedhsm.azure.net', + sql_server_hostname='.database.windows.net', + mysql_server_endpoint='.mysql.database.azure.com', + postgresql_server_endpoint='.postgres.database.azure.com', + mariadb_server_endpoint='.mariadb.database.azure.com', + azure_datalake_store_file_system_endpoint='azuredatalakestore.net', + azure_datalake_analytics_catalog_and_job_endpoint='azuredatalakeanalytics.net', + acr_login_server_endpoint='.azurecr.io', + synapse_analytics_endpoint='.dev.azuresynapse.net', + attestation_endpoint='.attest.azure.net')) + +AZURE_US_GCC_CLOUD = AzureCloud( + 'Embedded', + 'AzureUSGovernment', + 'gcc', + endpoints=AzureCloudEndpoints( + management='https://management.core.usgovcloudapi.net/', + resource_manager='https://management.usgovcloudapi.net/', + sql_management='https://management.core.usgovcloudapi.net:8443/', + batch_resource_id='https://batch.core.usgovcloudapi.net/', + gallery='https://gallery.usgovcloudapi.net/', + active_directory='https://login.microsoftonline.us', + active_directory_resource_id='https://management.core.usgovcloudapi.net/', + active_directory_graph_resource_id='https://graph.windows.net/', + microsoft_graph_resource_id='https://graph.microsoft.us/', + vm_image_alias_doc='https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/arm-compute/quickstart-templates/aliases.json', # noqa: E501 + media_resource_id='https://rest.media.usgovcloudapi.net', + ossrdbms_resource_id='https://ossrdbms-aad.database.usgovcloudapi.net', + app_insights_resource_id='https://api.applicationinsights.us', + log_analytics_resource_id='https://api.loganalytics.us', + app_insights_telemetry_channel_resource_id='https://dc.applicationinsights.us/v2/track', + synapse_analytics_resource_id='https://dev.azuresynapse.usgovcloudapi.net', + portal='https://portal.azure.us', + keyvault='https://vault.usgovcloudapi.net', + ), + suffixes=AzureCloudSuffixes( + storage_endpoint='core.usgovcloudapi.net', + storage_sync_endpoint='afs.azure.us', + keyvault_dns='.vault.usgovcloudapi.net', + mhsm_dns='.managedhsm.usgovcloudapi.net', + sql_server_hostname='.database.usgovcloudapi.net', + mysql_server_endpoint='.mysql.database.usgovcloudapi.net', + postgresql_server_endpoint='.postgres.database.usgovcloudapi.net', + mariadb_server_endpoint='.mariadb.database.usgovcloudapi.net', + acr_login_server_endpoint='.azurecr.us', + synapse_analytics_endpoint='.dev.azuresynapse.usgovcloudapi.net')) + +AZURE_US_GCC_HIGH_CLOUD = AzureCloud( + 'Embedded', + 'AzureUSGovernment', + 'gcc-high', + endpoints=AzureCloudEndpoints( + management='https://management.core.usgovcloudapi.net/', + resource_manager='https://management.usgovcloudapi.net/', + sql_management='https://management.core.usgovcloudapi.net:8443/', + batch_resource_id='https://batch.core.usgovcloudapi.net/', + gallery='https://gallery.usgovcloudapi.net/', + active_directory='https://login.microsoftonline.us', + active_directory_resource_id='https://management.core.usgovcloudapi.net/', + active_directory_graph_resource_id='https://graph.windows.net/', + microsoft_graph_resource_id='https://graph.microsoft.us/', + vm_image_alias_doc='https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/arm-compute/quickstart-templates/aliases.json', # noqa: E501 + media_resource_id='https://rest.media.usgovcloudapi.net', + ossrdbms_resource_id='https://ossrdbms-aad.database.usgovcloudapi.net', + app_insights_resource_id='https://api.applicationinsights.us', + log_analytics_resource_id='https://api.loganalytics.us', + app_insights_telemetry_channel_resource_id='https://dc.applicationinsights.us/v2/track', + synapse_analytics_resource_id='https://dev.azuresynapse.usgovcloudapi.net', + portal='https://portal.azure.us', + keyvault='https://vault.usgovcloudapi.net', + ), + suffixes=AzureCloudSuffixes( + storage_endpoint='core.usgovcloudapi.net', + storage_sync_endpoint='afs.azure.us', + keyvault_dns='.vault.usgovcloudapi.net', + mhsm_dns='.managedhsm.usgovcloudapi.net', + sql_server_hostname='.database.usgovcloudapi.net', + mysql_server_endpoint='.mysql.database.usgovcloudapi.net', + postgresql_server_endpoint='.postgres.database.usgovcloudapi.net', + mariadb_server_endpoint='.mariadb.database.usgovcloudapi.net', + acr_login_server_endpoint='.azurecr.us', + synapse_analytics_endpoint='.dev.azuresynapse.usgovcloudapi.net')) + +AZURE_DOD_CLOUD = AzureCloud( + 'Embedded', + 'AzureUSGovernment', + 'dod', + endpoints=AzureCloudEndpoints( + management='https://management.core.usgovcloudapi.net/', + resource_manager='https://management.usgovcloudapi.net/', + sql_management='https://management.core.usgovcloudapi.net:8443/', + batch_resource_id='https://batch.core.usgovcloudapi.net/', + gallery='https://gallery.usgovcloudapi.net/', + active_directory='https://login.microsoftonline.us', + active_directory_resource_id='https://management.core.usgovcloudapi.net/', + active_directory_graph_resource_id='https://graph.windows.net/', + microsoft_graph_resource_id='https://dod-graph.microsoft.us/', + vm_image_alias_doc='https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/arm-compute/quickstart-templates/aliases.json', # noqa: E501 + media_resource_id='https://rest.media.usgovcloudapi.net', + ossrdbms_resource_id='https://ossrdbms-aad.database.usgovcloudapi.net', + app_insights_resource_id='https://api.applicationinsights.us', + log_analytics_resource_id='https://api.loganalytics.us', + app_insights_telemetry_channel_resource_id='https://dc.applicationinsights.us/v2/track', + synapse_analytics_resource_id='https://dev.azuresynapse.usgovcloudapi.net', + portal='https://portal.azure.us', + keyvault='https://vault.usgovcloudapi.net', + ), + suffixes=AzureCloudSuffixes( + storage_endpoint='core.usgovcloudapi.net', + storage_sync_endpoint='afs.azure.us', + keyvault_dns='.vault.usgovcloudapi.net', + mhsm_dns='.managedhsm.usgovcloudapi.net', + sql_server_hostname='.database.usgovcloudapi.net', + mysql_server_endpoint='.mysql.database.usgovcloudapi.net', + postgresql_server_endpoint='.postgres.database.usgovcloudapi.net', + mariadb_server_endpoint='.mariadb.database.usgovcloudapi.net', + acr_login_server_endpoint='.azurecr.us', + synapse_analytics_endpoint='.dev.azuresynapse.usgovcloudapi.net')) + + +AZURE_GERMAN_CLOUD = AzureCloud( + 'Embedded', + 'AzureGermanCloud', + 'de', + endpoints=AzureCloudEndpoints( + management='https://management.core.cloudapi.de/', + resource_manager='https://management.microsoftazure.de', + sql_management='https://management.core.cloudapi.de:8443/', + batch_resource_id='https://batch.cloudapi.de/', + gallery='https://gallery.cloudapi.de/', + active_directory='https://login.microsoftonline.de', + active_directory_resource_id='https://management.core.cloudapi.de/', + active_directory_graph_resource_id='https://graph.cloudapi.de/', + microsoft_graph_resource_id='https://graph.microsoft.de', + vm_image_alias_doc='https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/arm-compute/quickstart-templates/aliases.json', # noqa: E501 + media_resource_id='https://rest.media.cloudapi.de', + ossrdbms_resource_id='https://ossrdbms-aad.database.cloudapi.de', + portal='https://portal.microsoftazure.de', + keyvault='https://vault.microsoftazure.de' + ), + suffixes=AzureCloudSuffixes( + storage_endpoint='core.cloudapi.de', + keyvault_dns='.vault.microsoftazure.de', + mhsm_dns='.managedhsm.microsoftazure.de', + sql_server_hostname='.database.cloudapi.de', + mysql_server_endpoint='.mysql.database.cloudapi.de', + postgresql_server_endpoint='.postgres.database.cloudapi.de', + mariadb_server_endpoint='.mariadb.database.cloudapi.de')) + +AZURE_CHINA_CLOUD = AzureCloud( + 'Embedded', + 'AzureChinaCloud', + 'cn', + endpoints=AzureCloudEndpoints( + management='https://management.core.chinacloudapi.cn/', + resource_manager='https://management.chinacloudapi.cn', + sql_management='https://management.core.chinacloudapi.cn:8443/', + batch_resource_id='https://batch.chinacloudapi.cn/', + gallery='https://gallery.chinacloudapi.cn/', + active_directory='https://login.chinacloudapi.cn', + active_directory_resource_id='https://management.core.chinacloudapi.cn/', + active_directory_graph_resource_id='https://graph.chinacloudapi.cn/', + microsoft_graph_resource_id='https://microsoftgraph.chinacloudapi.cn', + vm_image_alias_doc='https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/arm-compute/quickstart-templates/aliases.json', # noqa: E501 + media_resource_id='https://rest.media.chinacloudapi.cn', + ossrdbms_resource_id='https://ossrdbms-aad.database.chinacloudapi.cn', + app_insights_resource_id='https://api.applicationinsights.azure.cn', + log_analytics_resource_id='https://api.loganalytics.azure.cn', + app_insights_telemetry_channel_resource_id='https://dc.applicationinsights.azure.cn/v2/track', + synapse_analytics_resource_id='https://dev.azuresynapse.azure.cn', + portal='https://portal.azure.cn', + keyvault='https://vault.azure.cn', + ), + suffixes=AzureCloudSuffixes( + storage_endpoint='core.chinacloudapi.cn', + keyvault_dns='.vault.azure.cn', + mhsm_dns='.managedhsm.azure.cn', + sql_server_hostname='.database.chinacloudapi.cn', + mysql_server_endpoint='.mysql.database.chinacloudapi.cn', + postgresql_server_endpoint='.postgres.database.chinacloudapi.cn', + mariadb_server_endpoint='.mariadb.database.chinacloudapi.cn', + acr_login_server_endpoint='.azurecr.cn', + synapse_analytics_endpoint='.dev.azuresynapse.azure.cn')) + + +AZURE_CLOUD_NAME_MAPPING = { + "Worldwide": "com", + "Germany": "de", + "China": "cn", + "US GCC": "gcc", + "US GCC-High": "gcc-high", + "DoD": "dod", +} + +AZURE_CLOUD_NAME_CUSTOM = "Custom" + +AZURE_CLOUDS = { + "com": AZURE_WORLDWIDE_CLOUD, + "gcc": AZURE_US_GCC_CLOUD, + "gcc-high": AZURE_US_GCC_HIGH_CLOUD, + "dod": AZURE_DOD_CLOUD, + "de": AZURE_GERMAN_CLOUD, + "cn": AZURE_CHINA_CLOUD, +} + + +class AzureCloudNames: + WORLDWIDE = "com" + GERMANY = "de" + CHINA = "cn" + US_GCC = "gcc" + US_GCC_HIGH = "gcc-high" + DOD = "dod" + CUSTOM = "custom" + + +def create_custom_azure_cloud(origin: str, + name: Optional[str] = None, + abbreviation: Optional[str] = None, + defaults: Optional[AzureCloud] = None, + endpoints: Optional[Dict] = None, + suffixes: Optional[Dict] = None): + defaults = defaults or AzureCloud(origin, name, abbreviation) + endpoints = endpoints or {} + suffixes = suffixes or {} + return AzureCloud( + origin, + name or defaults.name, + abbreviation or defaults.abbreviation, + endpoints=AzureCloudEndpoints( + management=endpoints.get('management', defaults.endpoints.management), + resource_manager=endpoints.get('resource_manager', defaults.endpoints.resource_manager), + sql_management=endpoints.get('sql_management', defaults.endpoints.sql_management), + batch_resource_id=endpoints.get('batch_resource_id', defaults.endpoints.batch_resource_id), + gallery=endpoints.get('gallery', defaults.endpoints.gallery), + active_directory=endpoints.get('active_directory', defaults.endpoints.active_directory), + active_directory_resource_id=endpoints.get('active_directory_resource_id', + defaults.endpoints.active_directory_resource_id), + active_directory_graph_resource_id=endpoints.get( + 'active_directory_graph_resource_id', defaults.endpoints.active_directory_graph_resource_id), + microsoft_graph_resource_id=endpoints.get('microsoft_graph_resource_id', + defaults.endpoints.microsoft_graph_resource_id), + active_directory_data_lake_resource_id=endpoints.get( + 'active_directory_data_lake_resource_id', defaults.endpoints.active_directory_data_lake_resource_id), + vm_image_alias_doc=endpoints.get('vm_image_alias_doc', defaults.endpoints.vm_image_alias_doc), + media_resource_id=endpoints.get('media_resource_id', defaults.endpoints.media_resource_id), + ossrdbms_resource_id=endpoints.get('ossrdbms_resource_id', defaults.endpoints.ossrdbms_resource_id), + app_insights_resource_id=endpoints.get('app_insights_resource_id', defaults.endpoints.app_insights_resource_id), + log_analytics_resource_id=endpoints.get('log_analytics_resource_id', defaults.endpoints.log_analytics_resource_id), + app_insights_telemetry_channel_resource_id=endpoints.get( + 'app_insights_telemetry_channel_resource_id', defaults.endpoints.app_insights_telemetry_channel_resource_id), + synapse_analytics_resource_id=endpoints.get( + 'synapse_analytics_resource_id', defaults.endpoints.synapse_analytics_resource_id), + attestation_resource_id=endpoints.get('attestation_resource_id', defaults.endpoints.attestation_resource_id), + portal=endpoints.get('portal', defaults.endpoints.portal), + keyvault=endpoints.get('keyvault', defaults.endpoints.keyvault), + ), + suffixes=AzureCloudSuffixes( + storage_endpoint=suffixes.get('storage_endpoint', defaults.suffixes.storage_endpoint), + storage_sync_endpoint=suffixes.get('storage_sync_endpoint', defaults.suffixes.storage_sync_endpoint), + keyvault_dns=suffixes.get('keyvault_dns', defaults.suffixes.keyvault_dns), + mhsm_dns=suffixes.get('mhsm_dns', defaults.suffixes.mhsm_dns), + sql_server_hostname=suffixes.get('sql_server_hostname', defaults.suffixes.sql_server_hostname), + mysql_server_endpoint=suffixes.get('mysql_server_endpoint', defaults.suffixes.mysql_server_endpoint), + postgresql_server_endpoint=suffixes.get('postgresql_server_endpoint', defaults.suffixes.postgresql_server_endpoint), + mariadb_server_endpoint=suffixes.get('mariadb_server_endpoint', defaults.suffixes.mariadb_server_endpoint), + azure_datalake_store_file_system_endpoint=suffixes.get( + 'azure_datalake_store_file_system_endpoint', defaults.suffixes.azure_datalake_store_file_system_endpoint), + azure_datalake_analytics_catalog_and_job_endpoint=suffixes.get( + 'azure_datalake_analytics_catalog_and_job_endpoint', + defaults.suffixes.azure_datalake_analytics_catalog_and_job_endpoint), + acr_login_server_endpoint=suffixes.get('acr_login_server_endpoint', defaults.suffixes.acr_login_server_endpoint), + synapse_analytics_endpoint=suffixes.get('synapse_analytics_endpoint', defaults.suffixes.synapse_analytics_endpoint), + attestation_endpoint=suffixes.get('attestation_endpoint', defaults.suffixes.attestation_endpoint), + )) + + +def microsoft_defender_for_endpoint_get_base_url(endpoint_type, url, is_gcc=None): + # Backward compatible argument parsing, preserve the url and is_gcc functionality if provided, otherwise use endpoint_type. + log_message_append = "" + if is_gcc: # Backward compatible. + endpoint_type = "US GCC" + log_message_append = f" ,Overriding endpoint to {endpoint_type}, backward compatible." + elif endpoint_type == MICROSOFT_DEFENDER_FOR_ENDPOINT_TYPE_CUSTOM or not endpoint_type: + # When the integration was configured before our Azure Cloud support, the value will be None. + if not url: + if endpoint_type == MICROSOFT_DEFENDER_FOR_ENDPOINT_TYPE_CUSTOM: + raise DemistoException("Endpoint type is set to 'Custom' but no URL was provided.") + raise DemistoException("'Endpoint Type' is not set and no URL was provided.") + endpoint_type = MICROSOFT_DEFENDER_FOR_ENDPOINT_TYPE.get(endpoint_type, 'com') + url = url or MICROSOFT_DEFENDER_FOR_ENDPOINT_API[endpoint_type] + demisto.info(f"Using url:{url}, endpoint type:{endpoint_type}{log_message_append}") + return endpoint_type, url + + +def get_azure_cloud(params, integration_name): + azure_cloud_arg = params.get('azure_cloud') + if not azure_cloud_arg or azure_cloud_arg == AZURE_CLOUD_NAME_CUSTOM: + # Backward compatibility before the azure cloud settings. + if 'server_url' in params: + return create_custom_azure_cloud(integration_name, defaults=AZURE_WORLDWIDE_CLOUD, + endpoints={'resource_manager': params.get('server_url') + or 'https://management.azure.com'}) + if 'azure_ad_endpoint' in params: + return create_custom_azure_cloud(integration_name, defaults=AZURE_WORLDWIDE_CLOUD, + endpoints={ + 'active_directory': params.get('azure_ad_endpoint') + or 'https://login.microsoftonline.com' + }) + + # There is no need for backward compatibility support, as the integration didn't support it to begin with. + return AZURE_CLOUDS.get(azure_cloud_arg, AZURE_WORLDWIDE_CLOUD) + + class MicrosoftClient(BaseClient): def __init__(self, tenant_id: str = '', auth_id: str = '', @@ -82,12 +616,14 @@ def __init__(self, tenant_id: str = '', self_deployed: bool = False, timeout: Optional[int] = None, azure_ad_endpoint: str = '{endpoint}', - endpoint: str = 'com', + azure_cloud: AzureCloud = AZURE_WORLDWIDE_CLOUD, + endpoint: str = "__NA__", # Deprecated certificate_thumbprint: Optional[str] = None, retry_on_rate_limit: bool = False, private_key: Optional[str] = None, managed_identities_client_id: Optional[str] = None, managed_identities_resource_uri: Optional[str] = None, + base_url: Optional[str] = None, *args, **kwargs): """ Microsoft Client class that implements logic to authenticate with oproxy or self deployed applications. @@ -98,22 +634,33 @@ def __init__(self, tenant_id: str = '', contain the token url enc_key: If self deployed it's the client secret, otherwise (oproxy) it's the encryption key refresh_token: The current used refresh token. - refresh_token_param: The refresh token from the integration's parameters (i.e instance configuration). + refresh_token_param: The refresh token from the integration's parameters (i.e. instance configuration). scope: The scope of the application (only if self deployed) resource: The resource of the application (only if self deployed) multi_resource: Where or not module uses a multiple resources (self-deployed, auth_code grant type only) resources: Resources of the application (for multi-resource mode) verify: Demisto insecure parameter self_deployed: Indicates whether the integration mode is self deployed or oproxy + timeout: Connection timeout + azure_ad_endpoint: Custom endpoint to Azure Active Directory URL + azure_cloud: Azure Cloud. certificate_thumbprint: Certificate's thumbprint that's associated to the app private_key: Private key of the certificate managed_identities_client_id: The Azure Managed Identities client id managed_identities_resource_uri: The resource uri to get token for by Azure Managed Identities retry_on_rate_limit: If the http request returns with a 429 - Rate limit reached response, retry the request using a scheduled command. + base_url: Optionally override the calculated Azure endpoint, used for self-deployed and backward-compatibility with + integration that supported national cloud before the *azure_cloud* parameter. """ - super().__init__(verify=verify, *args, **kwargs) # type: ignore[misc] - self.endpoint = endpoint + if endpoint != "__NA__": + # Backward compatible. + self.azure_cloud = AZURE_CLOUDS.get(endpoint, AZURE_WORLDWIDE_CLOUD) + else: + self.azure_cloud = azure_cloud + + super().__init__(*args, verify=verify, base_url=base_url, **kwargs) # type: ignore[misc] + self.retry_on_rate_limit = retry_on_rate_limit if retry_on_rate_limit and (429 not in self._ok_codes): self._ok_codes = self._ok_codes + (429,) @@ -128,20 +675,19 @@ def __init__(self, tenant_id: str = '', self.app_name = app_name self.auth_id = auth_id self.enc_key = enc_key - self.tenant_id = tenant_id self.refresh_token = refresh_token self.refresh_token_param = refresh_token_param else: self.token_retrieval_url = token_retrieval_url.format(tenant_id=tenant_id, - endpoint=TOKEN_RETRIEVAL_ENDPOINTS[self.endpoint]) + endpoint=self.azure_cloud.endpoints.active_directory + .rstrip("/")) self.client_id = auth_id self.client_secret = enc_key - self.tenant_id = tenant_id self.auth_code = auth_code self.grant_type = grant_type self.resource = resource - self.scope = scope.format(graph_endpoint=GRAPH_ENDPOINTS[self.endpoint]) + self.scope = scope.format(graph_endpoint=self.azure_cloud.endpoints.microsoft_graph_resource_id.rstrip("/")) self.redirect_uri = redirect_uri if certificate_thumbprint and private_key: try: @@ -156,9 +702,11 @@ def __init__(self, tenant_id: str = '', else: self.jwt = None + self.tenant_id = tenant_id self.auth_type = SELF_DEPLOYED_AUTH_TYPE if self_deployed else OPROXY_AUTH_TYPE self.verify = verify - self.azure_ad_endpoint = azure_ad_endpoint.format(endpoint=TOKEN_RETRIEVAL_ENDPOINTS[self.endpoint]) + self.azure_ad_endpoint = azure_ad_endpoint.format( + endpoint=self.azure_cloud.endpoints.active_directory.rstrip("/")) self.timeout = timeout # type: ignore self.multi_resource = multi_resource @@ -190,7 +738,7 @@ def http_request( resp_type: Type of response to return. will be ignored if `return_empty_response` is True. headers: Headers to add to the request. return_empty_response: Return the response itself if the return_code is 206. - scope: A scope to request. Currently will work only with self-deployed app. + scope: A scope to request. Currently, will work only with self-deployed app. resource (str): The resource identifier for which the generated token will have access to. overwrite_rate_limit_retry : Skip rate limit retry Returns: @@ -821,7 +1369,8 @@ def __init__(self, message): def get_azure_managed_identities_client_id(params: dict) -> Optional[str]: - """"extract the Azure Managed Identities from the demisto params + """ + Extract the Azure Managed Identities from the demisto params Args: params (dict): the demisto params @@ -839,16 +1388,25 @@ def get_azure_managed_identities_client_id(params: dict) -> Optional[str]: return None -def generate_login_url(client: MicrosoftClient) -> CommandResults: - - assert client.tenant_id \ - and client.scope \ - and client.client_id \ - and client.redirect_uri, 'Please make sure you entered the Authorization configuration correctly.' - - login_url = f'https://login.microsoftonline.com/{client.tenant_id}/oauth2/v2.0/authorize?' \ - f'response_type=code&scope=offline_access%20{client.scope.replace(" ", "%20")}' \ - f'&client_id={client.client_id}&redirect_uri={client.redirect_uri}' +def generate_login_url(client: MicrosoftClient, + login_url: str = "https://login.microsoftonline.com/") -> CommandResults: + + missing = [] + if not client.client_id: + missing.append("client_id") + if not client.tenant_id: + missing.append("tenant_id") + if not client.scope: + missing.append("scope") + if not client.redirect_uri: + missing.append("redirect_uri") + if missing: + raise DemistoException("Please make sure you entered the Authorization configuration correctly. " + f"Missing:{','.join(missing)}") + + login_url = urljoin(login_url, f'{client.tenant_id}/oauth2/v2.0/authorize?' + f'response_type=code&scope=offline_access%20{client.scope.replace(" ", "%20")}' + f'&client_id={client.client_id}&redirect_uri={client.redirect_uri}') result_msg = f"""### Authorization instructions 1. Click on the [login URL]({login_url}) to sign in and grant Cortex XSOAR permissions for your Azure Service Management. diff --git a/Packs/ApiModules/Scripts/MicrosoftApiModule/MicrosoftApiModule.yml b/Packs/ApiModules/Scripts/MicrosoftApiModule/MicrosoftApiModule.yml index 4bda4ac832d2..67c0b37d2236 100644 --- a/Packs/ApiModules/Scripts/MicrosoftApiModule/MicrosoftApiModule.yml +++ b/Packs/ApiModules/Scripts/MicrosoftApiModule/MicrosoftApiModule.yml @@ -13,7 +13,7 @@ system: true scripttarget: 0 dependson: {} timeout: 0s -dockerimage: demisto/crypto:1.0.0.52480 +dockerimage: demisto/crypto:1.0.0.61689 fromversion: 5.0.0 tests: - No test diff --git a/Packs/ApiModules/Scripts/MicrosoftApiModule/MicrosoftApiModule_test.py b/Packs/ApiModules/Scripts/MicrosoftApiModule/MicrosoftApiModule_test.py index 509bb09a0e7f..58157d10e50d 100644 --- a/Packs/ApiModules/Scripts/MicrosoftApiModule/MicrosoftApiModule_test.py +++ b/Packs/ApiModules/Scripts/MicrosoftApiModule/MicrosoftApiModule_test.py @@ -127,10 +127,8 @@ def test_page_not_found_error(mocker): mocker.patch.object(BaseClient, '_http_request', return_value=error_404) mocker.patch.object(client, 'get_access_token') - try: + with pytest.raises(NotFoundError): client.http_request() - except Exception as e: # Validate that a `NotFoundError` was raised - assert type(e).__name__ == 'NotFoundError' def test_epoch_seconds(mocker): @@ -394,8 +392,8 @@ def test_self_deployed_multi_resource(requests_mock, resource): assert client.resource_to_access_token[resource] == TOKEN -@pytest.mark.parametrize('endpoint', ['com', 'gcc-high', 'dod', 'de', 'cn']) -def test_national_endpoints(mocker, endpoint): +@pytest.mark.parametrize('azure_cloud_name', ['com', 'gcc', 'gcc-high', 'dod', 'de', 'cn']) +def test_national_endpoints(mocker, azure_cloud_name): """ Given: self-deployed client @@ -408,14 +406,14 @@ def test_national_endpoints(mocker, endpoint): auth_id = f'{AUTH_ID}@{TOKEN_URL}' enc_key = ENC_KEY app_name = APP_NAME - base_url = BASE_URL ok_codes = OK_CODES + azure_cloud = AZURE_CLOUDS[azure_cloud_name] client = MicrosoftClient(self_deployed=True, auth_id=auth_id, enc_key=enc_key, app_name=app_name, - tenant_id=tenant_id, base_url=base_url, verify=True, proxy=False, ok_codes=ok_codes, - endpoint=endpoint) + tenant_id=tenant_id, verify=True, proxy=False, ok_codes=ok_codes, + azure_cloud=azure_cloud) - assert client.azure_ad_endpoint == TOKEN_RETRIEVAL_ENDPOINTS[endpoint] - assert client.scope == f'{GRAPH_ENDPOINTS[endpoint]}/.default' + assert client.azure_ad_endpoint == TOKEN_RETRIEVAL_ENDPOINTS[client.azure_cloud.abbreviation] + assert client.scope == f'{GRAPH_ENDPOINTS[client.azure_cloud.abbreviation]}/.default' def test_retry_on_rate_limit(requests_mock, mocker): @@ -483,11 +481,8 @@ def test_fail_on_retry_on_rate_limit(requests_mock, mocker): mocker.patch.object(sys, 'exit') mocker.patch.object(demisto, 'callingContext', {'context': {'ExecutedCommands': [{'moduleBrand': 'msgraph'}]}}) - try: + with pytest.raises(DemistoException, match=r'Rate limit reached!'): client.http_request(method='GET', url_suffix='test_id') - assert False - except DemistoException as err: - assert 'Rate limit reached!' in err.args[0]['content'] def test_rate_limit_when_retry_is_false(requests_mock): @@ -510,11 +505,8 @@ def test_rate_limit_when_retry_is_false(requests_mock): json={'content': "Rate limit reached!"} ) - try: + with pytest.raises(DemistoException, match="Error in API call \[429\]"): client.http_request(method='GET', url_suffix='test_id') - assert False - except DemistoException as err: - assert 'Error in API call [429]' in err.args[0] @pytest.mark.parametrize('response, result', [ @@ -556,13 +548,11 @@ def test_general_error_metrics(requests_mock, mocker): mocker.patch.object(demisto, 'command', return_value='testing_command') mocker.patch.object(demisto, 'results') - try: + with pytest.raises(DemistoException): client.http_request(method='GET', url_suffix='test_id') - assert False - except DemistoException: - metric_results = demisto.results.call_args_list[0][0][0] - assert metric_results.get('Contents') == 'Metrics reported successfully.' - assert metric_results.get('APIExecutionMetrics') == [{'Type': 'GeneralError', 'APICallsCount': 1}] + metric_results = demisto.results.call_args_list[0][0][0] + assert metric_results.get('Contents') == 'Metrics reported successfully.' + assert metric_results.get('APIExecutionMetrics') == [{'Type': 'GeneralError', 'APICallsCount': 1}] @pytest.mark.parametrize(argnames='client_id', argvalues=['test_client_id', None]) diff --git a/Packs/AzureKeyVault/.pack-ignore b/Packs/AzureKeyVault/.pack-ignore index 26d53e852c92..826d6f8dba60 100644 --- a/Packs/AzureKeyVault/.pack-ignore +++ b/Packs/AzureKeyVault/.pack-ignore @@ -3,3 +3,79 @@ ignore=IM111 [file:AzureKeyVault.yml] ignore=IN145 + +[known_words] +AQAB +Azur +Boolean +CN +D +Encipherment +Endpoints +Issuers +K +Purgeable +Rbac +URLs +UTC +VM +Vaul +XXX +XXXX +XXXXX +XXXXXX +aa +australiacentral +australiaeast +australiasoutheast +br +brazilsouth +canadacentral +canadaeast +centralindia +centralus +deleteissuers +deletesas +eastasia +eastus +ekus +exportable +francecentral +germanywestcentral +getissuers +getsas +gt +ifica +japaneast +japanwest +jioindiawest +koreacentral +kty +listissuers +listsas +managecontacts +manageissuers +nbf +northcentralus +northeurope +norwayeast +readonly +regeneratekey +setissuers +setsas +southafricanorth +southcentralus +southeastasia +southindia +switzerlandnorth +t +uaenorth +uksouth +ukwest +westcentralus +westeurope +westindia +westus +x +GCC +n diff --git a/Packs/AzureKeyVault/.secrets-ignore b/Packs/AzureKeyVault/.secrets-ignore index e2b6936e09d1..1e1249c9c6af 100644 --- a/Packs/AzureKeyVault/.secrets-ignore +++ b/Packs/AzureKeyVault/.secrets-ignore @@ -10,4 +10,11 @@ https://xsoar-test-285.vault.azure.net "https://xsoar-test-265.vault.azure.net 1.3.6.1 5.5.7.3 -https://portal.azure.com \ No newline at end of file +https://portal.azure.com +https://gallery.azure.com +https://management.core.windows.net +https://portal.azure.cn +https://portal.azure.com +https://portal.azure.us +https://vault.azure.cn +https://vault.azure.net diff --git a/Packs/AzureKeyVault/Integrations/AzureKeyVault/AzureKeyVault.py b/Packs/AzureKeyVault/Integrations/AzureKeyVault/AzureKeyVault.py index b346eb7efccf..10a2f668d79e 100644 --- a/Packs/AzureKeyVault/Integrations/AzureKeyVault/AzureKeyVault.py +++ b/Packs/AzureKeyVault/Integrations/AzureKeyVault/AzureKeyVault.py @@ -5,11 +5,11 @@ from datetime import datetime import copy +from MicrosoftApiModule import * # noqa: E402 + APP_NAME = 'azure-key-vault' DATE_FORMAT = '%Y-%m-%dT%H:%M:%SZ' AUTHORIZATION_CODE = 'authorization_code' -MANAGEMENT_RESOURCE = 'https://management.azure.com' -VAULT_RESOURCE = 'https://vault.azure.net' VAULT_NAME_CONTEXT_FIELD = 'key_vault_name' DEFAULT_LIMIT = 50 @@ -24,20 +24,22 @@ class KeyVaultClient: def __init__(self, tenant_id: str, client_id: str, client_secret: str, subscription_id: str, resource_group_name: str, verify: bool, proxy: bool, certificate_thumbprint: Optional[str], private_key: Optional[str], - managed_identities_client_id: Optional[str] = None): - + managed_identities_client_id: Optional[str] = None, + azure_cloud: Optional[AzureCloud] = None): + self.azure_cloud = azure_cloud or AZURE_WORLDWIDE_CLOUD self.ms_client = MicrosoftClient( self_deployed=True, auth_id=client_id, enc_key=client_secret, - token_retrieval_url=f'https://login.microsoftonline.com/{tenant_id}/oauth2/token', + token_retrieval_url=urljoin(self.azure_cloud.endpoints.active_directory, f'/{tenant_id}/oauth2/token'), app_name=APP_NAME, - base_url=f'https://management.azure.com/subscriptions/{subscription_id}/' - f'resourceGroups/{resource_group_name}/providers/Microsoft.KeyVault', + base_url=urljoin(self.azure_cloud.endpoints.resource_manager, + f'/subscriptions/{subscription_id}/resourceGroups/' + f'{resource_group_name}/providers/Microsoft.KeyVault'), verify=verify, proxy=proxy, multi_resource=True, - resources=[MANAGEMENT_RESOURCE, VAULT_RESOURCE], + resources=[self.get_management_resource(), self.get_vault_resource()], resource='', scope='', tenant_id=tenant_id, @@ -47,17 +49,25 @@ def __init__(self, tenant_id: str, client_id: str, client_secret: str, managed_identities_client_id=managed_identities_client_id, ) + def get_vault_resource(self) -> str: + return self.azure_cloud.endpoints.keyvault + + def get_management_resource(self) -> str: + return self.azure_cloud.endpoints.resource_manager + def http_request(self, method: str, url_suffix: str = None, full_url: str = None, params: dict = None, data: dict = None, - resource: str = MANAGEMENT_RESOURCE): + resource: Optional[str] = None): """ Wrapper to MicrosoftClient http_request method. """ + resource = resource or self.get_management_resource() if not params: params = {} - params['api-version'] = '2019-09-01' if resource == MANAGEMENT_RESOURCE else '7.2' + + params['api-version'] = '2019-09-01' if resource == self.get_management_resource() else '7.2' res = self.ms_client.http_request(method=method, url_suffix=url_suffix, full_url=full_url, @@ -105,7 +115,7 @@ def create_or_update_key_vault_request(self, vault_name: str, object_id: str, lo enabled_for_template_deployment (bool): permission for Azure Resource Manager to retrieve secrets. default_action (str): The default action. bypass (str): bypass network rules.Network acl property.Default is 'AzureServices'. - vnet_subnet_id:(str): Full resource id of a vnet subnet. + vnet_subnet_id (str): Full resource id of a vnet subnet. ignore_missing_vnet_service_endpoint (bool): NRP will ignore the check. ip_rules (List[str],optional) : The list of IP address rules. @@ -219,11 +229,11 @@ def get_key_request(self, vault_name: str, key_name: str, key_version: str) -> D Dict[str, Any]: API response from Azure. """ - url = f'https://{vault_name}.vault.azure.net/keys/{key_name}' + url = f'https://{vault_name}{self.azure_cloud.suffixes.keyvault_dns}/keys/{key_name}' if key_version: url = url + f'/{key_version}' response = self.http_request( - 'GET', full_url=url, resource=VAULT_RESOURCE) + 'GET', full_url=url, resource=self.get_vault_resource()) return response @@ -239,11 +249,11 @@ def list_keys_request(self, vault_name: str, limit: int, offset: int) -> List[di Dict[str, Any]: API response from Azure. """ - url = f'https://{vault_name}.vault.azure.net/keys' + url = f'https://{vault_name}{self.azure_cloud.suffixes.keyvault_dns}/keys' response = self.http_request( - 'GET', full_url=url, resource=VAULT_RESOURCE) + 'GET', full_url=url, resource=self.get_vault_resource()) - return self.get_entities_independent_of_pages(response, limit, offset, VAULT_RESOURCE) + return self.get_entities_independent_of_pages(response, limit, offset, self.get_vault_resource()) def delete_key_request(self, vault_name: str, key_name: str) -> Dict[str, Any]: """ @@ -256,9 +266,9 @@ def delete_key_request(self, vault_name: str, key_name: str) -> Dict[str, Any]: Returns: Dict[str, Any]: response json """ - url = f'https://{vault_name}.vault.azure.net/keys/{key_name}' + url = f'https://{vault_name}{self.azure_cloud.suffixes.keyvault_dns}/keys/{key_name}' response = self.http_request( - 'DELETE', full_url=url, resource=VAULT_RESOURCE) + 'DELETE', full_url=url, resource=self.get_vault_resource()) return response @@ -273,11 +283,11 @@ def get_secret_request(self, vault_name: str, secret_name: str, secret_version: Returns: Dict[str, Any]: API response from Azure. """ - url = f'https://{vault_name}.vault.azure.net/secrets/{secret_name}' + url = f'https://{vault_name}{self.azure_cloud.suffixes.keyvault_dns}/secrets/{secret_name}' if secret_version: url = url + f'/{secret_version}' response = self.http_request( - 'GET', full_url=url, resource=VAULT_RESOURCE) + 'GET', full_url=url, resource=self.get_vault_resource()) return response @@ -293,11 +303,11 @@ def list_secrets_request(self, vault_name: str, limit: int, offset: int) -> List Returns: Dict[str, Any]: API response from Azure. """ - url = f'https://{vault_name}.vault.azure.net/secrets' + url = f'https://{vault_name}{self.azure_cloud.suffixes.keyvault_dns}/secrets' response = self.http_request( - 'GET', full_url=url, resource=VAULT_RESOURCE) + 'GET', full_url=url, resource=self.get_vault_resource()) - return self.get_entities_independent_of_pages(response, limit, offset, VAULT_RESOURCE) + return self.get_entities_independent_of_pages(response, limit, offset, self.get_vault_resource()) def delete_secret_request(self, vault_name: str, secret_name: str) -> Dict[str, Any]: """ @@ -310,9 +320,9 @@ def delete_secret_request(self, vault_name: str, secret_name: str) -> Dict[str, Returns: Dict[str, Any]: API response from Azure. """ - url = f'https://{vault_name}.vault.azure.net/secrets/{secret_name}' + url = f'https://{vault_name}{self.azure_cloud.suffixes.keyvault_dns}/secrets/{secret_name}' response = self.http_request( - 'DELETE', full_url=url, resource=VAULT_RESOURCE) + 'DELETE', full_url=url, resource=self.get_vault_resource()) return response def get_certificate_request(self, vault_name: str, @@ -328,12 +338,12 @@ def get_certificate_request(self, vault_name: str, Returns: Dict[str, Any]: API response from Azure. """ - url = f'https://{vault_name}.vault.azure.net/certificates/{certificate_name}' + url = f'https://{vault_name}{self.azure_cloud.suffixes.keyvault_dns}/certificates/{certificate_name}' if certificate_version: url = url + f'/{certificate_version}' response = self.http_request( 'GET', full_url=url, - resource=VAULT_RESOURCE) + resource=self.get_vault_resource()) return response @@ -349,12 +359,12 @@ def list_certificates_request(self, vault_name: str, limit: int, offset: int) -> Returns: Dict[str, Any]: response json """ - url = f'https://{vault_name}.vault.azure.net/certificates' + url = f'https://{vault_name}{self.azure_cloud.suffixes.keyvault_dns}/certificates' response = self.http_request( - 'GET', full_url=url, resource=VAULT_RESOURCE) + 'GET', full_url=url, resource=self.get_vault_resource()) - return self.get_entities_independent_of_pages(response, limit, offset, VAULT_RESOURCE) + return self.get_entities_independent_of_pages(response, limit, offset, self.get_vault_resource()) def get_certificate_policy_request(self, vault_name: str, certificate_name: str) -> Dict[str, Any]: """ @@ -362,14 +372,14 @@ def get_certificate_policy_request(self, vault_name: str, certificate_name: str) Args: vault_name (str): Key Vault name. - certificate_name (str): the name of the certificate to retrieve it's policy. + certificate_name (str): the name of the certificate to retrieve its policy. Returns: Dict[str, Any]: API response from Azure. """ - url = f'https://{vault_name}.vault.azure.net/certificates/{certificate_name}/policy' + url = f'https://{vault_name}{self.azure_cloud.suffixes.keyvault_dns}/certificates/{certificate_name}/policy' response = self.http_request( - 'GET', full_url=url, resource=VAULT_RESOURCE) + 'GET', full_url=url, resource=self.get_vault_resource()) return response @@ -437,7 +447,6 @@ def config_vault_properties(self, object_id: str, tenant_id: str, enabled_for_de enabled_for_disk_encryption: bool, enabled_for_template_deployment: bool, sku_name: str, permissions: Dict[str, Any], network_acls: Dict[str, Any]): - """ Configure the properties of a vault on create or update command. @@ -468,7 +477,7 @@ def config_vault_properties(self, object_id: str, tenant_id: str, enabled_for_de return properties def get_entities_independent_of_pages(self, first_page: Dict[str, Any], limit: int, offset: int, - resource: str = MANAGEMENT_RESOURCE) -> List[dict]: + resource: Optional[str] = None) -> List[dict]: """ List the entities according to the offset and limit arguments, following the first API call to the endpoint. @@ -480,11 +489,12 @@ def get_entities_independent_of_pages(self, first_page: Dict[str, Any], limit: i first_page (Dict[str, Any]): The first list of entities which returned by the first API call. limit (int): limit on the number of entities to retrieve to the user. offset (int): first index to return from. - resource (str): Azure resource. Default is MANAGEMENT_RESOURCE. + resource (str | None): Azure resource. Default's to management resource. Returns: List[dict]: List of Key Vaults/Keys/Secrets/Certificates. """ + resource = resource or self.get_management_resource() entities = first_page.get('value') next_page_url = first_page.get('nextLink') # more entities to get @@ -509,7 +519,7 @@ def get_secret_credentials(self, key_vault_name: str, secret_name: str): "password": secret_value, "name": f'{key_vault_name}/{secret_name}' } - except Exception: # in case the secret does not exists in the vault + except Exception: # in case the secret does not exist in the vault return None @@ -1119,8 +1129,8 @@ def test_module(client: KeyVaultClient) -> None: None """ try: - client.ms_client.get_access_token(resource=MANAGEMENT_RESOURCE) - client.ms_client.get_access_token(resource=VAULT_RESOURCE) + client.ms_client.get_access_token(resource=client.get_management_resource()) + client.ms_client.get_access_token(resource=client.get_vault_resource()) client.list_key_vaults_request(1, 0) # fetch_credentials(client,[''],[''],'xsoar-test-vault/test-sec-1') return_results('ok') @@ -1272,12 +1282,12 @@ def main() -> None: verify_certificate: bool = not params.get('insecure', False) proxy = params.get('proxy', False) identifier = args.get('identifier') + client_secret = params.get('client_secret', {}).get('password') + azure_cloud = get_azure_cloud(params, "AzureKeyVault") managed_identities_client_id = get_azure_managed_identities_client_id(params) command = demisto.command() demisto.debug(f'Command being called is {command}') - try: - client_secret = params.get('client_secret') certificate_thumbprint = params.get('certificate_thumbprint') private_key = params.get('private_key') if not managed_identities_client_id and not client_secret and not (certificate_thumbprint and private_key): @@ -1296,7 +1306,8 @@ def main() -> None: proxy=proxy, certificate_thumbprint=certificate_thumbprint, private_key=private_key, - managed_identities_client_id=managed_identities_client_id + managed_identities_client_id=managed_identities_client_id, + azure_cloud=azure_cloud, ) commands = { @@ -1329,7 +1340,5 @@ def main() -> None: return_error(str(e)) -from MicrosoftApiModule import * # noqa: E402 - if __name__ in ["builtins", "__main__"]: main() diff --git a/Packs/AzureKeyVault/Integrations/AzureKeyVault/AzureKeyVault.yml b/Packs/AzureKeyVault/Integrations/AzureKeyVault/AzureKeyVault.yml index 04207582bc17..ed2fd0d269b3 100644 --- a/Packs/AzureKeyVault/Integrations/AzureKeyVault/AzureKeyVault.yml +++ b/Packs/AzureKeyVault/Integrations/AzureKeyVault/AzureKeyVault.yml @@ -3,6 +3,21 @@ commonfields: id: AzureKeyVault version: -1 configuration: +- display: Azure Cloud + name: azure_cloud + required: false + type: 15 + defaultvalue: Worldwide + options: + - Worldwide + - US GCC + - US GCC-High + - DoD + - Germany + - China + section: Connect + advanced: true + additionalinfo: More information about National clouds can be found here - https://xsoar.pan.dev/docs/reference/articles/microsoft-integrations---authentication#using-national-cloud - display: Client ID name: client_id required: false @@ -26,16 +41,16 @@ configuration: required: false type: 14 - additionalinfo: Relevant only if the integration is running on Azure VM. If selected, authenticates based on the value provided for the Azure Managed Identities Client ID field. If no value is provided for the Azure Managed Identities Client ID field, authenticates based on the System Assigned Managed Identity. For additional information, see the Help tab. - display: Use Azure Managed Identities name: use_managed_identities required: false type: 8 -- additionalinfo: The Managed Identities client ID for authentication - relevant only if the integration is running on Azure VM. - displaypassword: Azure Managed Identities Client ID - name: managed_identities_client_id + display: Use Azure Managed Identities +- name: managed_identities_client_id required: false - hiddenusername: true type: 9 + additionalinfo: The managed identities client ID for authentication. Relevant only if the integration is running on Azure VM. + displaypassword: Azure Managed Identities Client ID + hiddenusername: true - display: Subscription ID name: subscription_id required: true @@ -252,7 +267,7 @@ script: secret: false - auto: PREDEFINED default: false - description: The default action when no rule from ip_rules and from vnet_subnet_id match. For example, If no ip_rules and vnet_subnet_id arguments are supplied, the access to the key vault from any IP address or virtual network will be accrodingly to the default_action value. If you wish to allow access only from specific virtual network or IP address, use the ip_rules or the vnet_subnet_id arguments. This is only used after the bypass property has been evaluated. Network acl property. + description: The default action when no rule from ip_rules and from vnet_subnet_id match. For example, If no ip_rules and vnet_subnet_id arguments are supplied, the access to the key vault from any IP address or virtual network will be according to the default_action value. If you wish to allow access only from specific virtual network or IP address, use the ip_rules or the vnet_subnet_id arguments. This is only used after the bypass property has been evaluated. Network ACL property. isArray: false name: default_action predefined: diff --git a/Packs/AzureKeyVault/Integrations/AzureKeyVault/README.md b/Packs/AzureKeyVault/Integrations/AzureKeyVault/README.md index 00a77d94f4c3..6622cabb6730 100644 --- a/Packs/AzureKeyVault/Integrations/AzureKeyVault/README.md +++ b/Packs/AzureKeyVault/Integrations/AzureKeyVault/README.md @@ -7,28 +7,44 @@ This integration was integrated and tested with version 2019-09-01 of AzureKeyVa 2. Search for Azure Key Vault. 3. Click **Add instance** to create and configure a new integration instance. - | **Parameter** | **Required** | - | --- | --- | - | Client ID | False | - | Client Secret | False | - | Tenant ID | True | - | Certificate Thumbprint | False | - | Private Key | False | - | Use Azure Managed Identities | False | - | Azure Managed Identities Client ID | False | - | Subscription ID | True | - | Resource Group Name | True | - | Fetches credentials | False | - | Key Vault names - comma seperated list of Key Vaults to fetch secrets from. | False | - | Secret names - comma seperated list of secrets to fetch. | False | - | Trust any certificate (not secure) | False | - | Use system proxy settings | False | - -4. Click **Test** to validate the URLs, token, and connection. + | **Parameter** | **Required** | + |-----------------------------------------------------------------------------|--------------| + | Azure Cloud | False | + | Client ID | False | + | Client Secret | False | + | Tenant ID | True | + | Certificate Thumbprint | False | + | Private Key | False | + | Use Azure Managed Identities | False | + | Azure Managed Identities Client ID | False | + | Subscription ID | True | + | Resource Group Name | True | + | Fetches credentials | False | + | Key Vault names - comma-separated list of Key Vaults to fetch secrets from. | False | + | Secret names - comma-separated list of secrets to fetch. | False | + | Trust any certificate (not secure) | False | + | Use system proxy settings | False | + +4. Azure cloud options + + | Azure Cloud | Description | + |-------------|--------------------------------------------------------------------------| + | Worldwide | The publicly accessible Azure Cloud | + | US GCC | Azure cloud for the USA Government Cloud Community (GCC) | + | US GCC-High | Azure cloud for the USA Government Cloud Community High (GCC-High) | + | DoD | Azure cloud for the USA Department of Defense (DoD) | + | Germany | Azure cloud for the German Government | + | China | Azure cloud for the Chinese Government | + +5. Click **Test** to validate the URLs, token, and connection. + ## Commands + You can execute these commands from the Cortex XSOAR CLI, as part of an automation, or in a playbook. After you successfully execute a command, a DBot message appears in the War Room with the command details. + ### azure-key-vault-create-update + *** Create or update a key vault in the specified subscription. If the Key Vault exists, the updated properties will overwrite the existing ones. Please use azure-key-vault-access-policy-update command if you wish to update the access policy of an existing Key Vault. @@ -36,6 +52,7 @@ Create or update a key vault in the specified subscription. If the Key Vault exi #### Base Command `azure-key-vault-create-update` + #### Input | **Argument Name** | **Description** | **Required** | @@ -51,7 +68,7 @@ Create or update a key vault in the specified subscription. If the Key Vault exi | enabled_for_deployment | Specifies whether Azure Virtual Machines are permitted to retrieve certificates stored as secrets from the key vault. If the Key Vault exists, you must supply the previous value in order to keep it the same. Default value is True. Possible values are: true, false. | Optional | | enabled_for_disk_encryption | Specifies whether Azure Disk Encryption is permitted to retrieve secrets from the vault and unwrap keys.If the Key Vault exists, you must supply the previous value in order to keep it the same. Default value is True. Possible values are: true, false. | Optional | | enabled_for_template_deployment | Specifies whether Azure Resource Manager is permitted to retrieve secrets from the key vault. If the Key Vault exists, you must supply the previous value in order to keep it the same. Default value is True. Possible values are: true, false. | Optional | -| default_action | The default action when no rule from ip_rules and from vnet_subnet_id match. For example, If no ip_rules and vnet_subnet_id arguments are supplied, the access to the key vault from any IP address or virtual network will be accrodingly to the default_action value. If you wish to allow access only from specific virtual network or IP address, use the ip_rules or the vnet_subnet_id arguments. This is only used after the bypass property has been evaluated. Network acl property. Possible values are: Allow, Deny. | Optional | +| default_action | The default action when no rule from ip_rules and from vnet_subnet_id match. For example, If no ip_rules and vnet_subnet_id arguments are supplied, the access to the key vault from any IP address or virtual network will be according to the default_action value. If you wish to allow access only from specific virtual network or IP address, use the ip_rules or the vnet_subnet_id arguments. This is only used after the bypass property has been evaluated. Network acl property. Possible values are: Allow, Deny. | Optional | | bypass | Tells what traffic can bypass network rules. This can be 'AzureServices' or 'None'. For example, use 'AzureServices' if you wish to give azure services access to key vault, although the default action is 'Deny' or the access for a specific IP address. Network acl property. Default value is 'AzureServices'. Possible values are: AzureServices, None. | Optional | | vnet_subnet_id | Allow accessibility of a vault from a specific virtual network. This argument must be the full resource ID of a virtual network subnet. For example, for the subnet ID "/subscriptions/subid/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/subnet1", you allow access to the Key Vault from subnet1. Network acl property. | Optional | | ignore_missing_vnet_service_endpoint | Specifies whether the Network Resource Provider will ignore the check if parent subnet has serviceEndpoints configured. This allows the configuration for the Key Vault to complete without error before the configuration to the virtual network's subnet is complete. Once the subnet configuration is complete, the Cosmos account will then be accessible through the configured subnet. Network Acl property. Possible values are: . Default is True. | Optional | @@ -77,17 +94,15 @@ Create or update a key vault in the specified subscription. If the Key Vault exi | AzureKeyVault.KeyVault.properties.enabledForDeployment | Boolean | Property to specify whether Azure Virtual Machines are permitted to retrieve certificates stored as secrets from the key vault. | | AzureKeyVault.KeyVault.properties.enabledForDiskEncryption | Boolean | Property to specify whether Azure Disk Encryption is permitted to retrieve secrets from the vault and unwrap keys. | | AzureKeyVault.KeyVault.properties.enabledForTemplateDeployment | Boolean | Property to specify whether Azure Resource Manager is permitted to retrieve secrets from the key vault. | -| AzureKeyVault.KeyVault.properties.vaultUri | String | The URI of the vault for performing operations on keys and secrets. -| -| AzureKeyVault.KeyVault.properties.provisioningState | String | The current provisioning state. - - | - +| AzureKeyVault.KeyVault.properties.vaultUri | String | The URI of the vault for performing operations on keys and secrets. | +| AzureKeyVault.KeyVault.properties.provisioningState | String | The current provisioning state. | #### Command Example + ```!azure-key-vault-create-update object_id=YOUR_OBJECT_ID vault_name=xsoar-test-285 keys=create,decrypt``` #### Context Example + ```json { "AzureKeyVault": { @@ -166,12 +181,14 @@ Create or update a key vault in the specified subscription. If the Key Vault exi #### Human Readable Output >### xsoar-test-285 Information +> >|Id|Name|Type|Location| >|---|---|---|---| >| /subscriptions/SUBSCRIPTION_ID/resourceGroups/test-group/providers/Microsoft.KeyVault/vaults/xsoar-test-285 | xsoar-test-285 | Microsoft.KeyVault/vaults | westus | ### azure-key-vault-delete + *** Delete the specified key vault. @@ -179,6 +196,7 @@ Delete the specified key vault. #### Base Command `azure-key-vault-delete` + #### Input | **Argument Name** | **Description** | **Required** | @@ -191,6 +209,7 @@ Delete the specified key vault. There is no context output for this command. #### Command Example + ```!azure-key-vault-delete vault_name=xsoar-test-262``` #### Human Readable Output @@ -198,6 +217,7 @@ There is no context output for this command. >Deleted Key Vault xsoar-test-262 successfully. ### azure-key-vault-get + *** Get the specified key vault. @@ -205,6 +225,7 @@ Get the specified key vault. #### Base Command `azure-key-vault-get` + #### Input | **Argument Name** | **Description** | **Required** | @@ -236,9 +257,11 @@ Get the specified key vault. #### Command Example + ```!azure-key-vault-get vault_name=xsoar-test-vault``` #### Context Example + ```json { "AzureKeyVault": { @@ -325,12 +348,14 @@ Get the specified key vault. #### Human Readable Output >### xsoar-test-vault Information +> >|Id|Name|Type|Location| >|---|---|---|---| >| /subscriptions/SUBSCRIPTION_ID/resourceGroups/test-group/providers/Microsoft.KeyVault/vaults/xsoar-test-vault | xsoar-test-vault | Microsoft.KeyVault/vaults | eastus | ### azure-key-vault-list + *** The List operation gets information about the vaults associated with the subscription. For a limit greater than 25, more than one API call will be required and the command might take longer time. @@ -338,6 +363,7 @@ The List operation gets information about the vaults associated with the subscri #### Base Command `azure-key-vault-list` + #### Input | **Argument Name** | **Description** | **Required** | @@ -370,9 +396,11 @@ The List operation gets information about the vaults associated with the subscri #### Command Example + ```!azure-key-vault-list limit=1``` #### Context Example + ```json { "AzureKeyVault": { @@ -459,12 +487,14 @@ The List operation gets information about the vaults associated with the subscri #### Human Readable Output >### Key Vaults List +> >|Id|Name|Type|Location| >|---|---|---|---| >| /subscriptions/SUBSCRIPTION_ID/resourceGroups/test-group/providers/Microsoft.KeyVault/vaults/xsoar-test-265 | xsoar-test-265 | Microsoft.KeyVault/vaults | eastasia | ### azure-key-vault-access-policy-update + *** Update access policies in a key vault in the specified subscription. The update regards only the access policy for the specified object ID. @@ -472,6 +502,7 @@ Update access policies in a key vault in the specified subscription. The update #### Base Command `azure-key-vault-access-policy-update` + #### Input | **Argument Name** | **Description** | **Required** | @@ -499,9 +530,11 @@ Update access policies in a key vault in the specified subscription. The update #### Command Example + ```!azure-key-vault-access-policy-update object_id=YOUR_OBJECT_ID operation_kind=add vault_name=xsoar-test-285 keys=import,list``` #### Context Example + ```json { "AzureKeyVault": { @@ -568,12 +601,14 @@ Update access policies in a key vault in the specified subscription. The update #### Human Readable Output >### xsoar-test-285 Updated Access Policy +> >|Id|Type| >|---|---| >| /subscriptions/SUBSCRIPTION_ID/resourceGroups/test-group/providers/Microsoft.KeyVault/vaults/xsoar-test-285/accessPolicies/ | Microsoft.KeyVault/vaults/accessPolicies | ### azure-key-vault-key-get + *** Get the public part of a stored key. This operation requires the keys/get permission. @@ -581,6 +616,7 @@ Get the public part of a stored key. This operation requires the keys/get permis #### Base Command `azure-key-vault-key-get` + #### Input | **Argument Name** | **Description** | **Required** | @@ -606,9 +642,11 @@ Get the public part of a stored key. This operation requires the keys/get permis #### Command Example + ```!azure-key-vault-key-get key_name=test-key-1 vault_name=xsoar-test-vault``` #### Context Example + ```json { "AzureKeyVault": { @@ -644,12 +682,14 @@ Get the public part of a stored key. This operation requires the keys/get permis #### Human Readable Output >### test-key-1 Information +> >|Key Id|Enabled|Json Web Key Type|Key Operations|Create Time|Update Time| >|---|---|---|---|---|---| ->| https://xsoar-test-vault.vault.azure.net/keys/test-key-1/KEY_VERSION | true | RSA | sign,
verify,
wrapKey,
unwrapKey,
encrypt,
decrypt | 2021-08-11T12:03:16 | 2021-08-11T12:03:16 | +>| | true | RSA | sign,
verify,
wrapKey,
unwrapKey,
encrypt,
decrypt | 2021-08-11T12:03:16 | 2021-08-11T12:03:16 | ### azure-key-vault-key-list + *** List keys in the specified vault. For a limit greater than 25, more than one API call will be required and the command might take longer time. This operation requires the keys/list permission. @@ -657,6 +697,7 @@ List keys in the specified vault. For a limit greater than 25, more than one API #### Base Command `azure-key-vault-key-list` + #### Input | **Argument Name** | **Description** | **Required** | @@ -679,9 +720,11 @@ List keys in the specified vault. For a limit greater than 25, more than one API #### Command Example + ```!azure-key-vault-key-list vault_name=xsoar-test-vault limit=1``` #### Context Example + ```json { "AzureKeyVault": { @@ -707,12 +750,14 @@ List keys in the specified vault. For a limit greater than 25, more than one API #### Human Readable Output >### xsoar-test-vault Keys List +> >|Key Id|Enabled|Create Time|Update Time|Expiry Time| >|---|---|---|---|---| ->| https://xsoar-test-vault.vault.azure.net/keys/test-cer-1 | false | 2021-08-11T12:05:48 | 2021-09-05T14:02:13 | 2022-08-11T12:05:48 | +>| | false | 2021-08-11T12:05:48 | 2021-09-05T14:02:13 | 2022-08-11T12:05:48 | ### azure-key-vault-key-delete + *** Delete a key of any type from storage in Azure Key vault. This operation requires the keys/delete permission. @@ -720,6 +765,7 @@ Delete a key of any type from storage in Azure Key vault. This operation require #### Base Command `azure-key-vault-key-delete` + #### Input | **Argument Name** | **Description** | **Required** | @@ -746,9 +792,11 @@ Delete a key of any type from storage in Azure Key vault. This operation require #### Command Example + ```!azure-key-vault-key-delete key_name=test-key-10 vault_name=xsoar-test-vault``` #### Context Example + ```json { "AzureKeyVault": { @@ -789,12 +837,14 @@ Delete a key of any type from storage in Azure Key vault. This operation require #### Human Readable Output >### Delete test-key-10 +> >|Key Id|Recovery Id|Deleted Date|Scheduled Purge Date| >|---|---|---|---| ->| https://xsoar-test-vault.vault.azure.net/keys/test-key-10/KEY_VERSION | https://xsoar-test-vault.vault.azure.net/deletedkeys/test-key-10 | 2021-11-01T12:52:40 | 2022-01-30T12:52:40 | +>| | | 2021-11-01T12:52:40 | 2022-01-30T12:52:40 | ### azure-key-vault-secret-get + *** Get a specified secret from a given key vault. The GET operation is applicable to any secret stored in Azure Key Vault. This operation requires the secrets/get permission. @@ -802,6 +852,7 @@ Get a specified secret from a given key vault. The GET operation is applicable t #### Base Command `azure-key-vault-secret-get` + #### Input | **Argument Name** | **Description** | **Required** | @@ -814,19 +865,21 @@ Get a specified secret from a given key vault. The GET operation is applicable t #### Context Output | **Path** | **Type** | **Description** | -| --- | --- | --- | -| AzureKeyVault.Secret.value | String | Secret value. | -| AzureKeyVault.Secret.id | String | Secret ID. | -| AzureKeyVault.Secret.attributes.enabled | Bolean | Determines whether the object is enabled. | -| AzureKeyVault.Secret.attributes.created | Date | Creation time in UTC. | -| AzureKeyVault.Secret.attributes.updated | Date | Last updated time in UTC. | -| AzureKeyVault.Secret.attributes.recoveryLevel | String | Reflects the deletion recovery level currently in effect for secrets in the current vault. If it contains 'Purgeable', the secret can be permanently deleted by a privileged user; otherwise, only the system can purge the secret, at the end of the retention interval. | +| --- |----------| --- | +| AzureKeyVault.Secret.value | String | Secret value. | +| AzureKeyVault.Secret.id | String | Secret ID. | +| AzureKeyVault.Secret.attributes.enabled | Boolean | Determines whether the object is enabled. | +| AzureKeyVault.Secret.attributes.created | Date | Creation time in UTC. | +| AzureKeyVault.Secret.attributes.updated | Date | Last updated time in UTC. | +| AzureKeyVault.Secret.attributes.recoveryLevel | String | Reflects the deletion recovery level currently in effect for secrets in the current vault. If it contains 'Purgeable', the secret can be permanently deleted by a privileged user; otherwise, only the system can purge the secret, at the end of the retention interval. | #### Command Example + ```!azure-key-vault-secret-get secret_name=test-sec-1 vault_name=xsoar-test-vault``` #### Context Example + ```json { "AzureKeyVault": { @@ -853,12 +906,14 @@ Get a specified secret from a given key vault. The GET operation is applicable t #### Human Readable Output >### test-sec-1 Information +> >|Secret Id|Enabled|Create Time|Update Time|Expiry Time| >|---|---|---|---|---| ->| https://xsoar-test-vault.vault.azure.net/secrets/test-sec-1/SECRET_VERSION | true | 2021-08-11T12:04:12 | 2021-08-17T16:22:57 | 2023-08-11T12:04:06 | +>| | true | 2021-08-11T12:04:12 | 2021-08-17T16:22:57 | 2023-08-11T12:04:06 | ### azure-key-vault-secret-list + *** List secrets in a specified key vault. For a limit greater than 25, more than one API call will be required and the command might take longer time. This operation requires the secrets/list permission. @@ -866,6 +921,7 @@ List secrets in a specified key vault. For a limit greater than 25, more than on #### Base Command `azure-key-vault-secret-list` + #### Input | **Argument Name** | **Description** | **Required** | @@ -878,21 +934,23 @@ List secrets in a specified key vault. For a limit greater than 25, more than on #### Context Output | **Path** | **Type** | **Description** | -| --- | --- | --- | -| AzureKeyVault.Secret.id | String | Secret ID. | -| AzureKeyVault.Secret.attributes.enabled | Bolean | Determines whether the object is enabled. | -| AzureKeyVault.Secret.attributes.nbf | Date | Not before date in UTC. | -| AzureKeyVault.Secret.attributes.exp | Date | Expiry date in UTC. | -| AzureKeyVault.Secret.attributes.created | Date | Creation time in UTC. | -| AzureKeyVault.Secret.attributes.updated | Date | Last updated time in UTC. | -| AzureKeyVault.Secret.attributes.recoveryLevel | String | Reflects the deletion recovery level currently in effect for secrets in the current vault. If it contains 'Purgeable', the secret can be permanently deleted by a privileged user; otherwise, only the system can purge the secret, at the end of the retention interval. | -| AzureKeyVault.Secret.attributes.recoverableDays | Number | Soft Delete data retention days. Value should be >=7 and <=90 when softDelete enabled, otherwise 0. | +| --- |----------| --- | +| AzureKeyVault.Secret.id | String | Secret ID. | +| AzureKeyVault.Secret.attributes.enabled | Boolean | Determines whether the object is enabled. | +| AzureKeyVault.Secret.attributes.nbf | Date | Not before date in UTC. | +| AzureKeyVault.Secret.attributes.exp | Date | Expiry date in UTC. | +| AzureKeyVault.Secret.attributes.created | Date | Creation time in UTC. | +| AzureKeyVault.Secret.attributes.updated | Date | Last updated time in UTC. | +| AzureKeyVault.Secret.attributes.recoveryLevel | String | Reflects the deletion recovery level currently in effect for secrets in the current vault. If it contains 'Purgeable', the secret can be permanently deleted by a privileged user; otherwise, only the system can purge the secret, at the end of the retention interval. | +| AzureKeyVault.Secret.attributes.recoverableDays | Number | Soft Delete data retention days. Value should be >=7 and <=90 when softDelete enabled, otherwise 0. | #### Command Example + ```!azure-key-vault-secret-list vault_name=xsoar-test-vault limit=1``` #### Context Example + ```json { "AzureKeyVault": { @@ -919,12 +977,14 @@ List secrets in a specified key vault. For a limit greater than 25, more than on #### Human Readable Output >### xsoar-test-vault Secrets List +> >|Secret Id|Enabled|Create Time|Update Time|Expiry Time| >|---|---|---|---|---| ->| https://xsoar-test-vault.vault.azure.net/secrets/test-cer-1 | false | 2021-08-11T12:05:48 | 2021-09-05T14:02:13 | 2022-08-11T12:05:48 | +>| | false | 2021-08-11T12:05:48 | 2021-09-05T14:02:13 | 2022-08-11T12:05:48 | ### azure-key-vault-secret-delete + *** Delete a secret from a specified key vault. This operation requires the secrets/delete permission. @@ -932,6 +992,7 @@ Delete a secret from a specified key vault. This operation requires the secrets/ #### Base Command `azure-key-vault-secret-delete` + #### Input | **Argument Name** | **Description** | **Required** | @@ -955,9 +1016,11 @@ Delete a secret from a specified key vault. This operation requires the secrets/ #### Command Example + ```!azure-key-vault-secret-delete secret_name=test-sec-10 vault_name=xsoar-test-vault``` #### Context Example + ```json { "AzureKeyVault": { @@ -984,12 +1047,14 @@ Delete a secret from a specified key vault. This operation requires the secrets/ #### Human Readable Output >### Delete test-sec-10 +> >|Secret Id|Recovery Id|Deleted Date|Scheduled Purge Date| >|---|---|---|---| ->| https://xsoar-test-vault.vault.azure.net/secrets/test-sec-10/SECRET_VERSION | https://xsoar-test-vault.vault.azure.net/deletedsecrets/test-sec-10 | 2021-11-01T12:52:54 | 2022-01-30T12:52:54 | +>| | | 2021-11-01T12:52:54 | 2022-01-30T12:52:54 | ### azure-key-vault-certificate-get + *** Gets information about a specific certificate. This operation requires the certificates/get permission. @@ -997,6 +1062,7 @@ Gets information about a specific certificate. This operation requires the certi #### Base Command `azure-key-vault-certificate-get` + #### Input | **Argument Name** | **Description** | **Required** | @@ -1024,9 +1090,11 @@ Gets information about a specific certificate. This operation requires the certi #### Command Example + ```!azure-key-vault-certificate-get certificate_name=test-cer-1 vault_name=xsoar-test-vault``` #### Context Example + ```json { "AzureKeyVault": { @@ -1106,12 +1174,14 @@ Gets information about a specific certificate. This operation requires the certi #### Human Readable Output >### test-cer-1 Information +> >|Certificate Id|Enabled|Create Time|Update Time|Expiry Time| >|---|---|---|---|---| ->| https://xsoar-test-vault.vault.azure.net/certificates/test-cer-1/CERTIFICATE_VERSION | false | 2021-08-11T12:05:48 | 2021-09-05T14:02:13 | 2022-08-11T12:05:48 | +>| | false | 2021-08-11T12:05:48 | 2021-09-05T14:02:13 | 2022-08-11T12:05:48 | ### azure-key-vault-certificate-list + *** List certificates in a specified key vault. For a limit greater than 25, more than one API call will be required and the command might take longer time. This operation requires the certificates/list permission. @@ -1119,6 +1189,7 @@ List certificates in a specified key vault. For a limit greater than 25, more th #### Base Command `azure-key-vault-certificate-list` + #### Input | **Argument Name** | **Description** | **Required** | @@ -1140,9 +1211,11 @@ List certificates in a specified key vault. For a limit greater than 25, more th #### Command Example + ```!azure-key-vault-certificate-list vault_name=xsoar-test-vault limit=1``` #### Context Example + ```json { "AzureKeyVault": { @@ -1167,12 +1240,14 @@ List certificates in a specified key vault. For a limit greater than 25, more th #### Human Readable Output >### xsoar-test-vault Certificates List +> >|Certificate Id|Enabled|Create Time|Update Time|Expiry Time| >|---|---|---|---|---| ->| https://xsoar-test-vault.vault.azure.net/certificates/test-cer-1 | false | 2021-08-11T12:05:48 | 2021-09-05T14:02:13 | 2022-08-11T12:05:48 | +>| | false | 2021-08-11T12:05:48 | 2021-09-05T14:02:13 | 2022-08-11T12:05:48 | ### azure-key-vault-certificate-policy-get + *** Get the policy of the specified certificate.This operation requires the certificates/get permission. @@ -1180,6 +1255,7 @@ Get the policy of the specified certificate.This operation requires the certific #### Base Command `azure-key-vault-certificate-policy-get` + #### Input | **Argument Name** | **Description** | **Required** | @@ -1203,9 +1279,11 @@ Get the policy of the specified certificate.This operation requires the certific #### Command Example + ```!azure-key-vault-certificate-policy-get certificate_name=test-cer-1 vault_name=xsoar-test-vault``` #### Context Example + ```json { "AzureKeyVault": { @@ -1265,7 +1343,8 @@ Get the policy of the specified certificate.This operation requires the certific #### Human Readable Output >### test-cer-1 Policy Information +> >|Id|Key Props|Secret Props|X509 Props|Issuer|Attributes| >|---|---|---|---|---|---| ->| https://xsoar-test-vault.vault.azure.net/certificates/test-cer-1/policy | exportable: true
kty: RSA
key_size: 2048
reuse_key: false | contentType: application/x-pkcs12 | subject: CN=test
sans: {"dns_names": []}
ekus: 1.3.6.1.5.5.7.3.1,
1.3.6.1.5.5.7.3.2
key_usage: digitalSignature,
keyEncipherment
validity_months: 12
basic_constraints: {"ca": false} | name: Self | enabled: true
created: 2021-08-11T12:05:31
updated: 2021-08-11T12:05:31 | +>| | exportable: true
kty: RSA
key_size: 2048
reuse_key: false | contentType: application/x-pkcs12 | subject: CN=test
sans: {"dns_names": []}
ekus: 1.3.6.1.5.5.7.3.1,
1.3.6.1.5.5.7.3.2
key_usage: digitalSignature,
keyEncipherment
validity_months: 12
basic_constraints: {"ca": false} | name: Self | enabled: true
created: 2021-08-11T12:05:31
updated: 2021-08-11T12:05:31 | diff --git a/Packs/AzureKeyVault/ReleaseNotes/1_1_20.md b/Packs/AzureKeyVault/ReleaseNotes/1_1_20.md new file mode 100644 index 000000000000..15d233bbe69b --- /dev/null +++ b/Packs/AzureKeyVault/ReleaseNotes/1_1_20.md @@ -0,0 +1,7 @@ +#### Integrations + +##### Azure Key Vault + +- Updated the Docker image to: *demisto/crypto:1.0.0.63672*. +- Added support for All Azure Cloud environments: Public, GCC, GCC-High, DoD, Germany, China. + diff --git a/Packs/AzureKeyVault/pack_metadata.json b/Packs/AzureKeyVault/pack_metadata.json index 77a7ae46edeb..8b021ea32ec7 100644 --- a/Packs/AzureKeyVault/pack_metadata.json +++ b/Packs/AzureKeyVault/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Azure Key Vault", "description": "Use Key Vault to safeguard and manage cryptographic keys and secrets used by cloud applications and services.", "support": "xsoar", - "currentVersion": "1.1.19", + "currentVersion": "1.1.20", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/AzureKubernetesServices/.pack-ignore b/Packs/AzureKubernetesServices/.pack-ignore index 2daeb9f33a87..d7f20e26db94 100644 --- a/Packs/AzureKubernetesServices/.pack-ignore +++ b/Packs/AzureKubernetesServices/.pack-ignore @@ -1,2 +1,19 @@ [file:AzureKubernetesServices_image.png] -ignore=IM111 \ No newline at end of file +ignore=IM111 + +[known_words] +auth +VM +Kubernetes +DNS +FQDN +VNs +SSH +RBAC +plugin +CIDR +kubenet +containerized +VMs +GCC +D diff --git a/Packs/AzureKubernetesServices/Integrations/AzureKubernetesServices/AzureKubernetesServices.py b/Packs/AzureKubernetesServices/Integrations/AzureKubernetesServices/AzureKubernetesServices.py index 42cc08308ce6..aa5bcd1950af 100644 --- a/Packs/AzureKubernetesServices/Integrations/AzureKubernetesServices/AzureKubernetesServices.py +++ b/Packs/AzureKubernetesServices/Integrations/AzureKubernetesServices/AzureKubernetesServices.py @@ -2,6 +2,8 @@ from CommonServerPython import * from CommonServerUserPython import * +from MicrosoftApiModule import * # noqa: E402 + import urllib3 urllib3.disable_warnings() @@ -11,21 +13,25 @@ class AKSClient: def __init__(self, app_id: str, subscription_id: str, resource_group_name: str, verify: bool, proxy: bool, - azure_ad_endpoint: str = 'https://login.microsoftonline.com', tenant_id: str = None, + tenant_id: str = None, enc_key: str = None, auth_type: str = 'Device Code', redirect_uri: str = None, auth_code: str = None, - managed_identities_client_id: str = None): - AUTH_TYPES_DICT: dict[str, Any] = { + managed_identities_client_id: str = None, + azure_cloud: Optional[AzureCloud] = None, + ): + azure_cloud = azure_cloud or AZURE_WORLDWIDE_CLOUD + auth_types_dict: dict[str, Any] = { 'Authorization Code': { 'grant_type': AUTHORIZATION_CODE, 'resource': None, - 'scope': 'https://management.azure.com/.default' + 'scope': urljoin(azure_cloud.endpoints.resource_manager, '.default'), }, 'Device Code': { 'grant_type': DEVICE_CODE, - 'resource': 'https://management.core.windows.net', - 'scope': 'https://management.azure.com/user_impersonation offline_access user.read' + 'resource': azure_cloud.endpoints.management, + 'scope': urljoin(azure_cloud.endpoints.resource_manager, 'user_impersonation offline_access user.read'), } } + if '@' in app_id: app_id, refresh_token = app_id.split('@') integration_context = get_integration_context() @@ -35,14 +41,14 @@ def __init__(self, app_id: str, subscription_id: str, resource_group_name: str, client_args = assign_params( self_deployed=True, auth_id=app_id, - token_retrieval_url='https://login.microsoftonline.com/organizations/oauth2/v2.0/token', - grant_type=AUTH_TYPES_DICT.get(auth_type, {}).get('grant_type'), - base_url=f'https://management.azure.com/subscriptions/{subscription_id}', + token_retrieval_url=urljoin(azure_cloud.endpoints.active_directory, 'organizations/oauth2/v2.0/token'), + grant_type=auth_types_dict.get(auth_type, {}).get('grant_type'), + base_url=urljoin(azure_cloud.endpoints.resource_manager, f'subscriptions/{subscription_id}'), verify=verify, proxy=proxy, - resource=AUTH_TYPES_DICT.get(auth_type, {}).get('resource'), - scope=AUTH_TYPES_DICT.get(auth_type, {}).get('scope'), - azure_ad_endpoint=azure_ad_endpoint, + resource=auth_types_dict.get(auth_type, {}).get('resource'), + scope=auth_types_dict.get(auth_type, {}).get('scope'), + azure_ad_endpoint=azure_cloud.endpoints.active_directory, tenant_id=tenant_id, enc_key=enc_key, redirect_uri=redirect_uri, @@ -202,6 +208,7 @@ def main() -> None: demisto.debug(f'Command being called is {command}') try: + azure_cloud = get_azure_cloud(params, 'AzureKubernetesServices') client = AKSClient( tenant_id=params.get('tenant_id'), auth_type=params.get('auth_type', 'Device Code'), @@ -213,14 +220,13 @@ def main() -> None: resource_group_name=params.get('resource_group_name', ''), verify=not params.get('insecure', False), proxy=params.get('proxy', False), - azure_ad_endpoint=params.get('azure_ad_endpoint', - 'https://login.microsoftonline.com') or 'https://login.microsoftonline.com', + azure_cloud=azure_cloud, managed_identities_client_id=get_azure_managed_identities_client_id(params) ) if command == 'test-module': return_results(test_module(client)) elif command == 'azure-ks-generate-login-url': - return_results(generate_login_url(client.ms_client)) + return_results(generate_login_url(client.ms_client, login_url=azure_cloud.endpoints.active_directory)) elif command == 'azure-ks-auth-start': return_results(start_auth(client)) elif command == 'azure-ks-auth-complete': @@ -239,8 +245,5 @@ def main() -> None: return_error(f'Failed to execute {demisto.command()} command.\nError:\n{str(e)}', e) -from MicrosoftApiModule import * # noqa: E402 - - if __name__ in ('__main__', '__builtin__', 'builtins'): main() diff --git a/Packs/AzureKubernetesServices/Integrations/AzureKubernetesServices/AzureKubernetesServices.yml b/Packs/AzureKubernetesServices/Integrations/AzureKubernetesServices/AzureKubernetesServices.yml index 4314b480dbbe..09a0ba5c7da2 100644 --- a/Packs/AzureKubernetesServices/Integrations/AzureKubernetesServices/AzureKubernetesServices.yml +++ b/Packs/AzureKubernetesServices/Integrations/AzureKubernetesServices/AzureKubernetesServices.yml @@ -3,48 +3,65 @@ commonfields: id: Azure Kubernetes Services version: -1 configuration: -- defaultvalue: ab217a43-e09b-4f80-ae93-482fc7a3d1a3 - display: Application ID +- defaultvalue: Worldwide + display: Azure Cloud + name: azure_cloud + required: false + type: 15 + options: + - Worldwide + - US GCC + - US GCC-High + - DoD + - Germany + - China + - Custom + additionalinfo: When selecting the Custom option, the Azure AD endpoint parameter must be filled. More information about National clouds can be found here - https://xsoar.pan.dev/docs/reference/articles/microsoft-integrations---authentication#using-national-cloud + section: Connect + advanced: true +- display: Application ID name: app_id required: false + defaultvalue: ab217a43-e09b-4f80-ae93-482fc7a3d1a3 type: 0 -- additionalinfo: Type of authentication - can be Authorization Code Flow (recommended), Device Code Flow, or Azure Managed Identities. - display: Authentication Type + hidden: false +- display: Authentication Type name: auth_type required: true + type: 15 + additionalinfo: Type of authentication. Can be Authorization Code Flow (recommended), Device Code Flow, or Azure Managed Identities. defaultvalue: Device Code options: - Authorization Code - Device Code - Azure Managed Identities - type: 15 - display: Tenant ID (for authorization code mode) name: tenant_id required: false type: 0 - display: Client Secret (for authorization code mode) - displaypassword: Client Secret (for authorization code mode) - hiddenusername: true name: credentials required: false type: 9 + displaypassword: Client Secret (for authorization code mode) + hiddenusername: true - display: Application redirect URI (for authorization code mode) name: redirect_uri required: false type: 0 -- display: Authorization code +- additionalinfo: For user-auth mode - received from the authorization step. See Detailed Instructions (?) section displaypassword: Authorization code - additionalinfo: for user-auth mode - received from the authorization step. see Detailed Instructions (?) section - hiddenusername: true name: auth_code required: false + hiddenusername: true type: 9 -- additionalinfo: The Managed Identities client id for authentication - relevant only if the integration is running on Azure VM. - displaypassword: Azure Managed Identities Client ID - name: managed_identities_client_id + display: Authorization code +- name: managed_identities_client_id required: false - hiddenusername: true type: 9 + additionalinfo: The Managed Identities client ID for authentication. Relevant only if the integration is running on Azure VM. + displaypassword: Azure Managed Identities Client ID + hiddenusername: true - display: Subscription ID name: subscription_id required: true @@ -53,17 +70,6 @@ configuration: name: resource_group_name required: true type: 0 -- defaultvalue: https://login.microsoftonline.com - display: Azure AD endpoint - name: azure_ad_endpoint - options: - - https://login.microsoftonline.com - - https://login.microsoftonline.us - - https://login.microsoftonline.de - - https://login.chinacloudapi.cn - required: false - type: 15 - additionalinfo: Azure AD endpoint associated with a national cloud. - display: Trust any certificate (not secure) name: insecure required: false @@ -72,6 +78,14 @@ configuration: name: proxy required: false type: 8 +- defaultvalue: https://login.microsoftonline.com + display: Azure AD endpoint + name: azure_ad_endpoint + required: false + type: 0 + advanced: true + additionalinfo: Use this option when required to customize the URL to the Azure Active Directory endpoint. More information can be found here - https://xsoar.pan.dev/docs/reference/articles/microsoft-integrations---authentication#using-national-cloud + section: Connect description: Deploy and manage containerized applications with a fully managed Kubernetes service. display: Azure Kubernetes Services name: Azure Kubernetes Services @@ -288,7 +302,7 @@ script: execution: false name: azure-ks-generate-login-url arguments: [] - dockerimage: demisto/crypto:1.0.0.52480 + dockerimage: demisto/crypto:1.0.0.63672 feed: false isfetch: false longRunning: false @@ -298,3 +312,5 @@ script: subtype: python3 type: python fromversion: 5.0.0 +tests: +- No tests (auto formatted) diff --git a/Packs/AzureKubernetesServices/Integrations/AzureKubernetesServices/AzureKubernetesServices_test.py b/Packs/AzureKubernetesServices/Integrations/AzureKubernetesServices/AzureKubernetesServices_test.py index 26eba95545bc..11b5e39403d0 100644 --- a/Packs/AzureKubernetesServices/Integrations/AzureKubernetesServices/AzureKubernetesServices_test.py +++ b/Packs/AzureKubernetesServices/Integrations/AzureKubernetesServices/AzureKubernetesServices_test.py @@ -9,12 +9,13 @@ app_id = 'app_id' subscription_id = 'subscription_id' resource_group_name = 'resource_group_name' +tenant_id = 'tentant_id' @pytest.fixture() def client(mocker): mocker.patch('AzureKubernetesServices.MicrosoftClient.get_access_token', return_value='token') - return AKSClient(app_id, subscription_id, resource_group_name, False, False, 'Device') + return AKSClient(app_id, subscription_id, resource_group_name, False, False, tenant_id, None, 'Device Code') def load_test_data(path): @@ -191,4 +192,4 @@ def test_generate_login_url(mocker): 'response_type=code&scope=offline_access%20https://management.azure.com/.default' \ f'&client_id={client_id}&redirect_uri={redirect_uri})' res = AzureKubernetesServices.return_results.call_args[0][0].readable_output - assert expected_url in res + assert expected_url in res, "Login URL is incorrect" diff --git a/Packs/AzureKubernetesServices/Integrations/AzureKubernetesServices/README.md b/Packs/AzureKubernetesServices/Integrations/AzureKubernetesServices/README.md index 716c786c6da7..2679a3cc8d3a 100644 --- a/Packs/AzureKubernetesServices/Integrations/AzureKubernetesServices/README.md +++ b/Packs/AzureKubernetesServices/Integrations/AzureKubernetesServices/README.md @@ -2,6 +2,7 @@ Deploy and manage containerized applications with a fully managed Kubernetes ser This integration was integrated and tested with API version 2021-09-01 of AKS. # Self-Deployed Application + To use a self-configured Azure application, you need to add a [new Azure App Registration in the Azure Portal](https://docs.microsoft.com/en-us/graph/auth-register-app-v2#register-a-new-application-using-the-azure-portal). * The application must have **user_impersonation** permission (can be found in *API permissions* section of the Azure Kubernetes Services app registrations). @@ -29,6 +30,7 @@ Follow these steps for a self-deployed configuration: In order to use the Cortex XSOAR Azure application, use the default application ID (ab217a43-e09b-4f80-ae93-482fc7a3d1a3). ### Authentication Using the Device Code Flow + Follow these steps for a self-deployed configuration: 1. Fill in the required parameters. @@ -45,28 +47,45 @@ At end of the process you'll see a message that you've logged in successfully. 2. Search for Azure Kubernetes Services. 3. Click **Add instance** to create and configure a new integration instance. - | **Parameter** | **Description** | **Required** | - | --- | --- | --- | - | app_id | Application ID | False | - | subscription_id | Subscription ID | True | - | resource_group_name | Resource Group Name | True | - | azure_ad_endpoint | Azure AD endpoint associated with a national cloud | False | - | insecure | Trust any certificate \(not secure\) | False | - | proxy | Use system proxy settings | False | - | Tenant ID (for User Auth mode) | Tenant ID | False | - | Client Secret (for User Auth mode) | Encryption key given by the admin | False | - | Authentication Type | The request authentication type for the instance | False | - | Authorization code | as received from the authorization step | False | - | Application redirect URI | the redirect URI entered in the Azure portal | False | - | Azure Managed Identities Client ID | False | - - -4. Click **Test** to validate the URLs, token, and connection. + | **Parameter** | **Description** | **Required** | + |------------------------------------|----------------------------------------------------------------------------------------------------------------|--------------| + | Azure Cloud | Azure Cloud the K8S cluster resides in. See table below. | False | + | app_id | Application ID | False | + | subscription_id | Subscription ID | True | + | resource_group_name | Resource Group Name | True | + | azure_ad_endpoint | Azure AD endpoint associated with a national cloud. See note below. | False | + | insecure | Trust any certificate \(not secure\) | False | + | proxy | Use system proxy settings | False | + | Tenant ID (for User Auth mode) | Tenant ID | False | + | Client Secret (for User Auth mode) | Encryption key given by the admin | False | + | Authentication Type | The request authentication type for the instance | False | + | Authorization code | Received from the authorization step | False | + | Application redirect URI | The redirect URI entered in the Azure portal | False | + | Azure Managed Identities Client ID | The managed identities client ID for authentication. Relevant only if the integration is running on Azure VM. | False | + +4. Azure cloud options + + | Azure Cloud | Description | + |-------------|--------------------------------------------------------------------------| + | Worldwide | The publicly accessible Azure Cloud | + | US GCC | Azure cloud for the USA Government Cloud Community (GCC) | + | US GCC-High | Azure cloud for the USA Government Cloud Community High (GCC-High) | + | DoD | Azure cloud for the USA Department of Defense (DoD) | + | Germany | Azure cloud for the German Government | + | China | Azure cloud for the Chinese Government | + | Custom | Custom endpoint configuration to the Azure cloud. See note below. | + + * Note: In most cases, setting Azure cloud is preferred to setting Azure AD endpoint. Only use it in cases where a custom proxy URL is required for accessing a national cloud. + +5. Click **Test** to validate the URLs, token, and connection. ## Commands + You can execute these commands from the Cortex XSOAR CLI, as part of an automation, or in a playbook. After you successfully execute a command, a DBot message appears in the War Room with the command details. + ### azure-ks-auth-test + *** Tests the connectivity to Azure. @@ -74,15 +93,18 @@ Tests the connectivity to Azure. #### Base Command `azure-ks-auth-test` + #### Input There are no input arguments for this command. #### Human Readable Output +> >✅ Success! ### azure-ks-auth-start + *** Run this command to start the authorization process and follow the instructions in the command results. @@ -90,12 +112,15 @@ Run this command to start the authorization process and follow the instructions #### Base Command `azure-ks-auth-start` + #### Input There are no input arguments for this command. #### Human Readable Output +> >### Authorization instructions +> > 1. To sign in, use a web browser to open the page: > [https://microsoft.com/devicelogin](https://microsoft.com/devicelogin) > and enter the code **XXXXXXXX** to authenticate. @@ -104,6 +129,7 @@ There are no input arguments for this command. ### azure-ks-auth-complete + *** Run this command to complete the authorization process. Should be used after running the ***azure-ks-auth-start*** command. @@ -111,15 +137,18 @@ Run this command to complete the authorization process. Should be used after run #### Base Command `azure-ks-auth-complete` + #### Input There are no input arguments for this command. #### Human Readable Output +> >✅ Authorization completed successfully. ### azure-ks-auth-reset + *** Run this command if for some reason you need to rerun the authentication process. @@ -127,6 +156,7 @@ Run this command if for some reason you need to rerun the authentication process #### Base Command `azure-ks-auth-reset` + #### Input There are no input arguments for this command. @@ -136,6 +166,7 @@ There are no input arguments for this command. >Authorization was reset successfully. You can now run ***!azure-ks-auth-start*** and ***!azure-ks-auth-complete***. ### azure-ks-clusters-list + *** Gets a list of managed clusters in the specified subscription. @@ -143,6 +174,7 @@ Gets a list of managed clusters in the specified subscription. #### Base Command `azure-ks-clusters-list` + #### Input There are no input arguments for this command. @@ -186,9 +218,11 @@ There are no input arguments for this command. #### Command Example -```!azure-ks-clusters-list``` + +`!azure-ks-clusters-list` #### Context Example + ```json { "AzureKS": { @@ -264,12 +298,14 @@ There are no input arguments for this command. #### Human Readable Output >### AKS Clusters List +> >|Name|Status|Location|Tags|Kubernetes version|API server address|Network type (plugin)| >|---|---|---|---|---|---|---| >| clustername1 | Succeeded | location1 | tier: production | 1.9.6 | dnsprefix1-abcd1234.hcp.eastus.azmk8s.io | kubenet | ### azure-ks-cluster-addon-update + *** Updates a managed cluster with the specified configuration. @@ -277,6 +313,7 @@ Updates a managed cluster with the specified configuration. #### Base Command `azure-ks-cluster-addon-update` + #### Input | **Argument Name** | **Description** | **Required** | @@ -293,7 +330,8 @@ Updates a managed cluster with the specified configuration. There is no context output for this command. #### Command Example -```!azure-ks-cluster-addon-update resource_name=aks-integration location=westus http_application_routing_enabled=true``` + +`!azure-ks-cluster-addon-update resource_name=aks-integration location=westus http_application_routing_enabled=true` #### Human Readable Output @@ -301,12 +339,14 @@ There is no context output for this command. ### azure-ks-generate-login-url + *** Generate the login url used for Authorization code flow. #### Base Command `azure-ks-generate-login-url` + #### Input There are no input arguments for this command. @@ -316,14 +356,16 @@ There are no input arguments for this command. There is no context output for this command. #### Command Example -```azure-ks-generate-login-url``` + +`azure-ks-generate-login-url` #### Human Readable Output >### Authorization instructions ->1. Click on the [login URL]() to sign in and grant Cortex XSOAR permissions for your Azure Service Management. +> +>1. Click the [login URL](https://login.microsoftonline.com) to sign in and grant Cortex XSOAR permissions for your Azure Service Management. You will be automatically redirected to a link with the following structure: -```REDIRECT_URI?code=AUTH_CODE&session_state=SESSION_STATE``` +`REDIRECT_URI?code=AUTH_CODE&session_state=SESSION_STATE` >2. Copy the `AUTH_CODE` (without the `code=` prefix, and the `session_state` parameter) and paste it in your instance configuration under the **Authorization code** parameter. diff --git a/Packs/AzureKubernetesServices/ReleaseNotes/1_1_13.md b/Packs/AzureKubernetesServices/ReleaseNotes/1_1_13.md new file mode 100644 index 000000000000..e7042d31787f --- /dev/null +++ b/Packs/AzureKubernetesServices/ReleaseNotes/1_1_13.md @@ -0,0 +1,11 @@ + +#### Integrations + +##### Azure Kubernetes Services + +- Updated the Docker image to: *demisto/crypto:1.0.0.63672*. + + + +- Added support for All Azure Cloud environments: Public, GCC, GCC-High, DoD, Germany, China. + diff --git a/Packs/AzureKubernetesServices/pack_metadata.json b/Packs/AzureKubernetesServices/pack_metadata.json index 08c2717b84c1..8fad43562c39 100644 --- a/Packs/AzureKubernetesServices/pack_metadata.json +++ b/Packs/AzureKubernetesServices/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Azure Kubernetes Services", "description": "Deploy and manage containerized applications with a fully managed Kubernetes service.", "support": "xsoar", - "currentVersion": "1.1.12", + "currentVersion": "1.1.13", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/AzureSentinel/.pack-ignore b/Packs/AzureSentinel/.pack-ignore index f45e1c5a5c1f..7bb33d4306e4 100644 --- a/Packs/AzureSentinel/.pack-ignore +++ b/Packs/AzureSentinel/.pack-ignore @@ -1,2 +1,51 @@ [file:AzureSentinel.yml] ignore=IN126 + +[known_words] +URLs +mappers +DBot +Assignee +UTC +Etag +Sharepoint +br +gt +watchlists +CSV +Dns +IoTDevice +aad +kkk +upn +Boolean +Etags +pagination +Mappings +lookback +severities +displayname +AWSCloudTrail +Principalid +AWS +VPC +abcd +efgh +VM +T +Hn +Tn +Mn +D +Pn +S +W +f +anonymization +Appends +AWSClou +n +Eleme +Respo +ts +GCC diff --git a/Packs/AzureSentinel/.secrets-ignore b/Packs/AzureSentinel/.secrets-ignore index dbe54960c766..b61926edc06d 100644 --- a/Packs/AzureSentinel/.secrets-ignore +++ b/Packs/AzureSentinel/.secrets-ignore @@ -10,4 +10,9 @@ https://oproxy.demisto.ninja/ms-azure-sentinel /bs-latn-ba/azure/search/search-query-odata-filter https://xsoar.pan.dev https://techcommunity.microsoft.com/t5/azure-sentinel/get-entities-for-a-sentinel-incidient-by-api/m-p/1422643 -https://portal.azure.com \ No newline at end of file +https://portal.azure.com +https://gallery.azure.com +https://portal.azure.cn +https://portal.azure.us +https://vault.azure.cn +https://vault.azure.net diff --git a/Packs/AzureSentinel/Integrations/AzureSentinel/AzureSentinel.py b/Packs/AzureSentinel/Integrations/AzureSentinel/AzureSentinel.py index 06537f2af44d..283be8eb9415 100644 --- a/Packs/AzureSentinel/Integrations/AzureSentinel/AzureSentinel.py +++ b/Packs/AzureSentinel/Integrations/AzureSentinel/AzureSentinel.py @@ -1,14 +1,17 @@ -import demistomock as demisto -from CommonServerPython import * -from CommonServerUserPython import * +import demistomock as demisto # noqa +from CommonServerPython import * # noqa +from CommonServerUserPython import * # noqa # IMPORTS +from typing import Union import json import urllib3 import requests import dateparser import uuid +from MicrosoftApiModule import * # noqa: E402 + # Disable insecure warnings urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) @@ -21,9 +24,7 @@ API_VERSION = '2022-11-01' -DEFAULT_AZURE_SERVER_URL = 'https://management.azure.com' - -NEXTLINK_DESCRIPTION = 'NextLink for listing commands' +NEXT_LINK_DESCRIPTION = 'NextLink for listing commands' XSOAR_USER_AGENT = 'SentinelPartner-PaloAltoNetworks-CortexXsoar/1.0.0' @@ -78,16 +79,17 @@ class AzureSentinelClient: - def __init__(self, server_url: str, tenant_id: str, client_id: str, + def __init__(self, tenant_id: str, client_id: str, client_secret: str, subscription_id: str, resource_group_name: str, workspace_name: str, certificate_thumbprint: Optional[str], private_key: Optional[str], verify: bool = True, proxy: bool = False, - managed_identities_client_id: Optional[str] = None): + managed_identities_client_id: Optional[str] = None, + azure_cloud: Optional[AzureCloud] = None): """ AzureSentinelClient class that make use client credentials for authorization with Azure. - :type server_url: ``str`` - :param server_url: The server url. + :type azure_cloud: ``AzureCloud | None`` + :param azure_cloud: The Azure Cloud settings. :type tenant_id: ``str`` :param tenant_id: The tenant id. @@ -122,24 +124,27 @@ def __init__(self, server_url: str, tenant_id: str, client_id: str, :type managed_identities_client_id: ``str`` :param managed_identities_client_id: The Azure Managed Identities client id. """ - server_url = f'{server_url}/subscriptions/{subscription_id}/' \ - f'resourceGroups/{resource_group_name}/providers/Microsoft.OperationalInsights/workspaces/' \ - f'{workspace_name}/providers/Microsoft.SecurityInsights' + + azure_cloud = azure_cloud or AZURE_WORLDWIDE_CLOUD + base_url = f'{azure_cloud.endpoints.resource_manager}subscriptions/{subscription_id}/' \ + f'resourceGroups/{resource_group_name}/providers/Microsoft.OperationalInsights/workspaces/' \ + f'{workspace_name}/providers/Microsoft.SecurityInsights' self._client = MicrosoftClient( tenant_id=tenant_id, auth_id=client_id, enc_key=client_secret, self_deployed=True, grant_type=CLIENT_CREDENTIALS, - base_url=server_url, - scope=Scopes.management_azure, + scope=f'{azure_cloud.endpoints.resource_manager}.default', ok_codes=(200, 201, 202, 204), verify=verify, proxy=proxy, + azure_cloud=azure_cloud, certificate_thumbprint=certificate_thumbprint, private_key=private_key, managed_identities_client_id=managed_identities_client_id, - managed_identities_resource_uri=Resources.management_azure + managed_identities_resource_uri=azure_cloud.endpoints.resource_manager, + base_url=base_url ) def http_request(self, method, url_suffix=None, full_url=None, params=None, data=None): @@ -174,14 +179,12 @@ def get_error_kind(code): """ Get the kind of the error based on the http error code. """ - if code == 400: - return 'BadRequest' - elif code == 401: - return 'UnAuthorized' - elif code == 403: - return 'Forbidden' - elif code == 404: - return 'NotFound' + return { + 400: 'BadRequest', + 401: 'UnAuthorized', + 403: 'Forbidden', + 404: 'NotFound', + }.get(code) def error_handler(response: requests.Response): @@ -671,9 +674,10 @@ def update_incident_request(client: AzureSentinelClient, incident_id: str, data: Returns: Dict[str, Any]: the response of the update incident request """ - required_fileds = ('severity', 'status', 'title') - if any(field not in data for field in required_fileds): - raise DemistoException(f'Update incident request is missing one of the required fields for the API: {required_fileds}') + required_fields = ('severity', 'status', 'title') + if any(field not in data for field in required_fields): + raise DemistoException(f'Update incident request is missing one of the required fields for the ' + f'API: {required_fields}') properties = { 'title': data.get('title'), @@ -774,7 +778,7 @@ def get_incident_by_id_command(client, args): ) -def test_module(client): +def test_module(client: AzureSentinelClient, _: Dict[str, Any]): """ Test connection to Azure by calling the list incidents API with limit=1 """ @@ -796,7 +800,7 @@ def list_incidents_command(client: AzureSentinelClient, args, is_fetch_incidents next_link = args.get('next_link', '') if next_link: - next_link = next_link.replace('%20', ' ') # OData syntax can't handle '%' character + next_link = next_link.replace('%20', ' ') # Next link syntax can't handle '%' character result = client.http_request('GET', full_url=next_link) else: url_suffix = 'incidents' @@ -1034,7 +1038,7 @@ def list_incident_comments_command(client, args): next_link = args.get('next_link', '') if next_link: - next_link = next_link.replace('%20', ' ') # OData syntax can't handle '%' character + next_link = next_link.replace('%20', ' ') # Next link syntax can't handle '%' character result = client.http_request('GET', full_url=next_link) else: url_suffix = f'incidents/{inc_id}/comments' @@ -1147,7 +1151,7 @@ def list_incident_relations_command(client, args): filter_expression = args.get('filter', '') if next_link: - next_link = next_link.replace('%20', ' ') # OData syntax can't handle '%' character + next_link = next_link.replace('%20', ' ') # Next link syntax can't handle '%' character result = client.http_request('GET', full_url=next_link) else: # Handle entity kinds to filter by @@ -1191,13 +1195,13 @@ def update_next_link_in_context(result: dict, outputs: dict): next_link = result.get('nextLink', '').replace(' ', '%20') if next_link: next_link_item = { - 'Description': NEXTLINK_DESCRIPTION, + 'Description': NEXT_LINK_DESCRIPTION, 'URL': next_link, } - outputs[f'AzureSentinel.NextLink(val.Description == "{NEXTLINK_DESCRIPTION}")'] = next_link_item + outputs[f'AzureSentinel.NextLink(val.Description == "{NEXT_LINK_DESCRIPTION}")'] = next_link_item -def fetch_incidents_additional_info(client: AzureSentinelClient, incidents: List | Dict): +def fetch_incidents_additional_info(client: AzureSentinelClient, incidents: Union[List, Dict]): """Fetches additional info of an incidents array or a single incident. Args: @@ -1249,9 +1253,13 @@ def fetch_incidents(client: AzureSentinelClient, last_run: dict, first_fetch_tim if last_fetch_time is None: last_fetch_time_str, _ = parse_date_range(first_fetch_time, DATE_FORMAT) latest_created_time = dateparser.parse(last_fetch_time_str) + if not latest_created_time: + raise DemistoException(f'Got empty latest_created_time. {last_fetch_time_str=} {last_fetch_time=}') else: latest_created_time = dateparser.parse(last_fetch_time) - assert latest_created_time, f'Got empty latest_created_time. {last_fetch_time_str=} {last_fetch_time=}' + if not latest_created_time: + raise DemistoException(f'Got empty latest_created_time. {last_fetch_time=}') + latest_created_time_str = latest_created_time.strftime(DATE_FORMAT) command_args = { 'filter': f'properties/createdTimeUtc ge {latest_created_time_str}', @@ -1259,10 +1267,10 @@ def fetch_incidents(client: AzureSentinelClient, last_run: dict, first_fetch_tim } else: - demisto.debug("handle via id") + demisto.debug("last fetch time is empty, trying to fetch incidents by last incident id") latest_created_time = dateparser.parse(last_fetch_time) - assert latest_created_time is not None, f"dateparser.parse(last_fetch_time):" \ - f" {dateparser.parse(last_fetch_time)} couldnt be parsed" + if latest_created_time is None: + raise DemistoException(f"{last_fetch_time=} couldn't be parsed") command_args = { 'filter': f'properties/incidentNumber gt {last_incident_number}', 'orderby': 'properties/incidentNumber asc', @@ -1276,6 +1284,21 @@ def fetch_incidents(client: AzureSentinelClient, last_run: dict, first_fetch_tim latest_created_time, last_incident_number) # type: ignore[attr-defined] +def fetch_incidents_command(client, params): + # How much time before the first fetch to retrieve incidents + first_fetch_time = params.get('fetch_time', '3 days').strip() + min_severity = severity_to_level(params.get('min_severity', 'Informational')) + # Set and define the fetch incidents command to run after activated via integration settings. + next_run, incidents = fetch_incidents( + client=client, + last_run=demisto.getLastRun(), + first_fetch_time=first_fetch_time, + min_severity=min_severity + ) + demisto.setLastRun(next_run) + demisto.incidents(incidents) + + def process_incidents(raw_incidents: list, last_fetch_ids: list, min_severity: int, latest_created_time: datetime, last_incident_number): """Processing the raw incidents @@ -1317,8 +1340,9 @@ def process_incidents(raw_incidents: list, last_fetch_ids: list, min_severity: i "due to the {incident_severity=} is lower then {min_severity=}") # Update last run to the latest fetch time - assert incident_created_time is not None, f"incident.get('CreatedTimeUTC') : " \ - f"{incident.get('CreatedTimeUTC')} couldnt be parsed" + if incident_created_time is None: + raise DemistoException(f"{incident.get('CreatedTimeUTC')=} couldn't be parsed") + if incident_created_time > latest_created_time: latest_created_time = incident_created_time if incident.get('IncidentNumber') > last_incident_number: @@ -1399,14 +1423,12 @@ def build_query_filter(args): indicator_types = argToList(args.get('indicator_types')) if indicator_types: for ind_type in indicator_types: - if ind_type == 'ipv4': - filtering_args['patternTypes'].append('ipv4-address') - elif ind_type == 'ipv6': - filtering_args['patternTypes'].append('ipv6-address') - elif ind_type == 'domain': - filtering_args['patternTypes'].append('domain-name') - else: - filtering_args['patternTypes'].append(ind_type) + pattern_type = { + 'ipv4': '{ind_type}-address', + 'ipv6': '{ind_type}-address', + 'domain': '{ind_type}-name', + }.get(ind_type, "{ind_type}").format(ind_type=ind_type) + filtering_args['patternTypes'].append(pattern_type) include_disabled = args.get('include_disabled', 'false') == 'true' filtering_args['includeDisabled'] = include_disabled @@ -1502,11 +1524,10 @@ def list_threat_indicator_command(client, args): next_link = args.get('next_link', '') if next_link: - next_link = next_link.replace('%20', ' ') # OData syntax can't handle '%' character + next_link = next_link.replace('%20', ' ') # Next link syntax can't handle '%' character result = client.http_request('GET', full_url=next_link) else: - indicator_name = args.get('indicator_name') - if indicator_name: + if indicator_name := args.get('indicator_name'): url_suffix += f'/{indicator_name}' result = client.http_request('GET', url_suffix, params={'$top': limit}) @@ -1543,7 +1564,7 @@ def query_threat_indicators_command(client, args): data = build_query_filter(args) next_link = args.get('next_link', '') if next_link: - next_link = next_link.replace('%20', ' ') # OData syntax can't handle '%' character + next_link = next_link.replace('%20', ' ') # Next link syntax can't handle '%' character result = client.http_request('POST', full_url=next_link, data=data) else: @@ -1901,7 +1922,7 @@ def main(): resource_group_name = args.get('resource_group_name') or params.get('resourceGroupName', '') client = AzureSentinelClient( - server_url=params.get('server_url') or DEFAULT_AZURE_SERVER_URL, + azure_cloud=get_azure_cloud(params, 'AzureSentinel'), tenant_id=tenant_id, client_id=params.get('credentials', {}).get('identifier'), client_secret=client_secret, @@ -1916,6 +1937,7 @@ def main(): ) commands = { + 'test-module': test_module, 'azure-sentinel-get-incident-by-id': get_incident_by_id_command, 'azure-sentinel-list-incidents': list_incidents_command, 'azure-sentinel-update-incident': update_incident_command, @@ -1950,25 +1972,8 @@ def main(): 'update-remote-system': update_remote_system_command } - if demisto.command() == 'test-module': - return_results(test_module(client)) - - elif demisto.command() == 'fetch-incidents': - # How much time before the first fetch to retrieve incidents - first_fetch_time = params.get('fetch_time', '3 days').strip() - - min_severity = severity_to_level(params.get('min_severity', 'Informational')) - - # Set and define the fetch incidents command to run after activated via integration settings. - next_run, incidents = fetch_incidents( - client=client, - last_run=demisto.getLastRun(), - first_fetch_time=first_fetch_time, - min_severity=min_severity - ) - - demisto.setLastRun(next_run) - demisto.incidents(incidents) + if demisto.command() == 'fetch-incidents': + fetch_incidents_command(client, params) # mirroring command elif demisto.command() == 'get-mapping-fields': @@ -1983,7 +1988,5 @@ def main(): ) -from MicrosoftApiModule import * # noqa: E402 - -if __name__ in ('__main__', '__builtin__', 'builtins'): +if __name__ in ('__main__', '__builtin__', 'builtins'): # pragma: no cover main() diff --git a/Packs/AzureSentinel/Integrations/AzureSentinel/AzureSentinel.yml b/Packs/AzureSentinel/Integrations/AzureSentinel/AzureSentinel.yml index 895e8b8d3005..77a00da535a3 100644 --- a/Packs/AzureSentinel/Integrations/AzureSentinel/AzureSentinel.yml +++ b/Packs/AzureSentinel/Integrations/AzureSentinel/AzureSentinel.yml @@ -6,11 +6,22 @@ commonfields: id: Azure Sentinel version: -1 configuration: -- defaultvalue: https://management.azure.com - display: Server URL - name: server_url - required: true - type: 0 +- defaultvalue: Worldwide + display: Azure Cloud + name: azure_cloud + required: false + type: 15 + options: + - Worldwide + - US GCC + - US GCC-High + - DoD + - Germany + - China + - Custom + section: Connect + advanced: true + additionalinfo: When selecting the Custom option, the Server URL parameter must be filled. More information about National clouds can be found here - https://xsoar.pan.dev/docs/reference/articles/microsoft-integrations---authentication#using-national-cloud - name: creds_tenant_id required: false type: 9 @@ -112,6 +123,15 @@ configuration: required: false type: 13 section: Connect +- display: Server URL + name: server_url + required: false + type: 0 + section: Connect + advanced: true + defaultvalue: https://management.azure.com + hidden: false + additionalinfo: Use this option when required to customize the URL to the Azure management endpoint. More information can be found here - https://xsoar.pan.dev/docs/reference/articles/microsoft-integrations---authentication#using-national-cloud - display: Trust any certificate (not secure) name: insecure required: false @@ -128,29 +148,29 @@ configuration: name: fetch_additional_info required: false type: 16 - additionalinfo: | - Choose what additional info to fetch for each incident. - Note that this will increase the number of API calls. options: - Alerts - Entities - Comments - Relations section: Collect + additionalinfo: | + Choose what additional info to fetch for each incident. + Note that this will increase the number of API calls. advanced: true -- display: Mirroring Direction +- defaultvalue: 'None' + display: Mirroring Direction name: mirror_direction required: false type: 15 - defaultvalue: None + hidden: + - marketplacev2 + section: Collect options: - None - Incoming - Outgoing - Incoming And Outgoing - hidden: - - marketplacev2 - section: Collect - additionalinfo: When selected, closing the Microsoft Sentinel ticket is mirrored in Cortex XSOAR. defaultvalue: 'false' display: Close Mirrored XSOAR Incident @@ -1993,7 +2013,7 @@ script: description: The kind of the indicator. type: String - contextPath: AzureSentinel.ThreatIndicators.Confidence - description: The confidence of the threat indicator. THis is a number between 0-100. + description: The confidence of the threat indicator. This is a number between 0-100. type: Number - contextPath: AzureSentinel.ThreatIndicator.Created description: When the threat indicator was created. @@ -2656,7 +2676,7 @@ script: description: ETag of the Azure resource. type: String - contextPath: AzureSentinel.AlertRule.type - description: The type of the resource. E.g., "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts" + description: The type of the resource, e.g., "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts". type: String - contextPath: AzureSentinel.AlertRule.kind description: The alert rule kind. @@ -2934,7 +2954,7 @@ script: description: ETag of the Azure resource. type: String - contextPath: AzureSentinel.AlertRule.type - description: The type of the resource. E.g., "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts" + description: The type of the resource, e.g., "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts". type: String - contextPath: AzureSentinel.AlertRule.kind description: The alert rule kind. @@ -3005,7 +3025,7 @@ script: - contextPath: AzureSentinel.AlertRule.properties.incidentConfiguration description: The settings of the incidents that were created from alerts triggered by this analytics rule. type: Unknown - dockerimage: demisto/crypto:1.0.0.62834 + dockerimage: demisto/crypto:1.0.0.63672 feed: false isfetch: true longRunning: false diff --git a/Packs/AzureSentinel/Integrations/AzureSentinel/AzureSentinel_test.py b/Packs/AzureSentinel/Integrations/AzureSentinel/AzureSentinel_test.py index d11317c2a37e..65d194c34ff6 100644 --- a/Packs/AzureSentinel/Integrations/AzureSentinel/AzureSentinel_test.py +++ b/Packs/AzureSentinel/Integrations/AzureSentinel/AzureSentinel_test.py @@ -4,7 +4,7 @@ import pytest import requests import demistomock as demisto -from CommonServerPython import IncidentStatus +from CommonServerPython import IncidentStatus, tableToMarkdown, pascalToSpace, CommandResults from AzureSentinel import AzureSentinelClient, list_incidents_command, list_incident_relations_command, \ incident_add_comment_command, \ get_update_incident_request_data, list_incident_entities_command, list_incident_comments_command, \ @@ -14,12 +14,13 @@ delete_incident_command, XSOAR_USER_AGENT, incident_delete_comment_command, \ query_threat_indicators_command, create_threat_indicator_command, delete_threat_indicator_command, \ append_tags_threat_indicator_command, replace_tags_threat_indicator_command, update_threat_indicator_command, \ - list_threat_indicator_command, NEXTLINK_DESCRIPTION, process_incidents, fetch_incidents, fetch_incidents_additional_info, \ + list_threat_indicator_command, NEXT_LINK_DESCRIPTION, process_incidents, fetch_incidents, \ + fetch_incidents_additional_info, \ get_modified_remote_data_command, get_remote_data_command, get_remote_incident_data, get_mapping_fields_command, \ update_remote_system_command, update_remote_incident, close_incident_in_remote, update_incident_request, \ set_xsoar_incident_entries, build_threat_indicator_data, DEFAULT_SOURCE, list_alert_rule_command, \ list_alert_rule_template_command, delete_alert_rule_command, validate_required_arguments_for_alert_rule, \ - create_data_for_alert_rule, create_and_update_alert_rule_command + create_data_for_alert_rule, create_and_update_alert_rule_command, COMMENT_HEADERS, update_incident_command TEST_ITEM_ID = 'test_watchlist_item_id_1' @@ -49,12 +50,11 @@ def test_valid_error_is_raised_when_empty_api_response_is_returned(mocker): mocker.patch.object(client._client._session, 'request', return_value=api_response) with pytest.raises(ValueError, match='[Forbidden 403]'): - test_module(client) + test_module(client, {}) def mock_client(): client = AzureSentinelClient( - server_url='http://server_url', tenant_id='tenant_id', client_id='client_id', client_secret='client_secret', @@ -706,7 +706,8 @@ def test_update_incident(self, mocker): # prepare client = mock_client() - args = {'labels': ['label_after_1', 'label_after_2'], 'assignee_email': 'bob@example.com'} + args = {'labels': ['label_after_1', 'label_after_2'], 'assignee_email': 'bob@example.com', + 'user_principal_name': 'booUserPrincipalName'} mocker.patch.object(client, 'http_request', return_value=MOCKED_UPDATE_INCIDENT) # run @@ -717,6 +718,7 @@ def test_update_incident(self, mocker): assert properties['labels'] == [{'labelName': 'label_after_1', 'labelType': 'User'}, {'labelName': 'label_after_2', 'labelType': 'User'}] assert properties['owner']['email'] == 'bob@example.com' + assert properties['owner']['userPrincipalName'] == 'booUserPrincipalName' def test_list_incident_entities(self, mocker): """ @@ -1029,7 +1031,7 @@ def test_threat_indicator_list_command(self, args, expected_next_link, client, r if expected_next_link: mocked_indicators['nextLink'] = expected_next_link requests_mock.get( - 'http://server_url/subscriptions/subscriptionID/resourceGroups/resourceGroupName/providers/Microsoft' + 'https://management.azure.com/subscriptions/subscriptionID/resourceGroups/resourceGroupName/providers/Microsoft' '.OperationalInsights/workspaces/workspaceName/providers/Microsoft.SecurityInsights/threatIntelligence' '/main/indicators', json=mocked_indicators) else: @@ -1049,7 +1051,7 @@ def test_threat_indicator_list_command(self, args, expected_next_link, client, r assert context['DisplayName'] == 'displayfortestmay' assert len(raw_response['value']) == 1 - next_link = outputs.get(f'AzureSentinel.NextLink(val.Description == "{NEXTLINK_DESCRIPTION}")', {}).get('URL') + next_link = outputs.get(f'AzureSentinel.NextLink(val.Description == "{NEXT_LINK_DESCRIPTION}")', {}).get('URL') assert next_link == expected_next_link @pytest.mark.parametrize('args, expected_next_link, client', [ # disable-secrets-detection @@ -1072,7 +1074,7 @@ def test_query_threat_indicators_command(self, args, expected_next_link, client, if expected_next_link: mocked_indicators['nextLink'] = expected_next_link requests_mock.post( - 'http://server_url/subscriptions/subscriptionID/resourceGroups/resourceGroupName/providers/Microsoft' + 'https://management.azure.com/subscriptions/subscriptionID/resourceGroups/resourceGroupName/providers/Microsoft' '.OperationalInsights/workspaces/workspaceName/providers/Microsoft.SecurityInsights/threatIntelligence' '/main/queryIndicators', json=mocked_indicators) else: @@ -1091,7 +1093,7 @@ def test_query_threat_indicators_command(self, args, expected_next_link, client, assert context['DisplayName'] == 'displayfortestmay' assert len(raw_response['value']) == 1 - next_link = outputs.get(f'AzureSentinel.NextLink(val.Description == "{NEXTLINK_DESCRIPTION}")', {}).get('URL') + next_link = outputs.get(f'AzureSentinel.NextLink(val.Description == "{NEXT_LINK_DESCRIPTION}")', {}).get('URL') assert next_link == expected_next_link @pytest.mark.parametrize('args, client', [ # disable-secrets-detection @@ -1223,11 +1225,11 @@ def test_update_threat_indicator_command(self, args, client, requests_mock): mocked_updated_indicators = MOCKED_UPDATE_THREAT_INDICATOR requests_mock.get( - 'http://server_url/subscriptions/subscriptionID/resourceGroups/resourceGroupName/providers/Microsoft' + 'https://management.azure.com/subscriptions/subscriptionID/resourceGroups/resourceGroupName/providers/Microsoft' '.OperationalInsights/workspaces/workspaceName/providers/Microsoft.SecurityInsights/threatIntelligence' '/main/indicators/ind_name', json=mocked_indicators) requests_mock.put( - 'http://server_url/subscriptions/subscriptionID/resourceGroups/resourceGroupName/providers/Microsoft' + 'https://management.azure.com/subscriptions/subscriptionID/resourceGroups/resourceGroupName/providers/Microsoft' '.OperationalInsights/workspaces/workspaceName/providers/Microsoft.SecurityInsights/threatIntelligence' '/main/indicators/ind_name', json=mocked_updated_indicators) @@ -1393,7 +1395,8 @@ def test_test_module_command_with_managed_identities(self, mocker, requests_mock 'use_managed_identities': 'True', 'subscriptionID': 'test_subscription_id', 'resourceGroupName': 'test_resource_group', - 'tenant_id': 'test_tenant_id' + 'tenant_id': 'test_tenant_id', + 'azure_cloud': 'Worldwide', } mocker.patch.object(demisto, 'params', return_value=params) mocker.patch.object(demisto, 'command', return_value='test-module') @@ -1591,8 +1594,8 @@ def test_get_mapping_fields_command(): assert result.scheme_types_mappings[0].type_name == 'Microsoft Sentinel Incident' assert result.scheme_types_mappings[0].fields.keys() == {'description', 'status', 'lastActivityTimeUtc', 'classificationReason', 'tags', 'classificationComment', - 'severity', 'firstActivityTimeUtc', 'classification', 'title', - 'etag'} + 'severity', 'firstActivityTimeUtc', 'classification', + 'title', 'etag'} def test_update_remote_system_command(mocker): @@ -1905,3 +1908,105 @@ def test_create_and_update_alert_rule_command(mocker): assert command_results.outputs_prefix == 'AzureSentinel.AlertRule' assert command_results.outputs_key_field == 'name' assert '|ID|Name|Kind|Severity|Display Name|Description|Enabled|Etag|' in command_results.readable_output + + +def test_list_incident_comments_command_happy_path(mocker): + """ + Given: + - Valid incident ID, limit, and next link. + + When: + - Calling the list_incident_comments_command function. + + Then: + - Ensure the function successfully retrieves comments for the given incident ID with and without + a specified limit and next link. + - Ensure the function returns the expected CommandResults object. + """ + + client = mocker.Mock() + args = { + 'incident_id': '123', + 'limit': '50', + 'next_link': '' + } + result = { + 'value': [ + { + 'name': 'comment1', + 'properties': { + 'message': 'test comment 1', + 'author': { + 'assignedTo': 'test user', + 'email': 'test@test.com' + }, + 'createdTimeUtc': '2022-01-01T00:00:00Z' + } + }, + { + 'name': 'comment2', + 'properties': { + 'message': 'test comment 2', + 'author': { + 'assignedTo': 'test user 2', + 'email': 'test2@test.com' + }, + 'createdTimeUtc': '2022-01-02T00:00:00Z' + } + } + ], + 'nextLink': '' + } + client.http_request.return_value = result + + expected_comments = [ + { + 'ID': 'comment1', + 'IncidentID': '123', + 'Message': 'test comment 1', + 'AuthorName': 'test user', + 'AuthorEmail': 'test@test.com', + 'CreatedTimeUTC': '2022-01-01T00:00:00Z' + }, + { + 'ID': 'comment2', + 'IncidentID': '123', + 'Message': 'test comment 2', + 'AuthorName': 'test user 2', + 'AuthorEmail': 'test2@test.com', + 'CreatedTimeUTC': '2022-01-02T00:00:00Z' + } + ] + + expected_outputs = { + 'AzureSentinel.IncidentComment(val.ID === obj.ID && val.IncidentID === 123)': expected_comments + } + + expected_readable_output = tableToMarkdown('Incident 123 Comments (2 results)', expected_comments, + headers=COMMENT_HEADERS, headerTransform=pascalToSpace, removeNull=True) + + # Execute the test + assert list_incident_comments_command(client, args).readable_output == CommandResults( + readable_output=expected_readable_output, + outputs=expected_outputs, + raw_response=result + ).readable_output + + +def test_update_incident_command_table_to_markdown(mocker): + """ + Given: + - A valid incident_id and incident data. + + When: + - Calling update_incident_command function. + + Then: + - Ensure that the function formats the output table correctly. + """ + client = mock_client() + mocker.patch.object(client, 'http_request', return_value={'id': '123', 'title': 'test', 'severity': 'High'}) + args = {'incident_id': '123', 'title': 'new title', 'description': 'new description', 'severity': 'High'} + result = update_incident_command(client, args) + expected_output = '### Updated incidents 123 details\n**No entries.**' + assert result.readable_output.strip() == expected_output diff --git a/Packs/AzureSentinel/Integrations/AzureSentinel/README.md b/Packs/AzureSentinel/Integrations/AzureSentinel/README.md index 6d2e813796fa..937794ac4ae1 100644 --- a/Packs/AzureSentinel/Integrations/AzureSentinel/README.md +++ b/Packs/AzureSentinel/Integrations/AzureSentinel/README.md @@ -19,6 +19,7 @@ Follow these steps for a self-deployed configuration. 7. Copy your tenant ID for the integration configuration usage. ## Configure the server URL + If you have a dedicated server URL, enter it in the *Server Url* parameter. ## Get the additional instance parameters @@ -31,40 +32,57 @@ To get the *Subscription ID*, *Workspace Name* and *Resource Group* parameters, 2. Search for Azure Sentinel. 3. Click **Add instance** to create and configure a new integration instance. - | **Parameter** | **Required** | - | --- | --- | - | Server URL | False | - | Tenant ID | False | - | Client ID | False | - | Azure Managed Identities Client ID | False | - | Subscription ID | True | - | Resource Group Name | True | - | Workspace Name | True | - | Fetch incidents | False | - | First fetch timestamp (<number> <time unit>, e.g., 12 hours, 7 days) | False | - | The minimum severity of incidents to fetch | False | - | Incident type | False | - | Trust any certificate (not secure) | False | - | Use system proxy settings | False | - | Additional info to fetch | False | - | Mirroring Direction | False | - | Close Mirrored XSOAR Incident | False | - | Close Mirrored Microsoft Sentinel Ticket | False | - -4. Click **Test** to validate the URLs, token, and connection. + | **Parameter** | **Required** | + |----------------------------------------------------------------------------------|--------------| + | Azure Cloud | False | + | Tenant ID | False | + | Client ID | False | + | Azure Managed Identities Client ID | False | + | Subscription ID | True | + | Resource Group Name | True | + | Workspace Name | True | + | Fetch incidents | False | + | First fetch timestamp (<number> <time unit>, e.g., 12 hours, 7 days) | False | + | The minimum severity of incidents to fetch | False | + | Incident type | False | + | Trust any certificate (not secure) | False | + | Use system proxy settings | False | + | Additional info to fetch | False | + | Mirroring Direction | False | + | Close Mirrored XSOAR Incident | False | + | Close Mirrored Microsoft Sentinel Ticket | False | + | Server URL, see note below regarding Azure cloud options. | False | + +4. Azure cloud options + + | Azure Cloud | Description | + |-------------|--------------------------------------------------------------------------| + | Worldwide | The publicly accessible Azure Cloud | + | US GCC | Azure cloud for the USA Government Cloud Community (GCC) | + | US GCC-High | Azure cloud for the USA Government Cloud Community High (GCC-High) | + | DoD | Azure cloud for the USA Department of Defense (DoD) | + | Germany | Azure cloud for the German Government | + | China | Azure cloud for the Chinese Government | + | Custom | Custom endpoint configuration to the Azure cloud, please see note below. | + + - Note: In most cases setting Azure cloud is preferred to setting Server URL. Only use it in cases where a custom proxy URL is required for accessing a national cloud. + +5. Click **Test** to validate the URLs, token, and connection. ## Incident Mirroring + You can enable incident mirroring between Cortex XSOAR incidents and Microsoft Sentinel incidents (available from Cortex XSOAR version 6.0.0). To setup the mirroring follow these instructions: + 1. Navigate to **Settings > Integrations > Servers & Services**. 2. Search for **Microsoft Sentinel** and select your integration instance. 3. Enable **Fetches incidents**. 4. In the **Mirroring Direction** integration parameter, select in which direction the incidents should be mirrored: - * Incoming - Any changes in *Microsoft Sentinel* incidents will be reflected in Cortex XSOAR incidents. - * Outgoing - Any changes in Cortex XSOAR incidents will be reflected in *Microsoft Sentinel*. - * Incoming And Outgoing - Changes in Cortex XSOAR incidents and *Microsoft Sentinel* incidents will be reflected in both directions. - * None - Turns off incident mirroring. + - Incoming - Any changes in *Microsoft Sentinel* incidents will be reflected in Cortex XSOAR incidents. + - Outgoing - Any changes in Cortex XSOAR incidents will be reflected in *Microsoft Sentinel*. + - Incoming And Outgoing - Changes in Cortex XSOAR incidents and *Microsoft Sentinel* incidents will be reflected in both directions. + - None - Turns off incident mirroring. 5. Optional: Check the **Close Mirrored XSOAR Incident** integration parameter to close the Cortex XSOAR incident when the corresponding incident is closed in *Microsoft Sentinel*. 6. Optional: Check the **Close Mirrored Microsoft Sentinel Ticket** integration parameter to close the *Microsoft Sentinel* incident when the corresponding Cortex XSOAR incident is closed. @@ -73,9 +91,12 @@ Newly fetched incidents will be mirrored in the chosen direction. However, this ## Commands + You can execute these commands from the Cortex XSOAR CLI, as part of an automation, or in a playbook. After you successfully execute a command, a DBot message appears in the War Room with the command details. + ### azure-sentinel-get-incident-by-id + *** Gets a single incident from Azure Sentinel. @@ -83,6 +104,7 @@ Gets a single incident from Azure Sentinel. #### Base Command `azure-sentinel-get-incident-by-id` + #### Input | **Argument Name** | **Description** | **Required** | @@ -122,9 +144,11 @@ Gets a single incident from Azure Sentinel. #### Command Example + ```!azure-sentinel-get-incident-by-id incident_id=8a44b7bb-c8ae-4941-9fa0-3aecc8ef1742``` #### Context Example + ```json { "AzureSentinel": { @@ -170,12 +194,14 @@ Gets a single incident from Azure Sentinel. #### Human Readable Output >### Incident 8a44b7bb-c8ae-4941-9fa0-3aecc8ef1742 details +> >|ID|Incident Number|Title|Description|Severity|Status|Assignee Email|Label|Last Modified Time UTC|Created Time UTC|Alerts Count|Bookmarks Count|Comments Count|Alert Product Names|Etag| >|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---| ->| 8a44b7bb-c8ae-4941-9fa0-3aecc8ef1742 | 2 | SharePointFileOperation via previously unseen IPs | Identifies when the volume of documents uploaded to or downloaded from Sharepoint by new IP addresses
exceeds a threshold (default is 100). | Informational | New | test@test.com | {'Name': 'label_a', 'Type': 'User'},
{'Name': 'label_b', 'Type': 'User'} | 2021-08-23T13:28:51Z | 2020-01-15T09:29:14Z | 1 | 0 | 3 | Azure Sentinel | "2700a244-0000-0100-0000-6123a2930000" | +>| 8a44b7bb-c8ae-4941-9fa0-3aecc8ef1742 | 2 | SharePointFileOperation via previously unseen IPs | Identifies when the volume of documents uploaded to or downloaded from Sharepoint by new IP addresses
exceeds a threshold (default is 100). | Informational | New | | {'Name': 'label_a', 'Type': 'User'},
{'Name': 'label_b', 'Type': 'User'} | 2021-08-23T13:28:51Z | 2020-01-15T09:29:14Z | 1 | 0 | 3 | Azure Sentinel | "2700a244-0000-0100-0000-6123a2930000" | ### azure-sentinel-list-incidents + *** Gets a list of incidents from Azure Sentinel. @@ -183,12 +209,13 @@ Gets a list of incidents from Azure Sentinel. #### Base Command `azure-sentinel-list-incidents` + #### Input | **Argument Name** | **Description** | **Required** | | --- | --- | --- | | limit | The maximum number of incidents to return. The maximum value is 200. Default is 50. | Optional | -| filter | Filter results using OData syntax. For example: properties/createdTimeUtc gt 2020-02-02T14:00:00Z`). For more information, see the Azure documentation: https://docs.microsoft.com/bs-latn-ba/azure/search/search-query-odata-filter. | Optional | +| filter | Filter results using OData syntax. For example: properties/createdTimeUtc gt 2020-02-02T14:00:00Z`). For more information, see the Azure documentation: . | Optional | | next_link | A link that specifies a starting point to use for subsequent calls. This argument overrides all of the other command arguments. | Optional | | subscription_id | The subscription ID. | Optional | | resource_group_name | The resource group name. | Optional | @@ -225,9 +252,11 @@ Gets a list of incidents from Azure Sentinel. #### Command Example + ```!azure-sentinel-list-incidents limit=5``` #### Context Example + ```json { "AzureSentinel": { @@ -400,16 +429,18 @@ Gets a list of incidents from Azure Sentinel. #### Human Readable Output >### Incidents List (5 results) +> >|ID|Incident Number|Title|Description|Severity|Status|Assignee Email|Label|First Activity Time UTC|Last Activity Time UTC|Last Modified Time UTC|Created Time UTC|Alerts Count|Bookmarks Count|Comments Count|Alert Product Names|Etag| >|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---| ->| 8a44b7bb-c8ae-4941-9fa0-3aecc8ef1742 | 2 | SharePointFileOperation via previously unseen IPs | Identifies when the volume of documents uploaded to or downloaded from Sharepoint by new IP addresses
exceeds a threshold (default is 100). | Informational | New | test@test.com | {'Name': 'label_a', 'Type': 'User'},
{'Name': 'label_b', 'Type': 'User'} | | | 2021-08-23T13:28:51Z | 2020-01-15T09:29:14Z | 1 | 0 | 3 | Azure Sentinel | "2700a244-0000-0100-0000-6123a2930000" | ->| e0b06d71-b5a3-43a9-997f-f25b45085cb7 | 4 | SharePointFileOperation via previously unseen IPs | Identifies when the volume of documents uploaded to or downloaded from Sharepoint by new IP addresses
exceeds a threshold (default is 100). | Low | New | test@test.com | {'Name': 'f', 'Type': 'User'},
{'Name': 'o', 'Type': 'User'},
{'Name': 'o', 'Type': 'User'},
{'Name': '1', 'Type': 'User'} | | | 2021-05-10T12:49:54Z | 2020-01-15T09:34:12Z | 1 | 0 | 0 | Azure Sentinel | "dc00cb1c-0000-0100-0000-60992bf20000" | +>| 8a44b7bb-c8ae-4941-9fa0-3aecc8ef1742 | 2 | SharePointFileOperation via previously unseen IPs | Identifies when the volume of documents uploaded to or downloaded from Sharepoint by new IP addresses
exceeds a threshold (default is 100). | Informational | New | | {'Name': 'label_a', 'Type': 'User'},
{'Name': 'label_b', 'Type': 'User'} | | | 2021-08-23T13:28:51Z | 2020-01-15T09:29:14Z | 1 | 0 | 3 | Azure Sentinel | "2700a244-0000-0100-0000-6123a2930000" | +>| e0b06d71-b5a3-43a9-997f-f25b45085cb7 | 4 | SharePointFileOperation via previously unseen IPs | Identifies when the volume of documents uploaded to or downloaded from Sharepoint by new IP addresses
exceeds a threshold (default is 100). | Low | New | | {'Name': 'f', 'Type': 'User'},
{'Name': 'o', 'Type': 'User'},
{'Name': 'o', 'Type': 'User'},
{'Name': '1', 'Type': 'User'} | | | 2021-05-10T12:49:54Z | 2020-01-15T09:34:12Z | 1 | 0 | 0 | Azure Sentinel | "dc00cb1c-0000-0100-0000-60992bf20000" | >| a7977be7-1008-419b-877b-6793b7402a80 | 6 | SharePointFileOperation via previously unseen IPs | Identifies when the volume of documents uploaded to or downloaded from Sharepoint by new IP addresses
exceeds a threshold (default is 100). | Medium | New | | | 2020-01-15T08:04:05Z | 2020-01-15T09:04:05Z | 2020-01-15T09:40:09Z | 2020-01-15T09:40:09Z | 1 | 0 | 0 | Azure Sentinel | "0100c30e-0000-0100-0000-5fb883be0000" | >| 6440c129-c313-418c-a262-5df608aa9cd2 | 7 | test_title | Identifies when the volume of documents uploaded to or downloaded from Sharepoint by new IP addresses
exceeds a threshold (default is 100). | Medium | Active | | | | | 2020-12-17T12:26:49Z | 2020-01-15T09:44:12Z | 1 | 0 | 1 | Azure Sentinel | "0600a81f-0000-0100-0000-5fdb4e890000" | >| 413e9d64-c7b4-4e33-ae26-bb39710d2187 | 9 | SharePointFileOperation via previously unseen IPs | Identifies when the volume of documents uploaded to or downloaded from Sharepoint by new IP addresses
exceeds a threshold (default is 100). | Medium | New | | | 2020-01-15T08:44:06Z | 2020-01-15T09:44:06Z | 2020-01-15T09:49:12Z | 2020-01-15T09:49:12Z | 1 | 0 | 0 | Azure Sentinel | "0100b70e-0000-0100-0000-5fb883bd0000" | ### azure-sentinel-list-watchlists + *** Gets a list of watchlists from Azure Sentinel. @@ -417,6 +448,7 @@ Gets a list of watchlists from Azure Sentinel. #### Base Command `azure-sentinel-list-watchlists` + #### Input | **Argument Name** | **Description** | **Required** | @@ -447,9 +479,11 @@ Gets a list of watchlists from Azure Sentinel. #### Command Example + ```!azure-sentinel-list-watchlists``` #### Context Example + ```json { "AzureSentinel": { @@ -520,6 +554,7 @@ Gets a list of watchlists from Azure Sentinel. #### Human Readable Output >### Watchlists results +> >|Name|ID|Description| >|---|---|---| >| booboo | 35bffe30-19f2-40a6-8855-4a858e161fad | just for fun | @@ -529,6 +564,7 @@ Gets a list of watchlists from Azure Sentinel. ### azure-sentinel-delete-watchlist + *** Delete a watchlists from Azure Sentinel. @@ -536,6 +572,7 @@ Delete a watchlists from Azure Sentinel. #### Base Command `azure-sentinel-delete-watchlist` + #### Input | **Argument Name** | **Description** | **Required** | @@ -550,6 +587,7 @@ Delete a watchlists from Azure Sentinel. There is no context output for this command. #### Command Example + ```!azure-sentinel-delete-watchlist watchlist_alias=test_4``` #### Human Readable Output @@ -557,6 +595,7 @@ There is no context output for this command. >Watchlist test_4 was deleted successfully. ### azure-sentinel-watchlist-create-update + *** Create or update a watchlist in Azure Sentinel. @@ -564,6 +603,7 @@ Create or update a watchlist in Azure Sentinel. #### Base Command `azure-sentinel-watchlist-create-update` + #### Input | **Argument Name** | **Description** | **Required** | @@ -601,9 +641,11 @@ Create or update a watchlist in Azure Sentinel. #### Command Example + ```!azure-sentinel-watchlist-create-update items_search_key=IP raw_content=1711@3c9bd2a0-9eac-465b-8799-459df4997b2d source="Local file" watchlist_alias=test_4 watchlist_display_name=test_4 description="test watchlist"``` #### Context Example + ```json { "AzureSentinel": { @@ -628,12 +670,14 @@ Create or update a watchlist in Azure Sentinel. #### Human Readable Output >### Create watchlist results +> >|Name|ID|Description| >|---|---|---| >| test_4 | 84d1fedd-5945-4670-ae34-5e8c94af2660 | test watchlist | ### azure-sentinel-update-incident + *** Updates a single incident in Azure Sentinel. @@ -641,6 +685,7 @@ Updates a single incident in Azure Sentinel. #### Base Command `azure-sentinel-update-incident` + #### Input | **Argument Name** | **Description** | **Required** | @@ -689,9 +734,11 @@ Updates a single incident in Azure Sentinel. #### Command Example + ```!azure-sentinel-update-incident incident_id=8a44b7bb-c8ae-4941-9fa0-3aecc8ef1742 labels=label_a,label_b``` #### Context Example + ```json { "AzureSentinel": { @@ -737,12 +784,14 @@ Updates a single incident in Azure Sentinel. #### Human Readable Output >### Updated incidents 8a44b7bb-c8ae-4941-9fa0-3aecc8ef1742 details +> >|ID|Incident Number|Title|Description|Severity|Status|Assignee Email|Label|Last Modified Time UTC|Created Time UTC|Alerts Count|Bookmarks Count|Comments Count|Alert Product Names|Etag| >|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---| ->| 8a44b7bb-c8ae-4941-9fa0-3aecc8ef1742 | 2 | SharePointFileOperation via previously unseen IPs | Identifies when the volume of documents uploaded to or downloaded from Sharepoint by new IP addresses
exceeds a threshold (default is 100). | Informational | New | test@test.com | {'Name': 'label_a', 'Type': 'User'},
{'Name': 'label_b', 'Type': 'User'} | 2021-08-23T13:30:49Z | 2020-01-15T09:29:14Z | 1 | 0 | 4 | Azure Sentinel | "27002845-0000-0100-0000-6123a3090000" | +>| 8a44b7bb-c8ae-4941-9fa0-3aecc8ef1742 | 2 | SharePointFileOperation via previously unseen IPs | Identifies when the volume of documents uploaded to or downloaded from Sharepoint by new IP addresses
exceeds a threshold (default is 100). | Informational | New | | {'Name': 'label_a', 'Type': 'User'},
{'Name': 'label_b', 'Type': 'User'} | 2021-08-23T13:30:49Z | 2020-01-15T09:29:14Z | 1 | 0 | 4 | Azure Sentinel | "27002845-0000-0100-0000-6123a3090000" | ### azure-sentinel-delete-incident + *** Deletes a single incident in Azure Sentinel. @@ -750,6 +799,7 @@ Deletes a single incident in Azure Sentinel. #### Base Command `azure-sentinel-delete-incident` + #### Input | **Argument Name** | **Description** | **Required** | @@ -764,9 +814,11 @@ Deletes a single incident in Azure Sentinel. There is no context output for this command. #### Command Example + ```!azure-sentinel-delete-incident incident_id=c90cc84d-a95e-47a0-9478-89ebc9ee22fd``` #### Context Example + ```json { "AzureSentinel": { @@ -783,6 +835,7 @@ There is no context output for this command. >Incident c90cc84d-a95e-47a0-9478-89ebc9ee22fd was deleted successfully. ### azure-sentinel-list-incident-comments + *** Gets the comments of an incident from Azure Sentinel. @@ -790,6 +843,7 @@ Gets the comments of an incident from Azure Sentinel. #### Base Command `azure-sentinel-list-incident-comments` + #### Input | **Argument Name** | **Description** | **Required** | @@ -816,9 +870,11 @@ Gets the comments of an incident from Azure Sentinel. #### Command Example + ```!azure-sentinel-list-incident-comments incident_id=8a44b7bb-c8ae-4941-9fa0-3aecc8ef1742``` #### Context Example + ```json { "AzureSentinel": { @@ -863,15 +919,17 @@ Gets the comments of an incident from Azure Sentinel. #### Human Readable Output >### Incident 8a44b7bb-c8ae-4941-9fa0-3aecc8ef1742 Comments (4 results) +> >|ID|Incident ID|Message|Author Email|Created Time UTC| >|---|---|---|---|---| >| 231020399272240422047777436922721687523 | 8a44b7bb-c8ae-4941-9fa0-3aecc8ef1742 | test messages | | 2021-08-23T13:30:42Z | >| 251456744761940512356246980948458722890 | 8a44b7bb-c8ae-4941-9fa0-3aecc8ef1742 | test messages | | 2021-08-23T13:26:26Z | >| 152909182848719872520422267385960967748 | 8a44b7bb-c8ae-4941-9fa0-3aecc8ef1742 | test messages | | 2021-08-12T10:57:44Z | ->| 307866023137611282164566423986768628663 | 8a44b7bb-c8ae-4941-9fa0-3aecc8ef1742 | hello world | test@test.com | 2020-04-05T12:14:13Z | +>| 307866023137611282164566423986768628663 | 8a44b7bb-c8ae-4941-9fa0-3aecc8ef1742 | hello world | | 2020-04-05T12:14:13Z | ### azure-sentinel-incident-add-comment + *** Adds a comment to an incident in Azure Sentinel. @@ -879,6 +937,7 @@ Adds a comment to an incident in Azure Sentinel. #### Base Command `azure-sentinel-incident-add-comment` + #### Input | **Argument Name** | **Description** | **Required** | @@ -902,9 +961,11 @@ Adds a comment to an incident in Azure Sentinel. #### Command Example + ```!azure-sentinel-incident-add-comment incident_id=8a44b7bb-c8ae-4941-9fa0-3aecc8ef1742 message="test messages"``` #### Context Example + ```json { "AzureSentinel": { @@ -923,12 +984,14 @@ Adds a comment to an incident in Azure Sentinel. #### Human Readable Output >### Incident 8a44b7bb-c8ae-4941-9fa0-3aecc8ef1742 new comment details +> >|ID|Incident ID|Message|Created Time UTC| >|---|---|---|---| >| 231020399272240422047777436922721687523 | 8a44b7bb-c8ae-4941-9fa0-3aecc8ef1742 | test messages | 2021-08-23T13:30:42Z | ### azure-sentinel-incident-delete-comment + *** Deletes a comment from incident in Azure Sentinel. @@ -936,6 +999,7 @@ Deletes a comment from incident in Azure Sentinel. #### Base Command `azure-sentinel-incident-delete-comment` + #### Input | **Argument Name** | **Description** | **Required** | @@ -951,6 +1015,7 @@ Deletes a comment from incident in Azure Sentinel. There is no context output for this command. #### Command Example + ```!azure-sentinel-incident-delete-comment incident_id=8a44b7bb-c8ae-4941-9fa0-3aecc8ef1742 comment_id="296745069631925005023508651351426"``` #### Human Readable Output @@ -959,6 +1024,7 @@ There is no context output for this command. ### azure-sentinel-list-incident-relations + *** Gets a list of an incident's related entities from Azure Sentinel. @@ -966,6 +1032,7 @@ Gets a list of an incident's related entities from Azure Sentinel. #### Base Command `azure-sentinel-list-incident-relations` + #### Input | **Argument Name** | **Description** | **Required** | @@ -974,7 +1041,7 @@ Gets a list of an incident's related entities from Azure Sentinel. | limit | The maximum number of related entities to return. Default is 50. | Optional | | next_link | A link that specifies a starting point to use for subsequent calls. Using this argument overrides all of the other command arguments. | Optional | | entity_kinds | A comma-separated list of entity kinds to filter by. By default, the results won't be filtered by kind.
The optional kinds are: Account, Host, File, AzureResource, CloudApplication, DnsResolution, FileHash, Ip, Malware, Process, RegistryKey, RegistryValue, SecurityGroup, Url, IoTDevice, SecurityAlert, Bookmark. | Optional | -| filter | Filter results using OData syntax. For example: properties/createdTimeUtc gt 2020-02-02T14:00:00Z`). For more information see the Azure documentation: https://docs.microsoft.com/bs-latn-ba/azure/search/search-query-odata-filter. | Optional | +| filter | Filter results using OData syntax. For example: properties/createdTimeUtc gt 2020-02-02T14:00:00Z`). For more information see the Azure documentation: . | Optional | | subscription_id | The subscription ID. | Optional | | resource_group_name | The resource group name. | Optional | @@ -991,9 +1058,11 @@ Gets a list of an incident's related entities from Azure Sentinel. #### Command Example + ```!azure-sentinel-list-incident-relations incident_id=8a44b7bb-c8ae-4941-9fa0-3aecc8ef1742``` #### Context Example + ```json { "AzureSentinel": { @@ -1009,12 +1078,14 @@ Gets a list of an incident's related entities from Azure Sentinel. #### Human Readable Output >### Incident 8a44b7bb-c8ae-4941-9fa0-3aecc8ef1742 Relations (1 results) +> >|ID|Incident ID|Kind| >|---|---|---| >| bfb02efc-12b7-4147-a8e8-961338b1b834 | 8a44b7bb-c8ae-4941-9fa0-3aecc8ef1742 | SecurityAlert | ### azure-sentinel-list-incident-entities + *** Gets a list of an incident's entities from Azure Sentinel. @@ -1022,6 +1093,7 @@ Gets a list of an incident's entities from Azure Sentinel. #### Base Command `azure-sentinel-list-incident-entities` + #### Input | **Argument Name** | **Description** | **Required** | @@ -1042,9 +1114,11 @@ Gets a list of an incident's entities from Azure Sentinel. #### Command Example + ```!azure-sentinel-list-incident-entities incident_id=65d8cbc0-4e4d-4acb-ab7e-8aa19936002c``` #### Context Example + ```json { "AzureSentinel": { @@ -1089,12 +1163,14 @@ Gets a list of an incident's entities from Azure Sentinel. #### Human Readable Output >### Incident 65d8cbc0-4e4d-4acb-ab7e-8aa19936002c Entities (1 results) +> >|ID|Kind|Incident Id| >|---|---|---| >| 176567ab-1ccc-8a53-53bf-97958a78d3b5 | Account | 65d8cbc0-4e4d-4acb-ab7e-8aa19936002c | ### azure-sentinel-list-incident-alerts + *** Gets a list of an incident's alerts from Azure Sentinel. @@ -1102,6 +1178,7 @@ Gets a list of an incident's alerts from Azure Sentinel. #### Base Command `azure-sentinel-list-incident-alerts` + #### Input | **Argument Name** | **Description** | **Required** | @@ -1129,9 +1206,11 @@ Gets a list of an incident's alerts from Azure Sentinel. #### Command Example + ```!azure-sentinel-list-incident-alerts incident_id=25c9ddf4-d951-4b67-9381-172f953feb57``` #### Context Example + ```json { "AzureSentinel": { @@ -1168,12 +1247,14 @@ Gets a list of an incident's alerts from Azure Sentinel. #### Human Readable Output >### Incident 25c9ddf4-d951-4b67-9381-172f953feb57 Alerts (1 results) +> >|ID|Kind|Incident Id| >|---|---|---| >| f3319e38-3f5b-a1eb-9970-69679dcdf916 | SecurityAlert | 25c9ddf4-d951-4b67-9381-172f953feb57 | ### azure-sentinel-list-watchlist-items + *** Get a single watchlist item or list of watchlist items. @@ -1181,6 +1262,7 @@ Get a single watchlist item or list of watchlist items. #### Base Command `azure-sentinel-list-watchlist-items` + #### Input | **Argument Name** | **Description** | **Required** | @@ -1205,9 +1287,11 @@ Get a single watchlist item or list of watchlist items. #### Command Example + ```!azure-sentinel-list-watchlist-items watchlist_alias=test_4``` #### Context Example + ```json { "AzureSentinel": { @@ -1246,6 +1330,7 @@ Get a single watchlist item or list of watchlist items. #### Human Readable Output >### Watchlist items results +> >|ID|Items Key Value| >|---|---| >| 28bd8f55-131b-42e6-bd5d-33d30f2d1291 | name: test1
IP: 1.2.3.4 | @@ -1253,6 +1338,7 @@ Get a single watchlist item or list of watchlist items. ### azure-sentinel-delete-watchlist-item + *** Delete a watchlist item. @@ -1260,6 +1346,7 @@ Delete a watchlist item. #### Base Command `azure-sentinel-delete-watchlist-item` + #### Input | **Argument Name** | **Description** | **Required** | @@ -1275,6 +1362,7 @@ Delete a watchlist item. There is no context output for this command. #### Command Example + ```!azure-sentinel-delete-watchlist-item watchlist_alias=test_2 watchlist_item_id=96c326c6-2dea-403c-94bd-6a005921c3c1``` #### Human Readable Output @@ -1282,6 +1370,7 @@ There is no context output for this command. >Watchlist item 96c326c6-2dea-403c-94bd-6a005921c3c1 was deleted successfully. ### azure-sentinel-create-update-watchlist-item + *** Create or update a watchlist item. @@ -1289,6 +1378,7 @@ Create or update a watchlist item. #### Base Command `azure-sentinel-create-update-watchlist-item` + #### Input | **Argument Name** | **Description** | **Required** | @@ -1314,9 +1404,11 @@ Create or update a watchlist item. #### Command Example + ```!azure-sentinel-create-update-watchlist-item watchlist_alias=test_4 item_key_value=`{"name": "test_4_item", "IP": "4.4.4.4"}```` #### Context Example + ```json { "AzureSentinel": { @@ -1340,12 +1432,14 @@ Create or update a watchlist item. #### Human Readable Output >### Create watchlist item results +> >|ID|Items Key Value| >|---|---| >| 6b21d1ef-18fa-420f-ae4a-a6f94588ebe8 | name: test_4_item
IP: 4.4.4.4 | ### azure-sentinel-threat-indicator-list + *** Returns a list of threat indicators. @@ -1353,6 +1447,7 @@ Returns a list of threat indicators. #### Base Command `azure-sentinel-threat-indicator-list` + #### Input | **Argument Name** | **Description** | **Required** | @@ -1398,17 +1493,20 @@ Returns a list of threat indicators. #### Command Example + ```!azure-sentinel-threat-indicator-list limit=2``` #### Human Readable Output ### Threat Indicators (2 results) + |Name|Display Name|Values|Types|Source|Tags| |---|---|---|---|---|---| | a31f2257-1af5-5eb9-bc82-acb8cc10becd | Name | test.value | malicious-activity | Azure Sentinel | Tag | | 1286115b-3b65-5537-e831-969045792910 | DisplayName | domain.dot | benign | Azure Sentinel | No Tags | ### azure-sentinel-threat-indicator-query + *** Returns a list of threat indicators with specific entities. @@ -1416,6 +1514,7 @@ Returns a list of threat indicators with specific entities. #### Base Command `azure-sentinel-threat-indicator-query` + #### Input | **Argument Name** | **Description** | **Required** | @@ -1469,17 +1568,20 @@ Returns a list of threat indicators with specific entities. #### Command Example + ```!azure-sentinel-threat-indicator-query max_confidence=70 ``` #### Human Readable Output ### Threat Indicators (2 results) + |Name|Display Name|Values|Types|Source|Confidence|Tags| |---|---|---|---|---|---|---| | a31f2257-1af5-5eb9-bc82-acb8cc10becd | DisplayName | domain.dot | compromised | Azure Sentinel | 50 | newTag | | 1286115b-3b65-5537-e831-969045792910 | Name | test.dot | compromised | Azure Sentinel | 68 | No Tags | ### azure-sentinel-threat-indicator-create + *** Creates a new threat indicator. @@ -1487,6 +1589,7 @@ Creates a new threat indicator. #### Base Command `azure-sentinel-threat-indicator-create` + #### Input | **Argument Name** | **Description** | **Required** | @@ -1542,16 +1645,19 @@ Creates a new threat indicator. #### Command Example + ```!azure-sentinel-threat-indicator-create display_name=name indicator_type=domain threat_types=benign value=good.test confidence=77``` #### Human Readable Output ### New threat Indicator was created + |Name|Display Name|Values|Types|Source|Confidence|Tags| |---|---|---|---|---|---|---| |a31f2257-1af5-5eb9-bc82-acb8cc10becd| name | good.test | benign | Azure Sentinel | 77 | No Tags | ### azure-sentinel-threat-indicator-update + *** Updates an existing threat indicator. @@ -1559,6 +1665,7 @@ Updates an existing threat indicator. #### Base Command `azure-sentinel-threat-indicator-update` + #### Input | **Argument Name** | **Description** | **Required** | @@ -1615,17 +1722,20 @@ Updates an existing threat indicator. #### Command Example + ```!azure-sentinel-threat-indicator-update indicator_name=a31f2257-1af5-5eb9-bc82-acb8cc10becd display_name=WeChangedTheDisplayName indicator_type="domain-name" value=verynew.value``` #### Human Readable Output ### Threat Indicator a31f2257-1af5-5eb9-bc82-acb8cc10becd was updated + |Name|Display Name|Values|Types|Source|Tags| |---|---|---|---|---|---| | a31f2257-1af5-5eb9-bc82-acb8cc10becd | WeChangedTheDisplayName | verynew.value | malicious-activity | Azure Sentinel | ReplaceTheTag | ### azure-sentinel-threat-indicator-delete + *** Deletes an existing threat indicator. @@ -1633,6 +1743,7 @@ Deletes an existing threat indicator. #### Base Command `azure-sentinel-threat-indicator-delete` + #### Input | **Argument Name** | **Description** | **Required** | @@ -1647,6 +1758,7 @@ Deletes an existing threat indicator. There is no context output for this command. #### Command Example + ```!azure-sentinel-threat-indicator-delete indicator_names=1286115b-3b65-5537-e831-969045792910``` #### Human Readable Output @@ -1655,6 +1767,7 @@ Threat Intelligence Indicators 1286115b-3b65-5537-e831-969045792910 were deleted ### azure-sentinel-threat-indicator-tags-append + *** Appends new tags to an existing indicator. @@ -1662,6 +1775,7 @@ Appends new tags to an existing indicator. #### Base Command `azure-sentinel-threat-indicator-tags-append` + #### Input | **Argument Name** | **Description** | **Required** | @@ -1674,38 +1788,39 @@ Appends new tags to an existing indicator. #### Context Output -| **Path** | **Type** | **Description** | -| --- | --- | --- | -| AzureSentinel.ThreatIndicator.ID | String | The ID of the indicator. | -| AzureSentinel.ThreatIndicator.Name | String | The name of the indicator. | -| AzureSentinel.ThreatIndicator.ETag | String | The ETag of the indicator. | -| AzureSentinel.ThreatIndicator.Type | String | The type of the indicator. | -| AzureSentinel.ThreatIndicator.Kind | String | The kind of the indicator. | -| AzureSentinel.ThreatIndicators.Confidence | Number | The confidence of the threat indicator. THis is a number between 0-100. | -| AzureSentinel.ThreatIndicator.Created | Date | When the threat indicator was created. | -| AzureSentinel.ThreatIndicator.CreatedByRef | String | The creator of the indicator. | -| AzureSentinel.ThreatIndicator.ExternalID | String | The external ID of the indicator. | -| AzureSentinel.ThreatIndicator.Revoked | Boolean | Was the threat indicator revoked or not. | -| AzureSentinel.ThreatIndicator.Source | String | The source of the indicator. | -| AzureSentinel.ThreatIndicator.ETags | String | The Etags of the indicator. | -| AzureSentinel.ThreatIndicator.DisplayName | String | The display name of the indicator. | -| AzureSentinel.ThreatIndicator.Description | String | The description of the indicator. | -| AzureSentinel.ThreatIndicator.ThreatTypes | Unknown | The threat types of the indicator. | -| AzureSentinel.ThreatIndicator.KillChainPhases.KillChainName | String | The kill chain's name of the indicator. | -| AzureSentinel.ThreatIndicator.ParsedPattern.PatternTypeKey | Unknown | The pattern type key of the indicator. | -| AzureSentinel.ThreatIndicator.Pattern | String | The pattern of the indicator. | -| AzureSentinel.ThreatIndicator.PatternType | String | The pattern type of the indicator. | -| AzureSentinel.ThreatIndicator.ValidFrom | Date | The date from which the indicator is valid. | -| AzureSentinel.ThreatIndicator.ValidUntil | Date | The date until which the indicator is valid. | -| AzureSentinel.ThreatIndicator.KillChainPhases.PhaseName | String | The phase name of the indicator. | -| AzureSentinel.ThreatIndicator.ParsedPattern.PatternTypeValues.Value | String | The value of the indicator. | -| AzureSentinel.ThreatIndicator.ParsedPattern.PatternTypeValues.ValueType | String | The value type of the indicator. | -| AzureSentinel.ThreatIndicator.LastUpdatedTimeUtc | Date | The last updated time of the indicator. | -| AzureSentinel.ThreatIndicator.Tags | Unknown | The tags of the indicator. | -| AzureSentinel.ThreatIndicator.Types | Unknown | The threat types of the indicator. | +| **Path** | **Type** | **Description** | +| --- | --- |-------------------------------------------------------------------------| +| AzureSentinel.ThreatIndicator.ID | String | The ID of the indicator. | +| AzureSentinel.ThreatIndicator.Name | String | The name of the indicator. | +| AzureSentinel.ThreatIndicator.ETag | String | The ETag of the indicator. | +| AzureSentinel.ThreatIndicator.Type | String | The type of the indicator. | +| AzureSentinel.ThreatIndicator.Kind | String | The kind of the indicator. | +| AzureSentinel.ThreatIndicators.Confidence | Number | The confidence of the threat indicator. This is a number between 0-100. | +| AzureSentinel.ThreatIndicator.Created | Date | When the threat indicator was created. | +| AzureSentinel.ThreatIndicator.CreatedByRef | String | The creator of the indicator. | +| AzureSentinel.ThreatIndicator.ExternalID | String | The external ID of the indicator. | +| AzureSentinel.ThreatIndicator.Revoked | Boolean | Was the threat indicator revoked or not. | +| AzureSentinel.ThreatIndicator.Source | String | The source of the indicator. | +| AzureSentinel.ThreatIndicator.ETags | String | The Etags of the indicator. | +| AzureSentinel.ThreatIndicator.DisplayName | String | The display name of the indicator. | +| AzureSentinel.ThreatIndicator.Description | String | The description of the indicator. | +| AzureSentinel.ThreatIndicator.ThreatTypes | Unknown | The threat types of the indicator. | +| AzureSentinel.ThreatIndicator.KillChainPhases.KillChainName | String | The kill chain's name of the indicator. | +| AzureSentinel.ThreatIndicator.ParsedPattern.PatternTypeKey | Unknown | The pattern type key of the indicator. | +| AzureSentinel.ThreatIndicator.Pattern | String | The pattern of the indicator. | +| AzureSentinel.ThreatIndicator.PatternType | String | The pattern type of the indicator. | +| AzureSentinel.ThreatIndicator.ValidFrom | Date | The date from which the indicator is valid. | +| AzureSentinel.ThreatIndicator.ValidUntil | Date | The date until which the indicator is valid. | +| AzureSentinel.ThreatIndicator.KillChainPhases.PhaseName | String | The phase name of the indicator. | +| AzureSentinel.ThreatIndicator.ParsedPattern.PatternTypeValues.Value | String | The value of the indicator. | +| AzureSentinel.ThreatIndicator.ParsedPattern.PatternTypeValues.ValueType | String | The value type of the indicator. | +| AzureSentinel.ThreatIndicator.LastUpdatedTimeUtc | Date | The last updated time of the indicator. | +| AzureSentinel.ThreatIndicator.Tags | Unknown | The tags of the indicator. | +| AzureSentinel.ThreatIndicator.Types | Unknown | The threat types of the indicator. | #### Command Example + ```!azure-sentinel-threat-indicator-tags-append indicator_name=1286115b-3b65-5537-e831-969045792910 tags=newtag``` #### Human Readable Output @@ -1713,6 +1828,7 @@ Appends new tags to an existing indicator. Tags were appended to 1286115b-3b65-5537-e831-969045792910 Threat Indicator. ### azure-sentinel-threat-indicator-tags-replace + *** Replaces the tags of a given indicator. @@ -1720,6 +1836,7 @@ Replaces the tags of a given indicator. #### Base Command `azure-sentinel-threat-indicator-tags-replace` + #### Input | **Argument Name** | **Description** | **Required** | @@ -1764,6 +1881,7 @@ Replaces the tags of a given indicator. #### Command Example + ```!azure-sentinel-threat-indicator-tags-replace name=1286115b-3b65-5537-e831-969045792910 tags=newtag``` #### Human Readable Output @@ -1771,6 +1889,7 @@ Replaces the tags of a given indicator. Tags were replaced to 1286115b-3b65-5537-e831-969045792910 Threat Indicator. ### azure-sentinel-list-alert-rule + *** Gets a list of all alert rules. @@ -1778,6 +1897,7 @@ Gets a list of all alert rules. #### Base Command `azure-sentinel-list-alert-rule` + #### Input | **Argument Name** | **Description** | **Required** | @@ -1832,8 +1952,11 @@ Gets a list of all alert rules. | AzureSentinel.AlertRule.properties.displayNamesFilter | Unknown | The alerts' displayNames on which the cases will be generated | #### Command example + ```!azure-sentinel-list-alert-rule limit=1``` + #### Context Example + ```json { "AzureSentinel": { @@ -1907,11 +2030,13 @@ Gets a list of all alert rules. #### Human Readable Output >### Azure Sentinel Alert Rules +> >|ID|Kind|Severity|Display Name|Description|Enabled| >|---|---|---|---|---|---| >| test-rule-id | Scheduled | Low | testing displayname | | true | ### azure-sentinel-list-alert-rule-template + *** Gets a list of all alert rule templates. @@ -1919,6 +2044,7 @@ Gets a list of all alert rule templates. #### Base Command `azure-sentinel-list-alert-rule-template` + #### Input | **Argument Name** | **Description** | **Required** | @@ -1956,8 +2082,11 @@ Gets a list of all alert rule templates. | AzureSentinel.AlertRuleTemplate.properties.productFilter | String | The alerts' productName on which the cases will be generated. | #### Command example + ```!azure-sentinel-list-alert-rule-template limit=1``` + #### Context Example + ```json { "AzureSentinel": { @@ -2001,9 +2130,10 @@ Gets a list of all alert rule templates. #### Human Readable Output >### Azure Sentinel Alert Rule Template +> >|ID|Kind|Severity|Display Name|Description|Status|Created Date UTC|Last Updated Date UTC|Alert Rules Created By Template Count| >|---|---|---|---|---|---|---|---|---| ->| test-rule-template-id | Scheduled | Low | Changes to Amazon VPC settings | This alert monitors changes to Amazon VPC (Virtual Private Cloud) settings such as new ACL entries and routes in route tables.
More information: https://medium.com/@GorillaStack/the-most-important-aws-cloudtrail-security-events-to-track-a5b9873f8255
and https://aws.amazon.com/vpc/ | Available | 2019-02-27T00:00:00Z | 2021-02-27T10:00:00Z | 0 | +>| test-rule-template-id | Scheduled | Low | Changes to Amazon VPC settings | This alert monitors changes to Amazon VPC (Virtual Private Cloud) settings such as new ACL entries and routes in route tables.
More information:
and | Available | 2019-02-27T00:00:00Z | 2021-02-27T10:00:00Z | 0 | ### azure-sentinel-delete-alert-rule @@ -2030,8 +2160,11 @@ Deletes the specified alert rule. | AzureSentinel.AlertRule.Deleted | Boolean | Whether the alert rule was deleted. | #### Command example + ```!azure-sentinel-delete-alert-rule rule_id=1234-abcd-5678-efgh``` + #### Context Example + ```json { "AzureSentinel": { @@ -2046,6 +2179,7 @@ Deletes the specified alert rule. #### Human Readable Output >Alert rule 1234-abcd-5678-efgh was deleted successfully. +> ### azure-sentinel-create-alert-rule *** @@ -2086,39 +2220,42 @@ Creates a new alert rule. #### Context Output -| **Path** | **Type** | **Description** | -| --- | --- | --- | -| AzureSentinel.AlertRule.id | String | Fully qualified resource ID for the resource. | -| AzureSentinel.AlertRule.name | String | The name of the resource. | -| AzureSentinel.AlertRule.etag | String | ETag of the Azure resource. | -| AzureSentinel.AlertRule.type | String | The type of the resource. E.g., "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts" | -| AzureSentinel.AlertRule.kind | String | The alert rule kind. | -| AzureSentinel.AlertRule.properties.displayName | String | The display name for alerts created by this alert rule. | -| AzureSentinel.AlertRule.properties.description | String | The description of the alert rule. | -| AzureSentinel.AlertRule.properties.alertRuleTemplateName | Unknown | The name of the alert rule template used to create this rule. | -| AzureSentinel.AlertRule.properties.tactics | String | The tactics of the alert rule. | -| AzureSentinel.AlertRule.properties.severity | String | The severity for alerts created by this alert rule. | -| AzureSentinel.AlertRule.properties.enabled | Boolean | Determines whether this alert rule is enabled or disabled. | -| AzureSentinel.AlertRule.properties.lastModifiedUtc | Date | The last time that this alert was modified. | -| AzureSentinel.AlertRule.properties.productFilter | String | The alerts' productName on which the cases will be generated. | -| AzureSentinel.AlertRule.properties.severitiesFilter | Unknown | The alerts' severities on which the cases will be generated. | -| AzureSentinel.AlertRule.properties.displayNamesFilter | Unknown | The alerts' displayNames on which the cases will be generated. | -| AzureSentinel.AlertRule.properties.query | String | The query that creates alerts for this rule. | -| AzureSentinel.AlertRule.properties.queryFrequency | String | The frequency \(in ISO 8601 duration format\) for this alert rule to run. | -| AzureSentinel.AlertRule.properties.queryPeriod | String | The period \(in ISO 8601 duration format\) that this alert rule looks at. | -| AzureSentinel.AlertRule.properties.triggerOperator | String | The operation against the threshold that triggers the alert rule. | -| AzureSentinel.AlertRule.properties.triggerThreshold | Number | The threshold that triggers this alert rule. | +| **Path** | **Type** | **Description** | +| --- | --- |------------------------------------------------------------------------------------------------------------| +| AzureSentinel.AlertRule.id | String | Fully qualified resource ID for the resource. | +| AzureSentinel.AlertRule.name | String | The name of the resource. | +| AzureSentinel.AlertRule.etag | String | ETag of the Azure resource. | +| AzureSentinel.AlertRule.type | String | The type of the resource, e.g., "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts" | +| AzureSentinel.AlertRule.kind | String | The alert rule kind. | +| AzureSentinel.AlertRule.properties.displayName | String | The display name for alerts created by this alert rule. | +| AzureSentinel.AlertRule.properties.description | String | The description of the alert rule. | +| AzureSentinel.AlertRule.properties.alertRuleTemplateName | Unknown | The name of the alert rule template used to create this rule. | +| AzureSentinel.AlertRule.properties.tactics | String | The tactics of the alert rule. | +| AzureSentinel.AlertRule.properties.severity | String | The severity for alerts created by this alert rule. | +| AzureSentinel.AlertRule.properties.enabled | Boolean | Determines whether this alert rule is enabled or disabled. | +| AzureSentinel.AlertRule.properties.lastModifiedUtc | Date | The last time that this alert was modified. | +| AzureSentinel.AlertRule.properties.productFilter | String | The alerts' productName on which the cases will be generated. | +| AzureSentinel.AlertRule.properties.severitiesFilter | Unknown | The alerts' severities on which the cases will be generated. | +| AzureSentinel.AlertRule.properties.displayNamesFilter | Unknown | The alerts' displayNames on which the cases will be generated. | +| AzureSentinel.AlertRule.properties.query | String | The query that creates alerts for this rule. | +| AzureSentinel.AlertRule.properties.queryFrequency | String | The frequency \(in ISO 8601 duration format\) for this alert rule to run. | +| AzureSentinel.AlertRule.properties.queryPeriod | String | The period \(in ISO 8601 duration format\) that this alert rule looks at. | +| AzureSentinel.AlertRule.properties.triggerOperator | String | The operation against the threshold that triggers the alert rule. | +| AzureSentinel.AlertRule.properties.triggerThreshold | Number | The threshold that triggers this alert rule. | | AzureSentinel.AlertRule.properties.suppressionDuration | String | The suppression \(in ISO 8601 duration format\) to wait since the last time this alert rule was triggered. | -| AzureSentinel.AlertRule.properties.suppressionEnabled | Boolean | Determines whether the suppression for this alert rule is enabled or disabled. | -| AzureSentinel.AlertRule.properties.eventGroupingSettings | Unknown | The event grouping settings. | -| AzureSentinel.AlertRule.properties.customDetails | Unknown | Dictionary of string key-value pairs of columns to be attached to the alert. | -| AzureSentinel.AlertRule.properties.entityMappings | Unknown | Array of the entity mappings of the alert rule. | -| AzureSentinel.AlertRule.properties.alertDetailsOverride | String | The alert details override settings. | -| AzureSentinel.AlertRule.properties.incidentConfiguration | Unknown | The settings of the incidents that created from alerts triggered by this analytics rule. | +| AzureSentinel.AlertRule.properties.suppressionEnabled | Boolean | Determines whether the suppression for this alert rule is enabled or disabled. | +| AzureSentinel.AlertRule.properties.eventGroupingSettings | Unknown | The event grouping settings. | +| AzureSentinel.AlertRule.properties.customDetails | Unknown | Dictionary of string key-value pairs of columns to be attached to the alert. | +| AzureSentinel.AlertRule.properties.entityMappings | Unknown | Array of the entity mappings of the alert rule. | +| AzureSentinel.AlertRule.properties.alertDetailsOverride | String | The alert details override settings. | +| AzureSentinel.AlertRule.properties.incidentConfiguration | Unknown | The settings of the incidents that created from alerts triggered by this analytics rule. | #### Command example + ```!azure-sentinel-create-alert-rule enabled=true kind=microsoft_security_incident_creation rule_name=test_name displayName="Testing Display Name" product_filter=microsoft_cloud_app_security``` + #### Context Example + ```json { "AzureSentinel": { @@ -2147,6 +2284,7 @@ Creates a new alert rule. #### Human Readable Output >### Azure Sentinel Alert Rule successfully created/updated +> >|ID|Name|Kind|Display Name|Enabled|Etag| >|---|---|---|---|---|---|---|---| >| test_name | test_name | MicrosoftSecurityIncidentCreation | Testing Display Name | true | "09009060-0000-5e60000" | @@ -2191,39 +2329,42 @@ Updates an alert rule. #### Context Output -| **Path** | **Type** | **Description** | -| --- | --- | --- | -| AzureSentinel.AlertRule.id | String | Fully qualified resource ID for the resource. | -| AzureSentinel.AlertRule.name | String | The name of the resource. | -| AzureSentinel.AlertRule.etag | String | ETag of the Azure resource. | -| AzureSentinel.AlertRule.type | String | The type of the resource. E.g., "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts" | -| AzureSentinel.AlertRule.kind | String | The alert rule kind. | -| AzureSentinel.AlertRule.properties.displayName | String | The display name for alerts created by this alert rule. | -| AzureSentinel.AlertRule.properties.description | String | The description of the alert rule. | -| AzureSentinel.AlertRule.properties.alertRuleTemplateName | Unknown | The name of the alert rule template used to update this rule. | -| AzureSentinel.AlertRule.properties.tactics | String | The tactics of the alert rule. | -| AzureSentinel.AlertRule.properties.severity | String | The severity for alerts created by this alert rule. | -| AzureSentinel.AlertRule.properties.enabled | Boolean | Determines whether this alert rule is enabled or disabled. | -| AzureSentinel.AlertRule.properties.lastModifiedUtc | Date | The last time this alert was modified. | -| AzureSentinel.AlertRule.properties.productFilter | String | The alerts' productName on which the cases will be generated. | -| AzureSentinel.AlertRule.properties.severitiesFilter | Unknown | The alerts' severities on which the cases will be generated. | -| AzureSentinel.AlertRule.properties.displayNamesFilter | Unknown | The alerts' displayNames on which the cases will be generated. | -| AzureSentinel.AlertRule.properties.query | String | The query that creates alerts for this rule. | -| AzureSentinel.AlertRule.properties.queryFrequency | String | The frequency \(in ISO 8601 duration format\) for this alert rule to run. | -| AzureSentinel.AlertRule.properties.queryPeriod | String | The period \(in ISO 8601 duration format\) that this alert rule looks at. | -| AzureSentinel.AlertRule.properties.triggerOperator | String | The operation against the threshold that triggers alert rule. | -| AzureSentinel.AlertRule.properties.triggerThreshold | Number | The threshold triggers this alert rule. | +| **Path** | **Type** | **Description** | +| --- | --- |-------------------------------------------------------------------------------------------------------------| +| AzureSentinel.AlertRule.id | String | Fully qualified resource ID for the resource. | +| AzureSentinel.AlertRule.name | String | The name of the resource. | +| AzureSentinel.AlertRule.etag | String | ETag of the Azure resource. | +| AzureSentinel.AlertRule.type | String | The type of the resource, e.g., "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts" | +| AzureSentinel.AlertRule.kind | String | The alert rule kind. | +| AzureSentinel.AlertRule.properties.displayName | String | The display name for alerts created by this alert rule. | +| AzureSentinel.AlertRule.properties.description | String | The description of the alert rule. | +| AzureSentinel.AlertRule.properties.alertRuleTemplateName | Unknown | The name of the alert rule template used to update this rule. | +| AzureSentinel.AlertRule.properties.tactics | String | The tactics of the alert rule. | +| AzureSentinel.AlertRule.properties.severity | String | The severity for alerts created by this alert rule. | +| AzureSentinel.AlertRule.properties.enabled | Boolean | Determines whether this alert rule is enabled or disabled. | +| AzureSentinel.AlertRule.properties.lastModifiedUtc | Date | The last time this alert was modified. | +| AzureSentinel.AlertRule.properties.productFilter | String | The alerts' productName on which the cases will be generated. | +| AzureSentinel.AlertRule.properties.severitiesFilter | Unknown | The alerts' severities on which the cases will be generated. | +| AzureSentinel.AlertRule.properties.displayNamesFilter | Unknown | The alerts' displayNames on which the cases will be generated. | +| AzureSentinel.AlertRule.properties.query | String | The query that creates alerts for this rule. | +| AzureSentinel.AlertRule.properties.queryFrequency | String | The frequency \(in ISO 8601 duration format\) for this alert rule to run. | +| AzureSentinel.AlertRule.properties.queryPeriod | String | The period \(in ISO 8601 duration format\) that this alert rule looks at. | +| AzureSentinel.AlertRule.properties.triggerOperator | String | The operation against the threshold that triggers alert rule. | +| AzureSentinel.AlertRule.properties.triggerThreshold | Number | The threshold triggers this alert rule. | | AzureSentinel.AlertRule.properties.suppressionDuration | String | The suppression \(in ISO 8601 duration format\) to wait since the last time this alert rule been triggered. | -| AzureSentinel.AlertRule.properties.suppressionEnabled | Boolean | Determines whether the suppression for this alert rule is enabled or disabled. | -| AzureSentinel.AlertRule.properties.eventGroupingSettings | Unknown | The event grouping settings. | -| AzureSentinel.AlertRule.properties.customDetails | Unknown | Dictionary of string key-value pairs of columns to be attached to the alert | -| AzureSentinel.AlertRule.properties.entityMappings | Unknown | Array of the entity mappings of the alert rule. | -| AzureSentinel.AlertRule.properties.alertDetailsOverride | String | The alert details override settings. | -| AzureSentinel.AlertRule.properties.incidentConfiguration | Unknown | The settings of the incidents that created from alerts triggered by this analytics rule. | +| AzureSentinel.AlertRule.properties.suppressionEnabled | Boolean | Determines whether the suppression for this alert rule is enabled or disabled. | +| AzureSentinel.AlertRule.properties.eventGroupingSettings | Unknown | The event grouping settings. | +| AzureSentinel.AlertRule.properties.customDetails | Unknown | Dictionary of string key-value pairs of columns to be attached to the alert | +| AzureSentinel.AlertRule.properties.entityMappings | Unknown | Array of the entity mappings of the alert rule. | +| AzureSentinel.AlertRule.properties.alertDetailsOverride | String | The alert details override settings. | +| AzureSentinel.AlertRule.properties.incidentConfiguration | Unknown | The settings of the incidents that created from alerts triggered by this analytics rule. | #### Command example + ```!azure-sentinel-update-alert-rule enabled=true kind=microsoft_security_incident_creation rule_name=test_name displayName="Testing updating Display Name" product_filter=microsoft_cloud_app_security``` + #### Context Example + ```json { "AzureSentinel": { @@ -2252,6 +2393,7 @@ Updates an alert rule. #### Human Readable Output >### Azure Sentinel Alert Rule successfully created/updated +> >|ID|Name|Kind|Display Name|Enabled|Etag| >|---|---|---|---|---|---|---|---| >| test_name | test_name | MicrosoftSecurityIncidentCreation | Testing updating Display Name | true | "097809060-0000-6hd400" | diff --git a/Packs/AzureSentinel/ReleaseNotes/1_5_8.md b/Packs/AzureSentinel/ReleaseNotes/1_5_8.md index 9f58aa010fbb..4834e2f03b90 100644 --- a/Packs/AzureSentinel/ReleaseNotes/1_5_8.md +++ b/Packs/AzureSentinel/ReleaseNotes/1_5_8.md @@ -4,4 +4,4 @@ ##### Microsoft Sentinel - Fixed an issue where ***azure-sentinel-threat-indicator-query*** would fail when provided with multiple keywords. -- Updated the Docker image to: *demisto/crypto:1.0.0.62834*. \ No newline at end of file +- Updated the Docker image to: *demisto/crypto:1.0.0.62834*. diff --git a/Packs/AzureSentinel/ReleaseNotes/1_5_9.md b/Packs/AzureSentinel/ReleaseNotes/1_5_9.md new file mode 100644 index 000000000000..f65d78a9a423 --- /dev/null +++ b/Packs/AzureSentinel/ReleaseNotes/1_5_9.md @@ -0,0 +1,9 @@ + +#### Integrations + +##### Microsoft Sentinel + +- Updated the Docker image to: *demisto/crypto:1.0.0.63672*. + +- Added support for All Azure Cloud environments: Public, GCC, GCC-High, DoD, Germany, China. + diff --git a/Packs/AzureSentinel/pack_metadata.json b/Packs/AzureSentinel/pack_metadata.json index c6076ea12633..e99cf1b699d0 100644 --- a/Packs/AzureSentinel/pack_metadata.json +++ b/Packs/AzureSentinel/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Microsoft Sentinel", "description": "Microsoft Sentinel is a cloud-native security information and event manager (SIEM) platform that uses built-in AI to help analyze large volumes of data across an enterprise.", "support": "xsoar", - "currentVersion": "1.5.8", + "currentVersion": "1.5.9", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/MicrosoftDefenderAdvancedThreatProtection/.pack-ignore b/Packs/MicrosoftDefenderAdvancedThreatProtection/.pack-ignore index 8a9da566a075..7a7104c0bed9 100644 --- a/Packs/MicrosoftDefenderAdvancedThreatProtection/.pack-ignore +++ b/Packs/MicrosoftDefenderAdvancedThreatProtection/.pack-ignore @@ -12,10 +12,62 @@ sc ms offboarding offboard +ATP +misconfigurations +endpoints +hostname +Unisolate +Unisolates +GCC +DoD +URLs +XSIAM +SSL +DBot +Dns +aad +rbac +https +auth +VM +Deprecated +WDATP +hashes +UTC +s +logons +UPN +authenticode +ls +ctph +Mutex +delimited +CIDR +IPv4 +IPv6 +TCP +DDoS +RFC +libmagic +KBs +CVE +CVSS +severities +Kb +Backslashes +errorHResult +params +Args +SMB +FW +beaconing +MSDE +D +Pv +H [file:Microsoft365DefenderEventCollector_1_3.yml] ignore=MR108 [file:Microsoft365DefenderEventCollector.yml] ignore=MR108 - diff --git a/Packs/MicrosoftDefenderAdvancedThreatProtection/.secrets-ignore b/Packs/MicrosoftDefenderAdvancedThreatProtection/.secrets-ignore index 2e21b6644a48..17b49a4ad544 100644 --- a/Packs/MicrosoftDefenderAdvancedThreatProtection/.secrets-ignore +++ b/Packs/MicrosoftDefenderAdvancedThreatProtection/.secrets-ignore @@ -188,3 +188,10 @@ us.center.windows.com:443/safe/ 7.0.2.0 6.2.4.0 XDM_CONST.OUTCOME_PARTIAL, +https://gallery.azure.com +https://management.core.windows.net +https://portal.azure.cn +https://portal.azure.com +https://portal.azure.us +https://vault.azure.cn +https://vault.azure.net diff --git a/Packs/MicrosoftDefenderAdvancedThreatProtection/Integrations/Microsoft365DefenderEventCollector/Microsoft365DefenderEventCollector.py b/Packs/MicrosoftDefenderAdvancedThreatProtection/Integrations/Microsoft365DefenderEventCollector/Microsoft365DefenderEventCollector.py index a9d88073b802..68830dce8c65 100644 --- a/Packs/MicrosoftDefenderAdvancedThreatProtection/Integrations/Microsoft365DefenderEventCollector/Microsoft365DefenderEventCollector.py +++ b/Packs/MicrosoftDefenderAdvancedThreatProtection/Integrations/Microsoft365DefenderEventCollector/Microsoft365DefenderEventCollector.py @@ -1,5 +1,6 @@ # pylint: disable=no-name-in-module # pylint: disable=no-self-argument +import copy import demistomock as demisto from CommonServerPython import * # noqa # pylint: disable=unused-wildcard-import @@ -14,7 +15,6 @@ import requests import urllib3.util - from MicrosoftApiModule import * # Disable insecure warnings @@ -23,8 +23,7 @@ ''' CONSTANTS ''' MAX_ALERTS_PAGE_SIZE = 1000 ALERT_CREATION_TIME = 'alertCreationTime' -DEFNDER_DATE_FORMAT = '%Y-%m-%dT%H:%M:%S.%fZ' -SECURITY_SCOPE = 'https://securitycenter.onmicrosoft.com/windowsatpservice/.default' +DEFENDER_DATE_FORMAT = '%Y-%m-%dT%H:%M:%S.%fZ' AUTH_ERROR_MSG = 'Authorization Error: make sure tenant id, client id and client secret is correctly set' VENDOR = 'Microsoft 365' PRODUCT = 'Defender' @@ -62,7 +61,7 @@ class IntegrationHTTPRequest(BaseModel): method: Method url: AnyUrl verify: bool = True - headers: dict = dict() # type: ignore[type-arg] + headers: dict = {} # type: ignore[type-arg] auth: Optional[HTTPBasicAuth] data: Any = None @@ -79,12 +78,12 @@ class Credentials(BaseModel): password: str -def set_authorization(request: IntegrationHTTPRequest, auth_credendtials): +def set_authorization(request: IntegrationHTTPRequest, auth_credentials): """Automatic authorization. Supports {Authorization: Bearer __token__} or Basic Auth. """ - creds = Credentials.parse_obj(auth_credendtials) + creds = Credentials.parse_obj(auth_credentials) if creds.password and creds.identifier: request.auth = HTTPBasicAuth(creds.identifier, creds.password) auth = {'Authorization': f'Bearer {creds.password}'} @@ -181,7 +180,7 @@ def get_last_run(events: list) -> dict: @abstractmethod def _iter_events(self): """Create iterators with Yield""" - pass + raise NotImplementedError # END COPY OF SiemApiModule @@ -194,6 +193,8 @@ class DefenderIntegrationOptions(IntegrationOptions): class DefenderAuthenticator(BaseModel): verify: bool url: str + endpoint_type: str + scope_url: str tenant_id: str client_id: str credentials: dict @@ -202,13 +203,13 @@ class DefenderAuthenticator(BaseModel): def set_authorization(self, request: IntegrationHTTPRequest): try: if not self.ms_client: - demisto.debug('try init the ms client for the first time') + demisto.debug(f"try init the ms client for the first time, {self.url=}") self.ms_client = MicrosoftClient( base_url=self.url, tenant_id=self.tenant_id, auth_id=self.client_id, enc_key=self.credentials.get('password'), - scope=SECURITY_SCOPE, + scope=urljoin(self.scope_url, "/windowsatpservice/.default"), verify=self.verify, self_deployed=True ) @@ -231,11 +232,11 @@ def set_authorization(self, request: IntegrationHTTPRequest): class DefenderHTTPRequest(IntegrationHTTPRequest): - params: dict = dict() + params: dict = {} method: Method = Method.GET _normalize_url = validator('url', pre=True, allow_reuse=True)( - lambda base_url: base_url + '/api/alerts' + lambda base_url: f'{base_url}/api/alerts' ) @@ -253,7 +254,7 @@ def set_request_filter(self, after: Any): if not after: demisto.debug(f'lastRunObj is empty, calculate the first fetch time according {self.options.first_fetch=}') first_fetch_date = dateparser.parse(self.options.first_fetch, settings={'TIMEZONE': 'UTC'}) - after = datetime.strftime(first_fetch_date, DEFNDER_DATE_FORMAT) # type: ignore[arg-type] + after = datetime.strftime(first_fetch_date, DEFENDER_DATE_FORMAT) # type: ignore[arg-type] self.request.params = { '$filter': f'{ALERT_CREATION_TIME}+gt+{after}', '$orderby': f'{ALERT_CREATION_TIME}+asc', @@ -312,6 +313,7 @@ def get_last_run(events: list) -> dict: ''' HELPER FUNCTIONS ''' + ''' COMMAND FUNCTIONS ''' @@ -328,30 +330,35 @@ def test_module(get_events: DefenderGetEvents) -> str: :return: 'ok' if test passed, anything else will fail the test. :rtype: ``str`` """ - - message: str = '' try: get_events.client.request.params = {'limit': 1} get_events.run() - message = 'ok' + return 'ok' except DemistoException as e: if 'Forbidden' in str(e) or 'authenticate' in str(e): - message = AUTH_ERROR_MSG - else: - raise - return message + return AUTH_ERROR_MSG + raise -def main(command: str, demisto_params: dict): +def main(command: str, params: dict): demisto.debug(f'Command being called is {command}') try: + params_endpoint_type = params.get('endpoint_type') or 'Worldwide' + params_url = params.get('url') + # is_gcc wasn't supported in the event collector, thus passing it as None. + endpoint_type, params_url = microsoft_defender_for_endpoint_get_base_url(params_endpoint_type, params_url) + + parsed_params = copy.copy(params) + parsed_params["url"] = params_url + parsed_params["endpoint_type"] = endpoint_type + parsed_params["scope_url"] = MICROSOFT_DEFENDER_FOR_ENDPOINT_APT_SERVICE_ENDPOINTS[endpoint_type] - options = DefenderIntegrationOptions.parse_obj(demisto_params) - request = DefenderHTTPRequest.parse_obj(demisto_params) - authenticator = DefenderAuthenticator.parse_obj(demisto_params) + options = DefenderIntegrationOptions.parse_obj(parsed_params) + request = DefenderHTTPRequest.parse_obj(parsed_params) + authenticator = DefenderAuthenticator.parse_obj(parsed_params) - clinet = DefenderClient(request=request, options=options, authenticator=authenticator) - get_events = DefenderGetEvents(client=clinet, options=options) + client = DefenderClient(request=request, options=options, authenticator=authenticator) + get_events = DefenderGetEvents(client=client, options=options) if command == 'test-module': return_results(test_module(get_events=get_events)) @@ -363,7 +370,7 @@ def main(command: str, demisto_params: dict): return_results( CommandResults('Microsoft365Defender.alerts', 'id', events, readable_output=human_readable)) - if argToBoolean(demisto_params.get('push_to_xsiam', False)): + if argToBoolean(params.get('push_to_xsiam', False)): demisto.debug(f'{command=}, publishing events to XSIAM') send_events_to_xsiam(events, vendor=VENDOR, product=PRODUCT) @@ -382,7 +389,7 @@ def main(command: str, demisto_params: dict): ''' ENTRY POINT ''' -if __name__ in ('__main__', '__builtin__', 'builtins'): +if __name__ in ('__main__', '__builtin__', 'builtins'): # pragma: no cover # Args is always stronger. Get getIntegrationContext even stronger demisto_params = demisto.params() | demisto.args() | demisto.getLastRun() main(demisto.command(), demisto_params) diff --git a/Packs/MicrosoftDefenderAdvancedThreatProtection/Integrations/Microsoft365DefenderEventCollector/Microsoft365DefenderEventCollector.yml b/Packs/MicrosoftDefenderAdvancedThreatProtection/Integrations/Microsoft365DefenderEventCollector/Microsoft365DefenderEventCollector.yml index 09a712ef94a6..acd83cebdf53 100644 --- a/Packs/MicrosoftDefenderAdvancedThreatProtection/Integrations/Microsoft365DefenderEventCollector/Microsoft365DefenderEventCollector.yml +++ b/Packs/MicrosoftDefenderAdvancedThreatProtection/Integrations/Microsoft365DefenderEventCollector/Microsoft365DefenderEventCollector.yml @@ -7,33 +7,41 @@ commonfields: version: -1 configuration: - additionalinfo: |- - The United States: api-us.security.microsoft.com - Europe: api-eu.security.microsoft.com - The United Kingdom: api-uk.security.microsoft.co - defaultvalue: https://api.security.microsoft.com - display: Endpoint URI - name: url + When selecting the Custom option, the Server URL parameter must be filled. More information can be found on the integration page - https://xsoar.pan.dev/docs/reference/integrations/microsoft-365-defender-event-collector + defaultvalue: Worldwide + display: Endpoint Type + name: endpoint_type + required: false + type: 15 + section: Connect + options: + - Worldwide + - EU Geo Proximity + - UK Geo Proximity + - US Geo Proximity + - US GCC + - US GCC-High + - DoD + - Custom + advanced: true +- display: Tenant ID + name: tenant_id required: true type: 0 section: Connect -- additionalinfo: The Client (Application) ID to use to connect. - display: Client (Application) ID - name: client_id + advanced: false +- name: client_id required: true type: 0 section: Connect -- displaypassword: Client Secret - name: credentials + additionalinfo: The Client (Application) ID to use to connect. + display: Client (Application) ID +- name: credentials required: true type: 9 - hiddenusername: true section: Connect -- display: Tenant ID - name: tenant_id - required: true - type: 0 - section: Connect - advanced: true + displaypassword: Client Secret + hiddenusername: true - defaultvalue: 3 days display: First fetch timestamp (