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

Added Azure Container Registry (ACR) Support #1688

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<!-- ACR partial -->
<script id="services.acr.subscriptions.id.registries.partial" type="text/x-handlebars-template">
<div id="resource-name" class="list-group-item active">
<h4 class="list-group-item-heading">{{name}}</h4>
</div>
<div class="list-group-item">
<h4 class="list-group-item-heading">Information</h4>
<div class="list-group-item-text item-margin">ID: <span id="acr.subscriptions.{{@../key}}.registries.{{@key}}.id"><samp>{{ id }}</samp></span></div>
<div class="list-group-item-text item-margin">Location: <span id="acr.subscriptions.{{@../key}}.registries.{{@key}}.location"><samp>{{value_or_none location}}</samp></span></div>
<div class="list-group-item-text item-margin">Public Access: <span id="acr.subscriptions.{{@../key}}.registries.{{@key}}.public_network_access">{{ value_or_none public_network_access }}</span></div>
<div class="list-group-item-text item-margin">Admin Access Enabled: <span id="acr.subscriptions.{{@../key}}.registries.{{@key}}.admin_user_enabled">{{ convert_bool_to_enabled admin_user_enabled }}</span></div>
<div class="list-group-item-text item-margin">Tags:
{{#each tags}}
<div
style="border-radius: 5px; -webkit-border-radius: 5px; float: center; background-color: #c2c2d6; padding: 0.1px; text-align: center; display: inline-flex;">
<samp>{{value_or_none this}}</samp>
</div>&nbsp;&nbsp;
{{else}}
<div style="display: inline-flex;"><samp>None</samp></div>
{{/each}}
</div>
<div class="list-group-item-text item-margin">Resource group: <span id="acr.subscriptions.{{@../key}}.registries.{{@key}}.resource_group_name"><samp>{{value_or_none resource_group_name}}</samp></span></div>
</div>
</script>

<script>
Handlebars.registerPartial("services.acr.subscriptions.id.registries", $("#services\\.acr\\.subscriptions\\.id\\.registries\\.partial").html());
</script>

<!-- Single Key Vault template -->
<script id="single_acr_registries-template" type="text/x-handlebars-template">
{{> modal-template template='services.acr.registries' }}
</script>
<script>
var single_acr_registries_template = Handlebars.compile($("#single_acr_registries-template").html());
</script>
1 change: 1 addition & 0 deletions ScoutSuite/output/data/inc-scoutsuite/scoutsuite.js
Original file line number Diff line number Diff line change
Expand Up @@ -1233,6 +1233,7 @@ function makeTitle(title) {
const uppercaseTitles = [
'acm', 'aks', 'ec2', 'ecr', 'ecs', 'efs', 'eks', 'gke', 'iam', 'kms', 'rbac',
'rds', 'sns', 'ses', 'sqs', 'vpc', 'elb', 'elbv2', 'emr', 'dns', 'oss', 'ram',
'acr'
]

const formattedTitles = {
Expand Down
28 changes: 28 additions & 0 deletions ScoutSuite/providers/azure/facade/acr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from azure.mgmt.containerregistry import ContainerRegistryManagementClient

from ScoutSuite.core.console import print_exception
from ScoutSuite.providers.utils import run_concurrently
from ScoutSuite.utils import get_user_agent


class ACRFacade:

def __init__(self, credentials):
self.credentials = credentials

def get_client(self, subscription_id: str):
client = ContainerRegistryManagementClient(self.credentials.get_credentials(),
subscription_id=subscription_id, user_agent=get_user_agent())
return client

async def get_registries(self, subscription_id: str):
try:
client = self.get_client(subscription_id)
registries = await run_concurrently(
lambda: list(client.registries.list())
)
except Exception as e:
print_exception(f'Failed to retrieve container registries: {e}')
return []
else:
return registries
2 changes: 2 additions & 0 deletions ScoutSuite/providers/azure/facade/base.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from ScoutSuite.providers.azure.authentication_strategy import AzureCredentials
from ScoutSuite.providers.azure.facade.aad import AADFacade
from ScoutSuite.providers.azure.facade.acr import ACRFacade
from ScoutSuite.providers.azure.facade.rbac import RBACFacade
from ScoutSuite.providers.azure.facade.keyvault import KeyVaultFacade
from ScoutSuite.providers.azure.facade.network import NetworkFacade
Expand Down Expand Up @@ -48,6 +49,7 @@ def __init__(self,
self.all_subscriptions = all_subscriptions

self.aad = AADFacade(credentials)
self.acr = ACRFacade(credentials)
self.rbac = RBACFacade(credentials)
self.keyvault = KeyVaultFacade(credentials)
self.virtualmachines = VirtualMachineFacade(credentials)
Expand Down
10 changes: 10 additions & 0 deletions ScoutSuite/providers/azure/metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@
}
}
},
"container": {
"acr": {
"resources": {
"registries": {
"cols": 2,
"path": "services.acrs.subscriptions.id.registries"
}
}
}
},
"database": {
"sqldatabase": {
"resources": {
Expand Down
9 changes: 9 additions & 0 deletions ScoutSuite/providers/azure/resources/acr/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from ScoutSuite.providers.azure.resources.subscriptions import Subscriptions

from .registries import Registries


class ACRRegistries(Subscriptions):
_children = [
(Registries, 'registries')
]
75 changes: 75 additions & 0 deletions ScoutSuite/providers/azure/resources/acr/registries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
from ScoutSuite.providers.azure.facade.base import AzureFacade
from ScoutSuite.providers.azure.resources.base import AzureResources
from ScoutSuite.providers.utils import get_non_provider_id


class Registries(AzureResources):

def __init__(self, facade: AzureFacade, subscription_id: str):
super().__init__(facade)
self.subscription_id = subscription_id

async def fetch_all(self):
for raw_registry in await self.facade.acr.get_registries(self.subscription_id):
id, registry = self._parse_registry(raw_registry)
self[id] = registry

def _parse_registry(self, raw_registry):

registry = {}
registry['id'] = get_non_provider_id(raw_registry.id)
registry['name'] = raw_registry.name
registry['type'] = raw_registry.type
registry['location'] = raw_registry.location
if raw_registry.tags is not None:
registry['tags'] = ["{}:{}".format(key, value) for key, value in raw_registry.tags.items()]
else:
registry['tags'] = []

registry['sku'] = {}
registry['sku']['name'] = raw_registry.sku.name
registry['sku']['tier'] = raw_registry.sku.tier

registry['identity'] = raw_registry.identity
registry['login_server'] = raw_registry.login_server
registry['provisioning_state'] = raw_registry.provisioning_state
registry['status'] = raw_registry.status
registry['admin_user_enabled'] = bool(raw_registry.admin_user_enabled)
registry['network_rule_set'] = raw_registry.network_rule_set

registry['policies'] = {
'azureAD_authentication_policy': {},
'soft_delete_policy': {},
'quarantine_policy': {},
'trust_policy': {},
'retention_policy': {},
'export_policy': {}
}

registry['policies']['azureAD_suthentication_policy'] = raw_registry.policies.additional_properties['azureADAuthenticationAsArmPolicy']

registry['policies']['soft_delete_policy']['retention_days'] = raw_registry.policies.additional_properties['softDeletePolicy']['retentionDays']
registry['policies']['soft_delete_policy']['status'] = raw_registry.policies.additional_properties['softDeletePolicy']['status']

registry['policies']['quarantine_policy']['status'] = raw_registry.policies.quarantine_policy.status

registry['policies']['trust_policy']['status'] = raw_registry.policies.trust_policy.status
registry['policies']['trust_policy']['type'] = raw_registry.policies.trust_policy.type

registry['policies']['retention_policy']['status'] = raw_registry.policies.retention_policy.status
registry['policies']['retention_policy']['type'] = raw_registry.policies.retention_policy.days

registry['policies']['export_policy']['status'] = raw_registry.policies.export_policy.status

registry['encryption'] = {}
registry['encryption']['status'] = raw_registry.encryption.status
registry['encryption']['key_vault_properties'] = raw_registry.encryption.key_vault_properties

registry['data_endpoint_enabled'] = bool(raw_registry.data_endpoint_enabled)
registry['data_endpoint_host_names'] = raw_registry.data_endpoint_host_names
registry['private_endpoint_connections'] = raw_registry.private_endpoint_connections
registry['public_network_access'] = raw_registry.public_network_access
registry['network_rule_bypass_options'] = raw_registry.network_rule_bypass_options
registry['zone_redundancy'] = raw_registry.zone_redundancy

return registry['id'], registry
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"description": "Container Registry admin user Enabled",
"rationale": "",
"remediation": "",
"compliance": [
],
"references": [
],
"dashboard_name": "Registries",
"path": "containerregistry.subscriptions.id.registries.id",
"conditions": [
"and",
[
"containerregistry.subscriptions.id.registries.id.admin_user_enabled",
"notEqual",
"False"
]
],
"id_suffix": "admin_user_enabled"
}
21 changes: 21 additions & 0 deletions ScoutSuite/providers/azure/rules/findings/acr-public-access.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"description": "Container Registry public access Enabled",
"rationale": "",
"remediation": "",
"compliance": [
],
"references": [
"https://rnd-confluence.veeam.local/display/AP/AppSec+Cloud+Infrastructure+Security+Requirements"
],
"dashboard_name": "Registries",
"path": "containerregistry.subscriptions.id.registries.id",
"conditions": [
"and",
[
"containerregistry.subscriptions.id.registries.id.public_network_access",
"equal",
"Enabled"
]
],
"id_suffix": "public_access_enabled"
}
2 changes: 2 additions & 0 deletions ScoutSuite/providers/azure/services.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from ScoutSuite.providers.azure.authentication_strategy import AzureCredentials
from ScoutSuite.providers.azure.facade.base import AzureFacade
from ScoutSuite.providers.azure.resources.aad.base import AAD
from ScoutSuite.providers.azure.resources.acr.base import ACRRegistries
from ScoutSuite.providers.azure.resources.rbac.base import RBAC
from ScoutSuite.providers.azure.resources.keyvault.base import KeyVaults
from ScoutSuite.providers.azure.resources.network.base import Networks
Expand Down Expand Up @@ -44,6 +45,7 @@ def __init__(self,
programmatic_execution)

self.aad = AAD(facade)
self.acr = ACRRegistries(facade)
self.rbac = RBAC(facade)
self.securitycenter = SecurityCenter(facade)
self.sqldatabase = Servers(facade)
Expand Down
1 change: 1 addition & 0 deletions ScoutSuite/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
'ssm': 'Systems Manager',
# Azure
'aad': 'Azure Active Directory',
'registry': 'ACR Registry',
'storageaccounts': 'Storage Accounts',
'sqldatabase': 'SQL Database',
'securitycenter': 'Security Center',
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ azure-identity==1.5.0

## for resources

azure-mgmt-containerregistry==10.3.0
azure-mgmt-resource==15.0.0
azure-mgmt-storage==17.0.0
azure-mgmt-monitor==2.0.0
Expand Down