diff --git a/go.mod b/go.mod index a0ee6b4292..095e2ff775 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( cloud.google.com/go/iam v1.1.2 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.8.1 + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armsubscriptions v1.2.0 github.com/aquasecurity/go-dep-parser v0.0.0-20230605080024-b71d9356a6c6 github.com/aquasecurity/trivy v0.42.1 github.com/aquasecurity/trivy-db v0.0.0-20230515061101-378ab9ed302c diff --git a/go.sum b/go.sum index 69ce7ed2a5..936fc42999 100644 --- a/go.sum +++ b/go.sum @@ -227,8 +227,12 @@ github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1 h1:LNHhpdK7hzUcx/k1LIcuh github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1/go.mod h1:uE9zaUfEQT/nbQjVi2IblCG9iaLtZsuYZ8ne+PuQ02M= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.1.2 h1:mLY+pNLjCUeKhgnAJWAKhEUQM+RJQo2H1fuGSw1Ky1E= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.8.1 h1:nGiU2ovpbtkcC3x+g/wNHV4S9TOIYe2/yOVAj3wiGHI= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.8.1/go.mod h1:T3ZgvD1aRKu12mEA0fU3PPvI7V0Nh0wzIdK0QMBhf0Y= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0 h1:ECsQtyERDVz3NP3kvDOTLvbQhqWp/x9EsGKtb4ogUr8= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armsubscriptions v1.2.0 h1:Pmy0+3ox1IC3sp6musv87BFPIdQbqyPFjn7I8I0o2Js= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armsubscriptions v1.2.0/go.mod h1:ThfyMjs6auYrWPnYJjI3H4H++oVPrz01pizpu8lfl3A= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= diff --git a/magefile.go b/magefile.go index 39bb7ce351..c61cccebda 100644 --- a/magefile.go +++ b/magefile.go @@ -401,6 +401,6 @@ func BuildOpaBundle() (err error) { return err } - fmt.Printf("Generated OPA bundle from %s branch at %s", branch, cspPoliciesPkgDir) + fmt.Printf("Generated OPA bundle from %s branch at %s\n", branch, cspPoliciesPkgDir) return nil } diff --git a/resources/providers/azurelib/inventory/provider.go b/resources/providers/azurelib/inventory/provider.go index 6c4188fcb6..667bdcf12d 100644 --- a/resources/providers/azurelib/inventory/provider.go +++ b/resources/providers/azurelib/inventory/provider.go @@ -20,20 +20,25 @@ package inventory import ( "bytes" "context" - "os" + "errors" + "fmt" "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armsubscriptions" "github.com/elastic/elastic-agent-libs/logp" + "github.com/samber/lo" "github.com/elastic/cloudbeat/resources/providers/azurelib/auth" + "github.com/elastic/cloudbeat/resources/utils/strings" ) type Provider struct { - log *logp.Logger - client *AzureClientWrapper - ctx context.Context - Config auth.AzureFactoryConfig + log *logp.Logger + client *AzureClientWrapper + subscriptions []*string + ctx context.Context + Config auth.AzureFactoryConfig } type ProviderInitializer struct{} @@ -64,6 +69,8 @@ type ProviderInitializerAPI interface { } func (p *ProviderInitializer) Init(ctx context.Context, log *logp.Logger, azureConfig auth.AzureFactoryConfig) (ServiceAPI, error) { + log = log.Named("azure") + clientFactory, err := armresourcegraph.NewClientFactory(azureConfig.Credentials, nil) if err != nil { return nil, err @@ -71,21 +78,59 @@ func (p *ProviderInitializer) Init(ctx context.Context, log *logp.Logger, azureC client := clientFactory.NewClient() - // We wrap the client so we can mock it in tests + // We wrap the client, so we can mock it in tests wrapper := &AzureClientWrapper{ AssetQuery: func(ctx context.Context, query armresourcegraph.QueryRequest, options *armresourcegraph.ClientResourcesOptions) (armresourcegraph.ClientResourcesResponse, error) { return client.Resources(ctx, query, options) }, } + subscriptions, err := p.getSubscriptionIds(ctx, azureConfig) + if err != nil { + return nil, fmt.Errorf("failed to get subscription ids: %w", err) + } + if len(subscriptions) == 0 { + return nil, errors.New("no subscriptions available to query") + } + log.Info( + lo.Reduce(subscriptions, func(agg string, item *string, _ int) string { + return fmt.Sprintf("%s %s", agg, strings.Dereference(item)) + }, "subscriptions:"), + ) + return &Provider{ - Config: azureConfig, - client: wrapper, - log: log, - ctx: ctx, + log: log, + client: wrapper, + subscriptions: subscriptions, + ctx: ctx, + Config: azureConfig, }, nil } +func (p *ProviderInitializer) getSubscriptionIds(ctx context.Context, azureConfig auth.AzureFactoryConfig) ([]*string, error) { + // TODO: mockable + + var result []*string + + clientFactory, err := armsubscriptions.NewClientFactory(azureConfig.Credentials, nil) + if err != nil { + return nil, err + } + pager := clientFactory.NewClient().NewListPager(nil) + for pager.More() { + page, err := pager.NextPage(ctx) + if err != nil { + return nil, err + } + for _, subscription := range page.Value { + if subscription != nil { + result = append(result, subscription.SubscriptionID) + } + } + } + return result, nil +} + func (p *Provider) ListAllAssetTypesByName(assets []string) ([]AzureAsset, error) { p.log.Infof("Listing Azure assets: %v", assets) var resourceAssets []AzureAsset @@ -95,9 +140,7 @@ func (p *Provider) ListAllAssetTypesByName(assets []string) ([]AzureAsset, error Options: &armresourcegraph.QueryRequestOptions{ ResultFormat: to.Ptr(armresourcegraph.ResultFormatObjectArray), }, - Subscriptions: []*string{ - // TODO: Populate from config or query (not sensitive but still don't want to commit) - to.Ptr(os.Getenv("AZURE_SUBSCRIPTION_ID"))}, + Subscriptions: p.subscriptions, } resourceAssets, err := p.runPaginatedQuery(query)