Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Azure network security groups add user auth #20779

Merged
merged 9 commits into from Aug 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -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