Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@ cmd/cloudlist/cloudlist
dist
.env
provider-config.yaml
cloudlist

cloudlist
6 changes: 5 additions & 1 deletion internal/runner/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,11 @@ func readProviderConfig(configFile string) (schema.Options, error) {
if err != nil {
return nil, err
}
defer file.Close()
defer func() {
if err := file.Close(); err != nil {
gologger.Error().Msgf("Could not close provider config file: %s\n", err)
}
}()

config := schema.Options{}
if err := yaml.NewDecoder(file).Decode(&config); err != nil {
Expand Down
7 changes: 6 additions & 1 deletion pkg/inventory/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"os"

"github.com/projectdiscovery/cloudlist/pkg/schema"
"github.com/projectdiscovery/gologger"
"gopkg.in/yaml.v2"
)

Expand All @@ -13,7 +14,11 @@ func ParseOptions(path string) (schema.Options, error) {
if err != nil {
return nil, err
}
defer file.Close()
defer func() {
if err := file.Close(); err != nil {
gologger.Error().Msgf("Could not close provider config file: %s\n", err)
}
}()

options := schema.Options{}
if err := yaml.NewDecoder(file).Decode(&options); err != nil {
Expand Down
1 change: 1 addition & 0 deletions pkg/providers/aws/route53.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ func (r *route53Provider) listResourcesByZone(zones []*route53.HostedZone, clien
Service: r.name(),
}

//nolint
if *item.Type == "A" {
resource.PublicIPv4 = record
} else if *item.Type == "AAAA" {
Expand Down
142 changes: 94 additions & 48 deletions pkg/providers/azure/azure.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/Azure/azure-sdk-for-go/profiles/latest/network/mgmt/network"
"github.com/Azure/azure-sdk-for-go/profiles/latest/resources/mgmt/resources"
"github.com/Azure/azure-sdk-for-go/profiles/latest/resources/mgmt/subscriptions"
"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/azure/auth"
"github.com/projectdiscovery/cloudlist/pkg/schema"
Expand All @@ -18,7 +19,7 @@ const (
tenantID = `tenant_id`
clientID = `client_id`
clientSecret = `client_secret`
subscriptionID = `subscription_id`
subscriptionID = `subscription_id` // optional
useCliAuth = `use_cli_auth`

providerName = "azure"
Expand All @@ -28,22 +29,16 @@ var Services = []string{"vm", "publicip"}

// Provider is a data provider for Azure API
type Provider struct {
id string
SubscriptionID string
Authorizer autorest.Authorizer
services schema.ServiceMap
id string
SubscriptionIDs []string
Authorizer autorest.Authorizer
services schema.ServiceMap
}

// New creates a new provider client for Azure API
func New(options schema.OptionBlock) (*Provider, error) {
SubscriptionID, ok := options.GetMetadata(subscriptionID)
if !ok {
return nil, &schema.ErrNoSuchKey{Name: subscriptionID}
}

UseCliAuth, _ := options.GetMetadata(useCliAuth)

ID, _ := options.GetMetadata(id)
UseCliAuth, _ := options.GetMetadata(useCliAuth)

var authorizer autorest.Authorizer
var err error
Expand Down Expand Up @@ -75,6 +70,7 @@ func New(options schema.OptionBlock) (*Provider, error) {
}
}

// Parse services
supportedServicesMap := make(map[string]struct{})
for _, s := range Services {
supportedServicesMap[s] = struct{}{}
Expand All @@ -92,8 +88,49 @@ func New(options schema.OptionBlock) (*Provider, error) {
services[s] = struct{}{}
}
}
return &Provider{Authorizer: authorizer, SubscriptionID: SubscriptionID, id: ID, services: services}, nil

provider := &Provider{
Authorizer: authorizer,
id: ID,
services: services,
}

// Check if a specific subscription ID was provided
specifiedSubID, hasSpecificSub := options.GetMetadata(subscriptionID)

// If a specific subscription was provided, use only that one
if hasSpecificSub && specifiedSubID != "" {
provider.SubscriptionIDs = []string{specifiedSubID}
return provider, nil
}

// Otherwise, discover all available subscriptions
gologger.Info().Msgf("Listing subscriptions from provider: azure")

ctx := context.Background()
subsClient := subscriptions.NewClient()
subsClient.Authorizer = authorizer

var subIDs []string
for subsList, err := subsClient.List(ctx); subsList.NotDone(); err = subsList.NextWithContext(ctx) {
if err != nil {
return nil, fmt.Errorf("failed to list subscriptions: %v", err)
}

for _, sub := range subsList.Values() {
if sub.SubscriptionID != nil {
subIDs = append(subIDs, *sub.SubscriptionID)
gologger.Info().Msgf("Discovered subscription: %s", *sub.SubscriptionID)
}
}
}

if len(subIDs) == 0 {
return nil, fmt.Errorf("no subscriptions found for the provided credentials")
}

provider.SubscriptionIDs = subIDs
return provider, nil
}

// Name returns the name of the provider
Expand All @@ -115,52 +152,61 @@ func (p *Provider) Services() []string {
func (p *Provider) Resources(ctx context.Context) (*schema.Resources, error) {
resources := schema.NewResources()

if p.services.Has("vm") {
vmp := &vmProvider{Authorizer: p.Authorizer, SubscriptionID: p.SubscriptionID, id: p.id}
vmIPs, err := vmp.GetResource(ctx)
if err != nil {
return nil, fmt.Errorf("error listing VM public ips: %s", err)
}
resources.Merge(vmIPs)
}
// Process each subscription
for _, subscriptionID := range p.SubscriptionIDs {
gologger.Info().Msgf("Processing subscription: %s", subscriptionID)

if p.services.Has("publicip") {
if p.services.Has("vm") {
vmp := &vmProvider{Authorizer: p.Authorizer, SubscriptionID: subscriptionID, id: p.id}
vmIPs, err := vmp.GetResource(ctx)
if err != nil {
gologger.Warning().Msgf("Error listing VM public IPs for subscription %s: %s", subscriptionID, err)
continue
}
resources.Merge(vmIPs)
}

publicIPp := &publicIPProvider{Authorizer: p.Authorizer, SubscriptionID: p.SubscriptionID, id: p.id}
publicIPs, err := publicIPp.GetResource(ctx)
if err != nil {
return nil, fmt.Errorf("error listing public ips: %s", err)
if p.services.Has("publicip") {
publicIPp := &publicIPProvider{Authorizer: p.Authorizer, SubscriptionID: subscriptionID, id: p.id}
publicIPs, err := publicIPp.GetResource(ctx)
if err != nil {
gologger.Warning().Msgf("Error listing public IPs for subscription %s: %s", subscriptionID, err)
continue
}
resources.Merge(publicIPs)
}
resources.Merge(publicIPs)
}

return resources, nil
}

// Verify checks if the provider is valid using simple API call
func (p *Provider) Verify(ctx context.Context) error {
groupsClient := resources.NewGroupsClient(p.SubscriptionID)
groupsClient.Authorizer = p.Authorizer

pClient := network.NewPublicIPAddressesClient(p.SubscriptionID)
pClient.Authorizer = p.Authorizer

// Try a lightweight operation - just list the first group
var success bool
if p.services.Has("vm") {
_, err := groupsClient.List(ctx, "", nil)
if err != nil {
return fmt.Errorf("failed to verify Azure credentials: %v", err)
for _, subscriptionID := range p.SubscriptionIDs {
groupsClient := resources.NewGroupsClient(subscriptionID)
groupsClient.Authorizer = p.Authorizer

pClient := network.NewPublicIPAddressesClient(subscriptionID)
pClient.Authorizer = p.Authorizer

// Try a lightweight operation - just list the first group
var success bool
if p.services.Has("vm") {
_, err := groupsClient.List(ctx, "", nil)
if err != nil {
return fmt.Errorf("failed to verify Azure credentials: %v", err)
}
success = true
} else if p.services.Has("publicip") && !success {
_, err := pClient.ListAllComplete(ctx)
if err != nil {
return fmt.Errorf("failed to verify Azure credentials: %v", err)
}
success = true
}
success = true
} else if p.services.Has("publicip") && !success {
_, err := pClient.ListAllComplete(ctx)
if err != nil {
return fmt.Errorf("failed to verify Azure credentials: %v", err)
if success {
return nil
}
success = true
}
if success {
return nil
}
return fmt.Errorf("no accessible Azure services found with provided credentials")
}
7 changes: 6 additions & 1 deletion pkg/providers/custom/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"strings"

"github.com/projectdiscovery/cloudlist/pkg/schema"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/retryablehttp-go"
)

Expand Down Expand Up @@ -39,7 +40,11 @@ func (d *serviceProvider) GetResource(ctx context.Context) (*schema.Resources, e
if err != nil {
return nil, err
}
defer response.Body.Close()
defer func() {
if err := response.Body.Close(); err != nil {
gologger.Error().Msgf("Could not close provider config file: %s\n", err)
}
}()

if response.StatusCode != http.StatusOK {
continue
Expand Down
1 change: 1 addition & 0 deletions pkg/providers/gcp/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ func (d *cloudDNSProvider) parseRecordsForResourceSet(r *dns.ResourceRecordSetsL
Service: d.name(),
}

//nolint
if resource.Type == "A" {
dst.PublicIPv4 = data
} else if resource.Type == "AAAA" {
Expand Down
7 changes: 6 additions & 1 deletion pkg/providers/terraform/state_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/pkg/errors"
"github.com/projectdiscovery/cloudlist/pkg/schema"
"github.com/projectdiscovery/gologger"
)

// instanceProvider is an instance provider for terraform state file
Expand All @@ -26,7 +27,11 @@ func (d *instanceProvider) GetResource(ctx context.Context) (*schema.Resources,
if err != nil {
return nil, errors.Wrap(err, "could not open state file")
}
defer file.Close()
defer func() {
if err := file.Close(); err != nil {
gologger.Error().Msgf("Could not close provider config file: %s\n", err)
}
}()

data, err := io.ReadAll(file)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/schema/validate/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func (v *Validator) Identify(item string) ResourceType {

// isDNSName will validate the given string as a DNS name
func (v *Validator) isDNSName(str string, parsed net.IP) bool {
if str == "" || len(strings.Replace(str, ".", "", -1)) > 255 {
if str == "" || len(strings.ReplaceAll(str, ".", "")) > 255 {
// constraints already violated
return false
}
Expand Down
Loading