internal/resources/providers/azurelib/inventory/storage_provider.go (543 lines of code) (raw):

// Licensed to Elasticsearch B.V. under one or more contributor // license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright // ownership. Elasticsearch B.V. licenses this file to you under // the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. package inventory import ( "context" "errors" "fmt" "strings" "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/monitor/armmonitor" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage" "github.com/samber/lo" "github.com/elastic/cloudbeat/internal/infra/clog" "github.com/elastic/cloudbeat/internal/resources/fetching/cycle" "github.com/elastic/cloudbeat/internal/resources/utils/maps" "github.com/elastic/cloudbeat/internal/resources/utils/pointers" ) type storageAccountAzureClientWrapper struct { AssetDiagnosticSettings func(ctx context.Context, subID string, options *armmonitor.DiagnosticSettingsClientListOptions) ([]armmonitor.DiagnosticSettingsClientListResponse, error) AssetBlobContainers func(ctx context.Context, subID string, clientOptions *arm.ClientOptions, resourceGroup, storageAccountName string, options *armstorage.BlobContainersClientListOptions) ([]armstorage.BlobContainersClientListResponse, error) AssetBlobServices func(ctx context.Context, subID string, clientOptions *arm.ClientOptions, resourceGroup, storageAccountName string, options *armstorage.BlobServicesClientListOptions) ([]armstorage.BlobServicesClientListResponse, error) AssetFileServices func(ctx context.Context, subID string, clientOptions *arm.ClientOptions, resourceGroup, storageAccountName string, options *armstorage.FileServicesClientListOptions) (armstorage.FileServicesClientListResponse, error) AssetFileShares func(ctx context.Context, subID string, clientOptions *arm.ClientOptions, resourceGroup, storageAccountName string, options *armstorage.FileSharesClientListOptions) ([]armstorage.FileSharesClientListResponse, error) AssetQueues func(ctx context.Context, subID string, clientOptions *arm.ClientOptions, resourceGroup, storageAccountName string, options *armstorage.QueueClientListOptions) ([]armstorage.QueueClientListResponse, error) AssetQueueServices func(ctx context.Context, subID string, clientOptions *arm.ClientOptions, resourceGroup, storageAccountName string, options *armstorage.QueueServicesClientListOptions) (armstorage.QueueServicesClientListResponse, error) AssetTables func(ctx context.Context, subID string, clientOptions *arm.ClientOptions, resourceGroup, storageAccountName string, options *armstorage.TableClientListOptions) ([]armstorage.TableClientListResponse, error) AssetTableServices func(ctx context.Context, subID string, clientOptions *arm.ClientOptions, resourceGroup, storageAccountName string, options *armstorage.TableServicesClientListOptions) (armstorage.TableServicesClientListResponse, error) AssetAccountStorage func(ctx context.Context, subID string, clientOptions *arm.ClientOptions) ([]armstorage.AccountsClientListResponse, error) } type StorageAccountProviderAPI interface { ListDiagnosticSettingsAssetTypes(ctx context.Context, cycleMetadata cycle.Metadata, subscriptionIDs []string) ([]AzureAsset, error) ListStorageAccountBlobContainers(ctx context.Context, storageAccounts []AzureAsset) ([]AzureAsset, error) ListStorageAccountBlobServices(ctx context.Context, storageAccounts []AzureAsset) ([]AzureAsset, error) ListStorageAccountFileServices(ctx context.Context, storageAccounts []AzureAsset) ([]AzureAsset, error) ListStorageAccountFileShares(ctx context.Context, storageAccounts []AzureAsset) ([]AzureAsset, error) ListStorageAccountQueues(ctx context.Context, storageAccounts []AzureAsset) ([]AzureAsset, error) ListStorageAccountQueueServices(ctx context.Context, storageAccounts []AzureAsset) ([]AzureAsset, error) ListStorageAccountsBlobDiagnosticSettings(ctx context.Context, storageAccounts []AzureAsset) ([]AzureAsset, error) ListStorageAccountsTableDiagnosticSettings(ctx context.Context, storageAccounts []AzureAsset) ([]AzureAsset, error) ListStorageAccountTables(ctx context.Context, storageAccounts []AzureAsset) ([]AzureAsset, error) ListStorageAccountTableServices(ctx context.Context, storageAccounts []AzureAsset) ([]AzureAsset, error) ListStorageAccountsQueueDiagnosticSettings(ctx context.Context, storageAccounts []AzureAsset) ([]AzureAsset, error) ListStorageAccounts(ctx context.Context, storageAccountsSubscriptionsIds []string) ([]AzureAsset, error) } type storageAccountProvider struct { client *storageAccountAzureClientWrapper log *clog.Logger diagnosticSettingsCache *cycle.Cache[[]AzureAsset] } func NewStorageAccountProvider(log *clog.Logger, diagnosticSettingsClient *armmonitor.DiagnosticSettingsClient, credentials azcore.TokenCredential) StorageAccountProviderAPI { // We wrap the client, so we can mock it in tests wrapper := &storageAccountAzureClientWrapper{ AssetDiagnosticSettings: func(ctx context.Context, resourceURI string, options *armmonitor.DiagnosticSettingsClientListOptions) ([]armmonitor.DiagnosticSettingsClientListResponse, error) { pager := diagnosticSettingsClient.NewListPager(resourceURI, options) return readPager(ctx, pager) }, AssetBlobContainers: func(ctx context.Context, subID string, clientOptions *arm.ClientOptions, resourceGroupName, storageAccountName string, options *armstorage.BlobContainersClientListOptions) ([]armstorage.BlobContainersClientListResponse, error) { cl, err := armstorage.NewBlobContainersClient(subID, credentials, clientOptions) if err != nil { return nil, err } return readPager(ctx, cl.NewListPager(resourceGroupName, storageAccountName, options)) }, AssetBlobServices: func(ctx context.Context, subID string, clientOptions *arm.ClientOptions, resourceGroupName, storageAccountName string, options *armstorage.BlobServicesClientListOptions) ([]armstorage.BlobServicesClientListResponse, error) { cl, err := armstorage.NewBlobServicesClient(subID, credentials, clientOptions) if err != nil { return nil, err } return readPager(ctx, cl.NewListPager(resourceGroupName, storageAccountName, options)) }, AssetFileServices: func(ctx context.Context, subID string, clientOptions *arm.ClientOptions, resourceGroupName, storageAccountName string, options *armstorage.FileServicesClientListOptions) (armstorage.FileServicesClientListResponse, error) { cl, err := armstorage.NewFileServicesClient(subID, credentials, clientOptions) if err != nil { return armstorage.FileServicesClientListResponse{}, err } return cl.List(ctx, resourceGroupName, storageAccountName, options) }, AssetFileShares: func(ctx context.Context, subID string, clientOptions *arm.ClientOptions, resourceGroupName, storageAccountName string, options *armstorage.FileSharesClientListOptions) ([]armstorage.FileSharesClientListResponse, error) { cl, err := armstorage.NewFileSharesClient(subID, credentials, clientOptions) if err != nil { return nil, err } return readPager(ctx, cl.NewListPager(resourceGroupName, storageAccountName, options)) }, AssetQueues: func(ctx context.Context, subID string, clientOptions *arm.ClientOptions, resourceGroupName, storageAccountName string, options *armstorage.QueueClientListOptions) ([]armstorage.QueueClientListResponse, error) { cl, err := armstorage.NewQueueClient(subID, credentials, clientOptions) if err != nil { return nil, err } return readPager(ctx, cl.NewListPager(resourceGroupName, storageAccountName, options)) }, AssetQueueServices: func(ctx context.Context, subID string, clientOptions *arm.ClientOptions, resourceGroupName, storageAccountName string, options *armstorage.QueueServicesClientListOptions) (armstorage.QueueServicesClientListResponse, error) { cl, err := armstorage.NewQueueServicesClient(subID, credentials, clientOptions) if err != nil { return armstorage.QueueServicesClientListResponse{}, err } return cl.List(ctx, resourceGroupName, storageAccountName, options) }, AssetTables: func(ctx context.Context, subID string, clientOptions *arm.ClientOptions, resourceGroupName, storageAccountName string, options *armstorage.TableClientListOptions) ([]armstorage.TableClientListResponse, error) { cl, err := armstorage.NewTableClient(subID, credentials, clientOptions) if err != nil { return nil, err } return readPager(ctx, cl.NewListPager(resourceGroupName, storageAccountName, options)) }, AssetTableServices: func(ctx context.Context, subID string, clientOptions *arm.ClientOptions, resourceGroupName, storageAccountName string, options *armstorage.TableServicesClientListOptions) (armstorage.TableServicesClientListResponse, error) { cl, err := armstorage.NewTableServicesClient(subID, credentials, clientOptions) if err != nil { return armstorage.TableServicesClientListResponse{}, err } return cl.List(ctx, resourceGroupName, storageAccountName, options) }, AssetAccountStorage: func(ctx context.Context, subID string, clientOptions *arm.ClientOptions) ([]armstorage.AccountsClientListResponse, error) { accountsClient, err := armstorage.NewAccountsClient(subID, credentials, clientOptions) if err != nil { return nil, err } return readPager(ctx, accountsClient.NewListPager(&armstorage.AccountsClientListOptions{})) }, } return &storageAccountProvider{ log: log, client: wrapper, diagnosticSettingsCache: cycle.NewCache[[]AzureAsset](log), } } func (p *storageAccountProvider) ListStorageAccounts(ctx context.Context, storageAccountsSubscriptionsIds []string) ([]AzureAsset, error) { var assets []AzureAsset for _, saID := range storageAccountsSubscriptionsIds { res, err := p.client.AssetAccountStorage(ctx, saID, nil) if err != nil { p.log.Errorf("error while fetching storage accounts for subscriptionId: %s, error: %v", saID, err) continue } storageAccountsAssets, err := transformStorageAccounts(res, saID) if err != nil { p.log.Errorf("error while transforming storage for subscriptionId: %s, error: %v", saID, err) continue } assets = append(assets, storageAccountsAssets...) } return assets, nil } func transformStorageAccounts(accountPages []armstorage.AccountsClientListResponse, storageAccountId string) ([]AzureAsset, error) { var errs error return lo.FlatMap(accountPages, func(response armstorage.AccountsClientListResponse, _ int) []AzureAsset { return lo.Map(response.Value, func(item *armstorage.Account, _ int) AzureAsset { properties, err := maps.AsMapStringAny(item.Properties) if err != nil { errs = errors.Join(errs, err) } // extracting resourceGroup from the ID: // /subscriptions/<id>/resourceGroups/<name>/providers/Microsoft.Storage/storageAccounts/<name2> var resourceGroup string idElements := strings.Split(pointers.Deref(item.ID), "/") if len(idElements) > 5 && idElements[3] == "resourceGroups" { resourceGroup = idElements[4] } var tenantId string if item.Identity != nil { tenantId = pointers.Deref(item.Identity.TenantID) } return AzureAsset{ Id: pointers.Deref(item.ID), Name: pointers.Deref(item.Name), Type: strings.ToLower(pointers.Deref(item.Type)), ResourceGroup: resourceGroup, TenantId: tenantId, SubscriptionId: storageAccountId, Properties: properties, Extension: map[string]any{ ExtensionStorageAccountID: pointers.Deref(item.ID), ExtensionStorageAccountName: pointers.Deref(item.Name), }, } }) }), errs } func (p *storageAccountProvider) ListStorageAccountBlobContainers(ctx context.Context, storageAccounts []AzureAsset) ([]AzureAsset, error) { var assets []AzureAsset for _, sa := range storageAccounts { responses, err := p.client.AssetBlobContainers(ctx, sa.SubscriptionId, nil, sa.ResourceGroup, sa.Name, nil) if err != nil { return nil, fmt.Errorf("error while fetching azure blob containers for storage accounts %s: %w", sa.Id, err) } blobContainers, err := transformBlobContainers(responses, sa) if err != nil { return nil, fmt.Errorf("error while transforming azure blob containers for storage accounts %s: %w", sa.Id, err) } assets = append(assets, blobContainers...) } return assets, nil } func (p *storageAccountProvider) ListStorageAccountBlobServices(ctx context.Context, storageAccounts []AzureAsset) ([]AzureAsset, error) { var assets []AzureAsset for _, sa := range storageAccounts { responses, err := p.client.AssetBlobServices(ctx, sa.SubscriptionId, nil, sa.ResourceGroup, sa.Name, nil) if err != nil { return nil, fmt.Errorf("error while fetching azure blob services for storage accounts %s: %w", sa.Id, err) } blobServices, err := transformBlobServices(responses, sa) if err != nil { return nil, fmt.Errorf("error while transforming azure blob services for storage accounts %s: %w", sa.Id, err) } assets = append(assets, blobServices...) } return assets, nil } func (p *storageAccountProvider) ListStorageAccountFileServices(ctx context.Context, storageAccounts []AzureAsset) ([]AzureAsset, error) { var assets []AzureAsset for _, sa := range storageAccounts { response, err := p.client.AssetFileServices(ctx, sa.SubscriptionId, nil, sa.ResourceGroup, sa.Name, nil) if err != nil { return nil, fmt.Errorf("error while fetching azure blob services for storage accounts %s: %w", sa.Id, err) } for _, item := range response.Value { properties, err := maps.AsMapStringAny(item.FileServiceProperties) if err != nil { p.log.Errorf("error while transforming azure queue services for storage accounts %s: %v", sa.Id, err) } assets = append(assets, AzureAsset{ Id: pointers.Deref(item.ID), Name: pointers.Deref(item.Name), Type: strings.ToLower(pointers.Deref(item.Type)), ResourceGroup: sa.ResourceGroup, SubscriptionId: sa.SubscriptionId, TenantId: sa.TenantId, Properties: properties, Extension: map[string]any{ ExtensionStorageAccountID: sa.Id, ExtensionStorageAccountName: sa.Name, }, }) } } return assets, nil } func (p *storageAccountProvider) ListStorageAccountFileShares(ctx context.Context, storageAccounts []AzureAsset) ([]AzureAsset, error) { var assets []AzureAsset for _, sa := range storageAccounts { responses, err := p.client.AssetFileShares(ctx, sa.SubscriptionId, nil, sa.ResourceGroup, sa.Name, nil) if err != nil { return nil, fmt.Errorf("error while fetching azure file share for storage accounts %s: %w", sa.Id, err) } fileShares, err := transformFileShares(responses, sa) if err != nil { p.log.Errorf("error while transforming azure file share for storage accounts %s: %v", sa.Id, err) } assets = append(assets, fileShares...) } return assets, nil } func (p *storageAccountProvider) ListStorageAccountQueues(ctx context.Context, storageAccounts []AzureAsset) ([]AzureAsset, error) { var assets []AzureAsset for _, sa := range storageAccounts { responses, err := p.client.AssetQueues(ctx, sa.SubscriptionId, nil, sa.ResourceGroup, sa.Name, nil) if err != nil { return nil, fmt.Errorf("error while fetching azure queues for storage accounts %s: %w", sa.Id, err) } queues, err := transformQueues(responses, sa) if err != nil { p.log.Errorf("error while transforming azure queues for storage accounts %s: %v", sa.Id, err) } assets = append(assets, queues...) } return assets, nil } func (p *storageAccountProvider) ListStorageAccountQueueServices(ctx context.Context, storageAccounts []AzureAsset) ([]AzureAsset, error) { var assets []AzureAsset for _, sa := range storageAccounts { response, err := p.client.AssetQueueServices(ctx, sa.SubscriptionId, nil, sa.ResourceGroup, sa.Name, nil) if err != nil { return nil, fmt.Errorf("error while fetching azure queue services for storage accounts %s: %w", sa.Id, err) } for _, item := range response.Value { properties, err := maps.AsMapStringAny(item.QueueServiceProperties) if err != nil { p.log.Errorf("error while transforming azure queue services for storage accounts %s: %v", sa.Id, err) } assets = append(assets, AzureAsset{ Id: pointers.Deref(item.ID), Name: pointers.Deref(item.Name), Type: strings.ToLower(pointers.Deref(item.Type)), ResourceGroup: sa.ResourceGroup, SubscriptionId: sa.SubscriptionId, TenantId: sa.TenantId, Properties: properties, Extension: map[string]any{ ExtensionStorageAccountID: sa.Id, ExtensionStorageAccountName: sa.Name, }, }) } } return assets, nil } func (p *storageAccountProvider) ListStorageAccountTables(ctx context.Context, storageAccounts []AzureAsset) ([]AzureAsset, error) { var assets []AzureAsset for _, sa := range storageAccounts { responses, err := p.client.AssetTables(ctx, sa.SubscriptionId, nil, sa.ResourceGroup, sa.Name, nil) if err != nil { return nil, fmt.Errorf("error while fetching azure table services for storage accounts %s: %w", sa.Id, err) } tables, err := transformTables(responses, sa) if err != nil { p.log.Errorf("error while transforming azure tables for storage accounts %s: %v", sa.Id, err) } assets = append(assets, tables...) } return assets, nil } func (p *storageAccountProvider) ListStorageAccountTableServices(ctx context.Context, storageAccounts []AzureAsset) ([]AzureAsset, error) { var assets []AzureAsset for _, sa := range storageAccounts { response, err := p.client.AssetTableServices(ctx, sa.SubscriptionId, nil, sa.ResourceGroup, sa.Name, nil) if err != nil { return nil, fmt.Errorf("error while fetching azure table services for storage accounts %s: %w", sa.Id, err) } for _, item := range response.Value { properties, err := maps.AsMapStringAny(item.TableServiceProperties) if err != nil { p.log.Errorf("error while transforming azure table services for storage accounts %s: %v", sa.Id, err) } assets = append(assets, AzureAsset{ Id: pointers.Deref(item.ID), Name: pointers.Deref(item.Name), Type: strings.ToLower(pointers.Deref(item.Type)), ResourceGroup: sa.ResourceGroup, SubscriptionId: sa.SubscriptionId, TenantId: sa.TenantId, Properties: properties, Extension: map[string]any{ ExtensionStorageAccountID: sa.Id, ExtensionStorageAccountName: sa.Name, }, }) } } return assets, nil } func transformBlobContainers(servicesPages []armstorage.BlobContainersClientListResponse, storageAccount AzureAsset) ([]AzureAsset, error) { var errs error return lo.FlatMap(servicesPages, func(response armstorage.BlobContainersClientListResponse, _ int) []AzureAsset { return lo.Map(response.Value, func(item *armstorage.ListContainerItem, _ int) AzureAsset { properties, err := maps.AsMapStringAny(item.Properties) if err != nil { errs = errors.Join(errs, err) } return AzureAsset{ Id: pointers.Deref(item.ID), Name: pointers.Deref(item.Name), Type: strings.ToLower(pointers.Deref(item.Type)), ResourceGroup: storageAccount.ResourceGroup, SubscriptionId: storageAccount.SubscriptionId, TenantId: storageAccount.TenantId, Properties: properties, Extension: map[string]any{ ExtensionStorageAccountID: storageAccount.Id, ExtensionStorageAccountName: storageAccount.Name, }, } }) }), errs } func transformBlobServices(servicesPages []armstorage.BlobServicesClientListResponse, storageAccount AzureAsset) ([]AzureAsset, error) { var errs error return lo.FlatMap(servicesPages, func(response armstorage.BlobServicesClientListResponse, _ int) []AzureAsset { return lo.Map(response.Value, func(item *armstorage.BlobServiceProperties, _ int) AzureAsset { properties, err := maps.AsMapStringAny(item.BlobServiceProperties) if err != nil { errs = errors.Join(errs, err) } return AzureAsset{ Id: pointers.Deref(item.ID), Name: pointers.Deref(item.Name), Type: strings.ToLower(pointers.Deref(item.Type)), ResourceGroup: storageAccount.ResourceGroup, SubscriptionId: storageAccount.SubscriptionId, TenantId: storageAccount.TenantId, Properties: properties, Extension: map[string]any{ ExtensionStorageAccountID: storageAccount.Id, ExtensionStorageAccountName: storageAccount.Name, }, } }) }), errs } func transformFileShares(pages []armstorage.FileSharesClientListResponse, storageAccount AzureAsset) ([]AzureAsset, error) { var errs error return lo.FlatMap(pages, func(response armstorage.FileSharesClientListResponse, _ int) []AzureAsset { return lo.Map(response.Value, func(item *armstorage.FileShareItem, _ int) AzureAsset { properties, err := maps.AsMapStringAny(item.Properties) if err != nil { errs = errors.Join(errs, err) } return AzureAsset{ Id: pointers.Deref(item.ID), Name: pointers.Deref(item.Name), Type: strings.ToLower(pointers.Deref(item.Type)), ResourceGroup: storageAccount.ResourceGroup, SubscriptionId: storageAccount.SubscriptionId, TenantId: storageAccount.TenantId, Properties: properties, Extension: map[string]any{ ExtensionStorageAccountID: storageAccount.Id, ExtensionStorageAccountName: storageAccount.Name, }, } }) }), errs } func transformQueues(pages []armstorage.QueueClientListResponse, storageAccount AzureAsset) ([]AzureAsset, error) { var errs error return lo.FlatMap(pages, func(response armstorage.QueueClientListResponse, _ int) []AzureAsset { return lo.Map(response.Value, func(item *armstorage.ListQueue, _ int) AzureAsset { properties, err := maps.AsMapStringAny(item.QueueProperties) if err != nil { errs = errors.Join(errs, err) } return AzureAsset{ Id: pointers.Deref(item.ID), Name: pointers.Deref(item.Name), Type: strings.ToLower(pointers.Deref(item.Type)), ResourceGroup: storageAccount.ResourceGroup, SubscriptionId: storageAccount.SubscriptionId, TenantId: storageAccount.TenantId, Properties: properties, Extension: map[string]any{ ExtensionStorageAccountID: storageAccount.Id, ExtensionStorageAccountName: storageAccount.Name, }, } }) }), errs } func transformTables(pages []armstorage.TableClientListResponse, storageAccount AzureAsset) ([]AzureAsset, error) { var errs error return lo.FlatMap(pages, func(response armstorage.TableClientListResponse, _ int) []AzureAsset { return lo.Map(response.Value, func(item *armstorage.Table, _ int) AzureAsset { properties, err := maps.AsMapStringAny(item.TableProperties) if err != nil { errs = errors.Join(errs, err) } return AzureAsset{ Id: pointers.Deref(item.ID), Name: pointers.Deref(item.Name), Type: strings.ToLower(pointers.Deref(item.Type)), ResourceGroup: storageAccount.ResourceGroup, SubscriptionId: storageAccount.SubscriptionId, TenantId: storageAccount.TenantId, Properties: properties, Extension: map[string]any{ ExtensionStorageAccountID: storageAccount.Id, ExtensionStorageAccountName: storageAccount.Name, }, } }) }), errs } func (p *storageAccountProvider) ListStorageAccountsBlobDiagnosticSettings(ctx context.Context, storageAccounts []AzureAsset) ([]AzureAsset, error) { return p.serviceDiagnosticSettings(ctx, "blobServices/default", storageAccounts) } func (p *storageAccountProvider) ListStorageAccountsTableDiagnosticSettings(ctx context.Context, storageAccounts []AzureAsset) ([]AzureAsset, error) { return p.serviceDiagnosticSettings(ctx, "tableServices/default", storageAccounts) } func (p *storageAccountProvider) ListStorageAccountsQueueDiagnosticSettings(ctx context.Context, storageAccounts []AzureAsset) ([]AzureAsset, error) { return p.serviceDiagnosticSettings(ctx, "queueServices/default", storageAccounts) } func (p *storageAccountProvider) ListDiagnosticSettingsAssetTypes(ctx context.Context, cycleMetadata cycle.Metadata, subscriptionIDs []string) ([]AzureAsset, error) { p.log.Info("Listing Azure Diagnostic Monitor Settings") return p.diagnosticSettingsCache.GetValue(ctx, cycleMetadata, func(ctx context.Context) ([]AzureAsset, error) { return p.getDiagnosticSettings(ctx, subscriptionIDs) }) } func (p *storageAccountProvider) getDiagnosticSettings(ctx context.Context, subscriptionIDs []string) ([]AzureAsset, error) { var assets []AzureAsset for _, subID := range subscriptionIDs { responses, err := p.client.AssetDiagnosticSettings(ctx, fmt.Sprintf("/subscriptions/%s/", subID), nil) if err != nil { return nil, err } a, err := transformDiagnosticSettingsClientListResponses(responses, subID) if err != nil { return nil, err } assets = append(assets, a...) } return assets, nil } func (p *storageAccountProvider) serviceDiagnosticSettings(ctx context.Context, serviceIDPostfix string, storageAccounts []AzureAsset) ([]AzureAsset, error) { var assets []AzureAsset for _, sa := range storageAccounts { queueDiagSettings, err := p.storageAccountServiceDiagnosticSettings(ctx, serviceIDPostfix, sa) if err != nil { return nil, err } assets = append(assets, queueDiagSettings...) } return assets, nil } func (p *storageAccountProvider) storageAccountServiceDiagnosticSettings(ctx context.Context, idPostfix string, storageAccount AzureAsset) ([]AzureAsset, error) { res, err := p.client.AssetDiagnosticSettings(ctx, fmt.Sprintf("%s/%s", storageAccount.Id, idPostfix), nil) if err != nil { return nil, fmt.Errorf("error while fetching storage account service %s diagnostic settings: %w", idPostfix, err) } assets, err := transformDiagnosticSettingsClientListResponses(res, storageAccount.SubscriptionId) if err != nil { return nil, fmt.Errorf("error while transforming storage account service %s diagnostic settings: %w", idPostfix, err) } for i := range assets { (&assets[i]).AddExtension(ExtensionStorageAccountID, storageAccount.Id) } return assets, nil } func transformDiagnosticSettingsClientListResponses(response []armmonitor.DiagnosticSettingsClientListResponse, subID string) ([]AzureAsset, error) { var assets []AzureAsset for _, settingsCollection := range response { for _, v := range settingsCollection.Value { if v == nil { continue } a, err := transformDiagnosticSettingsResource(v, subID) if err != nil { return nil, fmt.Errorf("error parsing azure asset model: %w", err) } assets = append(assets, a) } } return assets, nil } func transformDiagnosticSettingsResource(v *armmonitor.DiagnosticSettingsResource, subID string) (AzureAsset, error) { properties, err := maps.AsMapStringAny(v.Properties) if err != nil { return AzureAsset{}, err } return AzureAsset{ Id: pointers.Deref(v.ID), Name: pointers.Deref(v.Name), Location: "global", Properties: properties, ResourceGroup: "", SubscriptionId: subID, TenantId: "", Type: pointers.Deref(v.Type), }, nil }