Skip to content

Azure Defender EASM Public Preview #28450

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

Merged
merged 29 commits into from
Feb 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
d71fd5d
azure-defender-easm client initial commit
nathanfalke Jan 23, 2023
5f4e5e2
added tests
nathanfalke Jan 23, 2023
5f1858d
added samples
nathanfalke Jan 23, 2023
be7a6ba
added swagger readme
nathanfalke Jan 31, 2023
c8cf575
Merge branch 'Azure:main' into main
nathanfalke Feb 1, 2023
4774229
updated tests to use test-proxy
nathanfalke Feb 1, 2023
893be52
updated swagger readme name/output folder
nathanfalke Feb 2, 2023
2f0fc81
Out-of-repo recordings
mccoyp Feb 2, 2023
5b03dd0
Merge pull request #1 from mccoyp/easm-recordings
nathanfalke Feb 2, 2023
b67b0ca
updated changelog to current year
nathanfalke Feb 6, 2023
22d70ac
updated sdk to reflect most recent swagger json
nathanfalke Feb 8, 2023
10fc169
disco_groups -> discovery_groups
nathanfalke Feb 13, 2023
2fe705b
remove old language
nathanfalke Feb 13, 2023
79ed5a2
updated samples to use metadata and os environment variables
nathanfalke Feb 13, 2023
9342845
added table of contents to readme
nathanfalke Feb 13, 2023
f2651a0
added test proxy to ci
nathanfalke Feb 16, 2023
40b9ea5
added easm to cspell
nathanfalke Feb 16, 2023
a0e6474
updated tests to use most recent sdk version
nathanfalke Feb 16, 2023
6f1f3fc
updated requirements to match frozen
nathanfalke Feb 17, 2023
7c13c3f
updated asset tag
nathanfalke Feb 17, 2023
2a8289e
moved requirements changes to overrides
nathanfalke Feb 17, 2023
3879161
updated package name in ci
nathanfalke Feb 17, 2023
aa761e2
split shared requirements into separate lines
nathanfalke Feb 17, 2023
80b2492
added pip link to ignore-links txt
nathanfalke Feb 21, 2023
a4baab8
added pylint ignore
nathanfalke Feb 21, 2023
2ece6bf
Merge branch 'main' into main
nathanfalke Feb 21, 2023
da877ea
updated pylint disable
nathanfalke Feb 21, 2023
a6cc9c1
updated readme links
nathanfalke Feb 21, 2023
f0cc162
added missing headers
nathanfalke Feb 21, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .vscode/cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"sdk/eventhub/azure-eventhub-checkpointstoretable/**",
"sdk/eventhub/azure-eventhub-checkpointstoreblob-aio/**",
"sdk/eventhub/azure-eventhub/**",
"sdk/easm/azure-defender-easm/azure/defender/easm/**",
"sdk/graphrbac/azure-graphrbac/**",
"sdk/formrecognizer/azure-ai-formrecognizer/samples/sample_forms/**",
"sdk/formrecognizer/azure-ai-formrecognizer/tests/sample_forms/**",
Expand Down Expand Up @@ -170,6 +171,7 @@
"dtlksd",
"DWORD",
"eastus",
"Easm",
"euap",
"eckey",
"ekus",
Expand Down
1 change: 1 addition & 0 deletions eng/ignore-links.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ https://pypi.org/project/azure-messaging-webpubsubservice/
https://github.com/Azure/azure-rest-api-specs-pr
https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/communication/azure-communication-rooms/samples
http://localhost:8000/samples/pyodide_integration
https://pypi.org/project/azure-defender-easm/
https://github.com/Azure/azure-sdk-tools/blob/main/eng/common/testproxy/transition-scripts/generate-assets-json.ps1
5 changes: 5 additions & 0 deletions sdk/easm/azure-defender-easm/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Release History

## 1.0.0b1 (2023-02-01)

- Initial Release
21 changes: 21 additions & 0 deletions sdk/easm/azure-defender-easm/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Copyright (c) Microsoft Corporation.

MIT License

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
7 changes: 7 additions & 0 deletions sdk/easm/azure-defender-easm/MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
include *.md
include LICENSE
include azure/defender/easm/py.typed
recursive-include tests *.py
recursive-include samples *.py *.md
include azure/__init__.py
include azure/defender/__init__.py
157 changes: 157 additions & 0 deletions sdk/easm/azure-defender-easm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@

# Azure EASM Data Plane client library for Python
*Microsoft Defender External Attack Surface Management (Defender EASM)* continuously discovers and maps your digital attack surface to provide an external view of your online infrastructure. This visibility enables security and IT teams to identify unknowns, prioritize risk, eliminate threats, and extend vulnerability and exposure control beyond the firewall. Defender EASM leverages Microsoft’s crawling technology to discover assets that are related to your known online infrastructure, and actively scans these assets to discover new connections over time. Attack Surface Insights are generated by leveraging vulnerability and infrastructure data to showcase the key areas of concern for your organization.

[Source Code][source_code] | [Package (pypi)][pypi] | [Api Reference Documentation][api_reference] | [Product Documentation][product_documentation]

## Getting started
### Installing the package

#### pip
```bash
python -m pip install azure-defender-easm
```

#### from source
```bash
python setup.py intall
```

#### Prerequisites

- Python 3.7 or later is required to use this package.
- You need an [Azure subscription][azure_sub] to use this package.
- An existing EASM Data Plane Client instance.

#### Create with an Azure Active Directory Credential
To use an [Azure Active Directory (AAD) token credential][authenticate_with_token],
provide an instance of the desired credential type obtained from the
[azure-identity][azure_identity_credentials] library.

To authenticate with AAD, you must first [pip][pip] install [`azure-identity`][azure_identity_pip]

After setup, you can choose which type of [credential][azure_identity_credentials] from azure.identity to use.
As an example, [DefaultAzureCredential][default_azure_credential] can be used to authenticate the client:

Set the values of the client ID, tenant ID, and client secret of the AAD application as environment variables:
`AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, `AZURE_CLIENT_SECRET`

Use the returned token credential to authenticate the client:

```python
from azure.defender.easm import EasmClient
from azure.identity import DefaultAzureCredential

sub_id = '<your subscription ID here>'
workspace_name = '<your workspace name here>'
resource_group = '<your resource group here>'
region = '<your region here>'

endpoint = f'{region}.easm.defender.microsoft.com'

client = EasmClient(endpoint, resource_group, sub_id, workspace_name, credential=DefaultAzureCredential())
```

## Key concepts
Basic understanding these terms will help to get started with EASM client library.

### [Assets][assets_documentation]
Defender EASM includes the discovery of the following kinds of assets:
- Domains
- Hosts
- Pages
- IP Blocks
- IP Addresses
- Autonomous System Numbers (ASNs)
- SSL Certificates
- WHOIS Contacts

These asset types comprise your attack surface inventory in Defender EASM. This solution discovers externally facing assets that are exposed to the open internet outside of traditional firewall protection; they need to be monitored and maintained to minimize risk and improve an organization’s security posture. Microsoft Defender External Attack Surface Management (Defender EASM) actively discovers and monitors these assets, then surfacing key insights that help customers efficiently address any vulnerabilities in their organization.

### [Discovery][discovery_documentation]
Microsoft Defender External Attack Surface Management (Defender EASM) relies on our proprietary discovery technology to continuously define your organization’s unique Internet-exposed attack surface. Discovery scans known assets owned by your organization to uncover previously unknown and unmonitored properties. Discovered assets are indexed in a customer’s inventory, providing a dynamic system of record of web applications, third party dependencies, and web infrastructure under the organization’s management through a single pane of glass.

#### [Discovery Groups][discovery_groups_documentation]
Custom discoveries are organized into Discovery Groups. They are independent seed clusters that comprise a single discovery run and operate on their own recurrence schedules. Users can elect to organize their Discovery Groups to delineate assets in whatever way best benefits their company and workflows. Common options include organizing by responsible team/business unit, brands or subsidiaries.

## Examples
After authenticating as shown in the "Create with an Azure Active Directory Credential" section, you can get started building your inventory like this:

### Create a discovery group
```python
from azure.defender.easm import EasmClient
from azure.identity import DefaultAzureCredential

sub_id = '<your subscription ID here>'
workspace_name = '<your workspace name here>'
resource_group = '<your resource group here>'
region = '<your region here>'

endpoint = f'{region}.easm.defender.microsoft.com'

client = EasmClient(endpoint, resource_group, sub_id, workspace_name, credential=DefaultAzureCredential())

client.discovery_groups.put("example group", {
'seeds': [
{'kind': 'host', 'name': 'example.org'}
]
})
client.discovery_groups.run("example group")
```

### View assets
```python
from azure.defender.easm import EasmClient
from azure.identity import DefaultAzureCredential

sub_id = '<your subscription ID here>'
workspace_name = '<your workspace name here>'
resource_group = '<your resource group here>'
region = '<your region here>'

endpoint = f'{region}.easm.defender.microsoft.com'

client = EasmClient(endpoint, resource_group, sub_id, workspace_name, credential=DefaultAzureCredential())

for asset in client.assets.list():
print(f'{asset.kind}: {asset.name}')
```
### More examples
More examples can be viewed in the [samples directory][samples] of this repository

### Troubleshooting

### Next steps

## Contributing
This project welcomes contributions and suggestions. Most contributions require
you to agree to a Contributor License Agreement (CLA) declaring that you have
the right to, and actually do, grant us the rights to use your contribution.
For details, visit https://cla.microsoft.com.

When you submit a pull request, a CLA-bot will automatically determine whether
you need to provide a CLA and decorate the PR appropriately (e.g., label,
comment). Simply follow the instructions provided by the bot. You will only
need to do this once across all repos using our CLA.

This project has adopted the
[Microsoft Open Source Code of Conduct][code_of_conduct]. For more information,
see the Code of Conduct FAQ or contact [email protected] with any
additional questions or comments.

<!-- LINKS -->
[code_of_conduct]: https://opensource.microsoft.com/codeofconduct/
[authenticate_with_token]: https://docs.microsoft.com/azure/cognitive-services/authentication?tabs=powershell#authenticate-with-an-authentication-token
[azure_identity_credentials]: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/identity/azure-identity#credentials
[azure_identity_pip]: https://pypi.org/project/azure-identity/
[default_azure_credential]: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/identity/azure-identity#defaultazurecredential
[pip]: https://pypi.org/project/pip/
[azure_sub]: https://azure.microsoft.com/free/
[samples]: https://github.com/nathanfalke/azure-sdk-for-python/tree/main/sdk/easm/azure-defender-easm/samples
[assets_documentation]: https://learn.microsoft.com/azure/external-attack-surface-management/understanding-inventory-assets
[discovery_documentation]: https://learn.microsoft.com/azure/external-attack-surface-management/what-is-discovery
[discovery_groups_documentation]: https://learn.microsoft.com/azure/external-attack-surface-management/using-and-managing-discovery#discovery-groups
[source_code]: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/easm/azure-defender-easm/
[pypi]: https://pypi.org/project/azure-defender-easm/
[api_reference]: https://review.learn.microsoft.com/rest/api/defenderforeasm/?branch=easm
[product_documentation]: https://learn.microsoft.com/azure/external-attack-surface-management/
6 changes: 6 additions & 0 deletions sdk/easm/azure-defender-easm/assets.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"AssetsRepo": "Azure/azure-sdk-assets",
"AssetsRepoPrefixPath": "python",
"TagPrefix": "python/easm/azure-defender-easm",
"Tag": "python/easm/azure-defender-easm_1ce88f356c"
}
1 change: 1 addition & 0 deletions sdk/easm/azure-defender-easm/azure/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__path__ = __import__("pkgutil").extend_path(__path__, __name__) # type: ignore
1 change: 1 addition & 0 deletions sdk/easm/azure-defender-easm/azure/defender/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__path__ = __import__("pkgutil").extend_path(__path__, __name__) # type: ignore
26 changes: 26 additions & 0 deletions sdk/easm/azure-defender-easm/azure/defender/easm/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# coding=utf-8
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# Code generated by Microsoft (R) AutoRest Code Generator.
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
# --------------------------------------------------------------------------

from ._client import EasmClient
from ._version import VERSION

__version__ = VERSION

try:
from ._patch import __all__ as _patch_all
from ._patch import * # pylint: disable=unused-wildcard-import
except ImportError:
_patch_all = []
from ._patch import patch_sdk as _patch_sdk

__all__ = [
"EasmClient",
]
__all__.extend([p for p in _patch_all if p not in __all__])

_patch_sdk()
134 changes: 134 additions & 0 deletions sdk/easm/azure-defender-easm/azure/defender/easm/_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# coding=utf-8
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# Code generated by Microsoft (R) AutoRest Code Generator.
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
# --------------------------------------------------------------------------

from copy import deepcopy
from typing import Any, TYPE_CHECKING

from azure.core import PipelineClient
from azure.core.rest import HttpRequest, HttpResponse

from ._configuration import EasmClientConfiguration
from ._serialization import Deserializer, Serializer
from .operations import (
AssetsOperations,
DiscoveryGroupsOperations,
DiscoveryTemplatesOperations,
ReportsOperations,
SavedFiltersOperations,
TasksOperations,
)

if TYPE_CHECKING:
# pylint: disable=unused-import,ungrouped-imports
from azure.core.credentials import TokenCredential


class EasmClient: # pylint: disable=client-accepts-api-version-keyword
"""Defender EASM discovers and maps your digital attack surface to provide an "outside-in"
perspective using probes to discover assets. The assets are provided with detailed metadata
associated, including vulnerabilities, configurations and web components, allowing customers to
view and prioritize external risk. The EASM REST API enables you to develop clients that
integrate with your application.

:ivar assets: AssetsOperations operations
:vartype assets: azure.defender.easm.operations.AssetsOperations
:ivar discovery_groups: DiscoveryGroupsOperations operations
:vartype discovery_groups: azure.defender.easm.operations.DiscoveryGroupsOperations
:ivar discovery_templates: DiscoveryTemplatesOperations operations
:vartype discovery_templates: azure.defender.easm.operations.DiscoveryTemplatesOperations
:ivar reports: ReportsOperations operations
:vartype reports: azure.defender.easm.operations.ReportsOperations
:ivar saved_filters: SavedFiltersOperations operations
:vartype saved_filters: azure.defender.easm.operations.SavedFiltersOperations
:ivar tasks: TasksOperations operations
:vartype tasks: azure.defender.easm.operations.TasksOperations
:param endpoint: The endpoint hosting the requested resource. For example,
{region}.easm.defender.microsoft.com. Required.
:type endpoint: str
:param resource_group_name: The name of the Resource Group. Required.
:type resource_group_name: str
:param subscription_id: The ID of the target subscription. Required.
:type subscription_id: str
:param workspace_name: The name of the Workspace. Required.
:type workspace_name: str
:param credential: Credential needed for the client to connect to Azure. Required.
:type credential: ~azure.core.credentials.TokenCredential
:keyword api_version: Api Version. Default value is "2022-11-01-preview". Note that overriding
this default value may result in unsupported behavior.
:paramtype api_version: str
"""

def __init__(
self,
endpoint: str,
resource_group_name: str,
subscription_id: str,
workspace_name: str,
credential: "TokenCredential",
**kwargs: Any
) -> None:
_endpoint = "https://{endpoint}"
self._config = EasmClientConfiguration(
endpoint=endpoint,
resource_group_name=resource_group_name,
subscription_id=subscription_id,
workspace_name=workspace_name,
credential=credential,
**kwargs
)
self._client = PipelineClient(base_url=_endpoint, config=self._config, **kwargs)

self._serialize = Serializer()
self._deserialize = Deserializer()
self._serialize.client_side_validation = False
self.assets = AssetsOperations(self._client, self._config, self._serialize, self._deserialize)
self.discovery_groups = DiscoveryGroupsOperations(
self._client, self._config, self._serialize, self._deserialize
)
self.discovery_templates = DiscoveryTemplatesOperations(
self._client, self._config, self._serialize, self._deserialize
)
self.reports = ReportsOperations(self._client, self._config, self._serialize, self._deserialize)
self.saved_filters = SavedFiltersOperations(self._client, self._config, self._serialize, self._deserialize)
self.tasks = TasksOperations(self._client, self._config, self._serialize, self._deserialize)

def send_request(self, request: HttpRequest, **kwargs: Any) -> HttpResponse:
"""Runs the network request through the client's chained policies.

>>> from azure.core.rest import HttpRequest
>>> request = HttpRequest("GET", "https://www.example.org/")
<HttpRequest [GET], url: 'https://www.example.org/'>
>>> response = client.send_request(request)
<HttpResponse: 200 OK>

For more information on this code flow, see https://aka.ms/azsdk/dpcodegen/python/send_request

:param request: The network request you want to make. Required.
:type request: ~azure.core.rest.HttpRequest
:keyword bool stream: Whether the response payload will be streamed. Defaults to False.
:return: The response of your network call. Does not do error handling on your response.
:rtype: ~azure.core.rest.HttpResponse
"""

request_copy = deepcopy(request)
path_format_arguments = {
"endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str"),
}

request_copy.url = self._client.format_url(request_copy.url, **path_format_arguments)
return self._client.send_request(request_copy, **kwargs)

def close(self) -> None:
self._client.close()

def __enter__(self) -> "EasmClient":
self._client.__enter__()
return self

def __exit__(self, *exc_details) -> None:
self._client.__exit__(*exc_details)
Loading