Skip to content

Commit

Permalink
Azure network security groups add user auth (#20779)
Browse files Browse the repository at this point in the history
* add docs

* rn

* minor fix

* fix unit tests

* cr fixes
  • Loading branch information
ostolero committed Aug 31, 2022
1 parent fbe9417 commit 2490a88
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 70 deletions.
@@ -1,6 +1,7 @@
import demistomock as demisto
from CommonServerPython import *
from CommonServerUserPython import *
from MicrosoftApiModule import * # noqa: E402

import urllib3
import traceback
Expand All @@ -14,37 +15,46 @@

DATE_FORMAT = '%Y-%m-%dT%H:%M:%SZ'
API_VERSION = '2020-05-01'

GRANT_BY_CONNECTION = {'Device Code': DEVICE_CODE, 'Authorization Code': AUTHORIZATION_CODE}
SCOPE_BY_CONNECTION = {'Device Code': "https://management.azure.com/user_impersonation offline_access user.read",
'Authorization Code': "https://management.azure.com/.default"}
''' CLIENT CLASS '''


class AzureNSGClient:
@logger
def __init__(self, app_id, subscription_id, resource_group_name, verify, proxy,
azure_ad_endpoint='https://login.microsoftonline.com'):
def __init__(self, app_id, subscription_id, resource_group_name, verify, proxy, connection_type: str,
azure_ad_endpoint='https://login.microsoftonline.com', tenant_id: str = None, enc_key: str = None,
auth_code: str = None, redirect_uri: str = None):
if '@' in app_id:
app_id, refresh_token = app_id.split('@')
integration_context = get_integration_context()
integration_context.update(current_refresh_token=refresh_token)
set_integration_context(integration_context)
base_url = f'https://management.azure.com/subscriptions/{subscription_id}/' \
f'resourceGroups/{resource_group_name}/providers/Microsoft.Network/networkSecurityGroups'
client_args = {
'self_deployed': True, # We always set the self_deployed key as True because when not using a self
# deployed machine, the DEVICE_CODE flow should behave somewhat like a self deployed
# flow and most of the same arguments should be set, as we're !not! using OProxy.
'auth_id': app_id,
'token_retrieval_url': 'https://login.microsoftonline.com/organizations/oauth2/v2.0/token',
'grant_type': DEVICE_CODE, # disable-secrets-detection
'base_url': base_url,
'verify': verify,
'proxy': proxy,
'resource': 'https://management.core.windows.net', # disable-secrets-detection
'scope': 'https://management.azure.com/user_impersonation offline_access user.read',
'ok_codes': (200, 201, 202, 204),
'azure_ad_endpoint': azure_ad_endpoint
}
client_args = assign_params(
self_deployed=True, # We always set the self_deployed key as True because when not using a self
# deployed machine, the DEVICE_CODE flow should behave somewhat like a self deployed
# flow and most of the same arguments should be set, as we're !not! using OProxy.
auth_id=app_id,
token_retrieval_url='https://login.microsoftonline.com/organizations/oauth2/v2.0/token',
grant_type=GRANT_BY_CONNECTION[connection_type], # disable-secrets-detection
base_url=base_url,
verify=verify,
proxy=proxy,
resource='https://management.core.windows.net' if 'Device' in connection_type
else None, # disable-secrets-detection
scope=SCOPE_BY_CONNECTION[connection_type],
ok_codes=(200, 201, 202, 204),
azure_ad_endpoint=azure_ad_endpoint,
tenant_id=tenant_id,
enc_key=enc_key,
auth_code=auth_code,
redirect_uri=redirect_uri
)
self.ms_client = MicrosoftClient(**client_args)
self.connection_type = connection_type

@logger
def http_request(self, method: str, url_suffix: str = None, full_url: str = None, params: dict = None,
Expand Down Expand Up @@ -338,6 +348,29 @@ def reset_auth(client: AzureNSGClient):
'**!azure-nsg-auth-start** and **!azure-nsg-auth-complete**.')


def test_module(client: AzureNSGClient) -> str:
"""Tests API connectivity and authentication'
Returning 'ok' indicates that the integration works like it is supposed to.
Connection to the service is successful.
Raises exceptions if something goes wrong.
:type AzureNSGClient: ``Client``
:param Client: client to use
:return: 'ok' if test passed.
:rtype: ``str``
"""
# This should validate all the inputs given in the integration configuration panel,
# either manually or by using an API that uses them.
if "Device" in client.connection_type:
raise DemistoException("Please enable the integration and run `!azure-nsg-auth-start`"
"and `!azure-nsg-auth-complete` to log in."
"You can validate the connection by running `!azure-nsg-auth-test`\n"
"For more details press the (?) button.")

else:
raise Exception("When using user auth flow configuration, "
"Please enable the integration and run the !azure-nsg-auth-test command in order to test it")


''' MAIN FUNCTION '''


Expand All @@ -354,8 +387,13 @@ def main() -> None:
resource_group_name=params.get('resource_group_name', ''),
verify=not params.get('insecure', False),
proxy=params.get('proxy', False),
connection_type=params.get('auth_type', 'Device Code'),
azure_ad_endpoint=params.get('azure_ad_endpoint',
'https://login.microsoftonline.com') or 'https://login.microsoftonline.com'
'https://login.microsoftonline.com') or 'https://login.microsoftonline.com',
tenant_id=params.get('tenant_id'),
enc_key=params.get('credentials', {}).get('password', ''),
auth_code=(params.get('auth_code', {})).get('password'),
redirect_uri=params.get('redirect_uri')
)
commands = {
'azure-nsg-security-groups-list': list_groups_command,
Expand All @@ -369,8 +407,7 @@ def main() -> None:
'azure-nsg-auth-reset': reset_auth,
}
if command == 'test-module':
return_error("Please run `!azure-nsg-auth-start` and `!azure-nsg-auth-complete` to log in."
" For more details press the (?) button.")
return_results(test_module(client))

if command == 'azure-nsg-auth-test':
return_results(test_connection(client, params))
Expand All @@ -383,8 +420,6 @@ def main() -> None:
return_error(f'Failed to execute {demisto.command()} command.\nError:\n{str(e)}')


from MicrosoftApiModule import * # noqa: E402

''' ENTRY POINT '''

if __name__ in ('__main__', '__builtin__', 'builtins'):
Expand Down
Expand Up @@ -39,6 +39,43 @@ configuration:
name: proxy
required: false
type: 8
- name: auth_type
display: Authentication Type
required: true
defaultvalue: Device Code
type: 15
additionalinfo: Type of authentication - could be Authorization Code flow (recommended) or Device Code flow.
options:
- Authorization Code
- Device Code
- name: tenant_id
display: Tenant ID (for user-auth mode)
required: false
defaultvalue:
type: 0
additionalinfo: ""
- name: credentials
display: Client Secret (for user-auth mode)
required: false
defaultvalue:
type: 9
additionalinfo: ""
displaypassword: Client Secret (for user-auth mode)
hiddenusername: true
- name: redirect_uri
display: Application redirect URI (for user-auth mode)
required: false
defaultvalue:
type: 0
additionalinfo: ""
- name: auth_code
display: Authorization code
required: false
defaultvalue:
type: 9
additionalinfo: For user-auth mode - received from the authorization step. See Detailed Instructions (?) section.
displaypassword: Authorization code
hiddenusername: true
description: Azure network security groups are used to filter network traffic to and
from Azure resources in an Azure virtual network.
display: Azure Network Security Groups
Expand Down Expand Up @@ -215,7 +252,7 @@ script:
- default: false
description: The source IP address range from which incoming traffic will be
allowed or denied by this rule. Possible values are "Any", an IP address range,
an application security group, or a default tag.
an application security group, or a default tag. Default is "Any".
isArray: false
name: source
required: false
Expand All @@ -224,7 +261,7 @@ script:
description: The priority by which the rules will be processed. The lower the
number, the higher the priority. We recommend leaving gaps between rules -
100, 200, 300, etc. - so that it is easier to add new rules without having
to edit existing rules.
to edit existing rules. Default is "4096".
isArray: false
name: priority
required: false
Expand All @@ -233,7 +270,7 @@ script:
description: The source ports from which traffic will be allowed or denied by
this rule. Provide a single port, such as 80; a port range, such as 1024-65535;
or a comma-separated list of single ports and/or port ranges, such as 80,1024-65535.
Use an asterisk (*) to allow traffic on any port.
Use an asterisk (*) to allow traffic on any port. Default is "*".
isArray: false
name: source_ports
required: false
Expand Down Expand Up @@ -365,7 +402,7 @@ script:
- default: false
description: The source IP address range from which incoming traffic will be
allowed or denied by this rule. Possible values are "Any", an IP address range,
an application security group, or a default tag.
an application security group, or a default tag. Default is "Any".
isArray: false
name: source
required: false
Expand All @@ -374,7 +411,7 @@ script:
description: The priority by which the rules will be processed. The lower the
number, the higher the priority. We recommend leaving gaps between rules -
100, 200, 300, etc. - so that it is easier to add new rules without having
to edit existing rules.
to edit existing rules. Default is "4096".
isArray: false
name: priority
required: false
Expand All @@ -383,7 +420,7 @@ script:
description: The source ports from which traffic will be allowed or denied by
this rule. Provide a single port, such as 80; a port range, such as 1024-65535;
or a comma-separated list of single ports and/or port ranges, such as 80,1024-65535.
Use an asterisk (*) to allow traffic on any port.
Use an asterisk (*) to allow traffic on any port. Default is "*".
isArray: false
name: source_ports
required: false
Expand Down
@@ -1,4 +1,22 @@
In both options below, the [device authorization grant flow](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-device-code) is used.
In order to connect to the Azure Network Security Groups use one of the following methods:

1. *Authorization Code Flow* (Recommended).
2. *Device Code Flow*.

### Authentication Using the Authorization Code Flow (recommended)

1. To use a self-configured Azure application, you need to add a new Azure App Registration in the Azure Portal. To add the registration, refer to the following [Microsoft article](https://docs.microsoft.com/en-us/microsoft-365/security/defender/api-create-app-web?view=o365-worldwide#create-an-app) steps 1-8.
2. In the **Authentication Type** field, select the **Authorization Code** option.
3. In the **Application ID** field, enter your Client/Application ID.
4. In the **Client Secret** field, enter your Client Secret.
5. In the **Tenant ID** field, enter your Tenant ID .
6. In the **Application redirect URI** field, enter your Application redirect URI.
7. In the **Authorization code** field, enter your Authorization code.
8. Save the instance.

### Authentication Using the Device Code Flow

Use the [device authorization grant flow](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-device-code).

In order to connect to the Azure Network Security Group using either Cortex XSOAR Azure App or the Self-Deployed Azure App:
1. Fill in the required parameters.
Expand Down
Expand Up @@ -11,7 +11,8 @@ def mock_client(mocker, http_request_result=None):
subscription_id='subscriptionID',
resource_group_name='resourceGroupName',
verify=False,
proxy=False
proxy=False,
connection_type='Device Code'
)
if http_request_result:
mocker.patch.object(client, 'http_request', return_value=http_request_result)
Expand Down

0 comments on commit 2490a88

Please sign in to comment.