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
2 changes: 2 additions & 0 deletions PROVIDERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,8 @@ Alibaba Cloud can be integrated by using the following configuration block.

Alibaba Cloud Access Key ID and Secret can be created by visiting https://ram.console.aliyun.com/manage/ak

Supported services: `instance` (ECS), `slb` (Classic Load Balancer), `alb` (Application Load Balancer), `eip` (Elastic IP), `ack` (Container Service for Kubernetes API server endpoints). The RAM user needs read-only access to each of them, e.g. the `AliyunECSReadOnlyAccess`, `AliyunSLBReadOnlyAccess`, `AliyunALBReadOnlyAccess`, `AliyunVPCReadOnlyAccess` and `AliyunCSReadOnlyAccess` system policies.


References -
- https://www.alibabacloud.com/help/faq-detail/142101.htm
Expand Down
98 changes: 98 additions & 0 deletions pkg/providers/alibaba/ack.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package alibaba

import (
"context"
"encoding/json"
"net"
"net/url"

"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/services/cs"
"github.com/projectdiscovery/cloudlist/pkg/schema"
)

// ackProvider is a Container Service for Kubernetes (ACK) provider for alibaba API
type ackProvider struct {
id string
client *cs.Client
}

// The cs SDK package leaves ROA response bodies untyped, so the fields we
// need are decoded here.
type ackClustersResponse struct {
Clusters []struct {
// MasterURL is itself a JSON-encoded object.
MasterURL string `json:"master_url"`
} `json:"clusters"`
PageInfo struct {
TotalCount int `json:"total_count"`
} `json:"page_info"`
}

type ackMasterURL struct {
APIServerEndpoint string `json:"api_server_endpoint"`
IntranetAPIServerEndpoint string `json:"intranet_api_server_endpoint"`
}

func (d *ackProvider) name() string {
return "ack"
}

// GetResource returns all the resources in the store for a provider.
func (d *ackProvider) GetResource(ctx context.Context) (*schema.Resources, error) {
list := schema.NewResources()

request := cs.CreateDescribeClustersV1Request()
request.PageSize = requests.NewInteger(pageSize)
for page := 1; ; page++ {
request.PageNumber = requests.NewInteger(page)
response, err := d.client.DescribeClustersV1(request)
if err != nil {
return list, err
}

var clusters ackClustersResponse
if err := json.Unmarshal(response.GetHttpContentBytes(), &clusters); err != nil {
return list, err
}

for _, cluster := range clusters.Clusters {
var masterURL ackMasterURL
if err := json.Unmarshal([]byte(cluster.MasterURL), &masterURL); err != nil {
continue
}
d.appendEndpoint(list, masterURL.APIServerEndpoint, true)
d.appendEndpoint(list, masterURL.IntranetAPIServerEndpoint, false)
}

if len(clusters.Clusters) == 0 || page*pageSize >= clusters.PageInfo.TotalCount {
break
}
}
return list, nil
}

// appendEndpoint adds the host of an API server URL such as https://47.0.0.1:6443.
func (d *ackProvider) appendEndpoint(list *schema.Resources, endpoint string, public bool) {
parsed, err := url.Parse(endpoint)
if err != nil || parsed.Hostname() == "" {
return
}
host := parsed.Hostname()

resource := &schema.Resource{
ID: d.id,
Provider: providerName,
Public: public,
Service: d.name(),
}
switch {
case net.ParseIP(host) == nil:
resource.DNSName = host
case public:
resource.PublicIPv4 = host
default:
resource.PrivateIpv4 = host
}
list.Append(resource)
}
49 changes: 49 additions & 0 deletions pkg/providers/alibaba/alb.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package alibaba

import (
"context"

"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/services/alb"
"github.com/projectdiscovery/cloudlist/pkg/schema"
)

// albProvider is an Application Load Balancer provider for alibaba API
type albProvider struct {
id string
client *alb.Client
}

func (d *albProvider) name() string {
return "alb"
}

// GetResource returns all the resources in the store for a provider.
func (d *albProvider) GetResource(ctx context.Context) (*schema.Resources, error) {
list := schema.NewResources()

request := alb.CreateListLoadBalancersRequest()
request.MaxResults = requests.NewInteger(pageSize)
for {
response, err := d.client.ListLoadBalancers(request)
if err != nil {
return list, err
}

for _, lb := range response.LoadBalancers {
list.Append(&schema.Resource{
ID: d.id,
Provider: providerName,
DNSName: lb.DNSName,
Public: lb.AddressType == "Internet",
Service: d.name(),
})
}

if response.NextToken == "" {
break
}
request.NextToken = response.NextToken
}
return list, nil
}
70 changes: 59 additions & 11 deletions pkg/providers/alibaba/alibaba.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,35 @@ package alibaba
import (
"context"

"github.com/aliyun/alibaba-cloud-sdk-go/sdk"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
"github.com/aliyun/alibaba-cloud-sdk-go/services/alb"
"github.com/aliyun/alibaba-cloud-sdk-go/services/cs"
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
"github.com/aliyun/alibaba-cloud-sdk-go/services/slb"
"github.com/aliyun/alibaba-cloud-sdk-go/services/vpc"
"github.com/projectdiscovery/cloudlist/pkg/schema"
"github.com/projectdiscovery/gologger"
)

var Services = []string{"instance"}
var Services = []string{"instance", "slb", "alb", "eip", "ack"}

const (
regionID = "alibaba_region_id"
accessKeyID = "alibaba_access_key"
accessKeySecret = "alibaba_access_key_secret"
providerName = "alibaba"
pageSize = 100
)

// Provider is a data provider for alibaba API
type Provider struct {
id string
ecsClient *ecs.Client
slbClient *slb.Client
albClient *alb.Client
vpcClient *vpc.Client
csClient *cs.Client
services schema.ServiceMap
}

Expand All @@ -45,16 +56,34 @@ func New(options schema.OptionBlock) (*Provider, error) {
services := options.ResolveServices(Services)
provider.services = services

// The SDK defaults to plain HTTP.
config := sdk.NewConfig().WithScheme("HTTPS")
credential := credentials.NewAccessKeyCredential(accessKeyID, accessKeySecret)
var err error
if services.Has("instance") {
client, err := ecs.NewClientWithAccessKey(
regionID, // region ID
accessKeyID, // AccessKey ID
accessKeySecret, // AccessKey secret
)
if err != nil {
if provider.ecsClient, err = ecs.NewClientWithOptions(regionID, config, credential); err != nil {
return nil, err
}
}
if services.Has("slb") {
if provider.slbClient, err = slb.NewClientWithOptions(regionID, config, credential); err != nil {
return nil, err
}
}
if services.Has("alb") {
if provider.albClient, err = alb.NewClientWithOptions(regionID, config, credential); err != nil {
return nil, err
}
}
if services.Has("eip") {
if provider.vpcClient, err = vpc.NewClientWithOptions(regionID, config, credential); err != nil {
return nil, err
}
}
if services.Has("ack") {
if provider.csClient, err = cs.NewClientWithOptions(regionID, config, credential); err != nil {
return nil, err
}
provider.ecsClient = client
}

return provider, nil
Expand All @@ -78,14 +107,33 @@ func (p *Provider) Services() []string {
// Resources returns the provider for an resource deployment source.
func (p *Provider) Resources(ctx context.Context) (*schema.Resources, error) {
finalResources := schema.NewResources()

var providers []interface {
GetResource(ctx context.Context) (*schema.Resources, error)
}
if p.ecsClient != nil {
ecsprovider := &instanceProvider{client: p.ecsClient, id: p.id}
resources, err := ecsprovider.GetResource(ctx)
providers = append(providers, &instanceProvider{client: p.ecsClient, id: p.id})
}
if p.slbClient != nil {
providers = append(providers, &slbProvider{client: p.slbClient, id: p.id})
}
if p.albClient != nil {
providers = append(providers, &albProvider{client: p.albClient, id: p.id})
}
if p.vpcClient != nil {
providers = append(providers, &eipProvider{client: p.vpcClient, id: p.id})
}
if p.csClient != nil {
providers = append(providers, &ackProvider{client: p.csClient, id: p.id})
}

for _, provider := range providers {
resources, err := provider.GetResource(ctx)
if resources != nil {
finalResources.Merge(resources)
}
if err != nil {
gologger.Warning().Msgf("alibaba: instance listing failed: %v", err)
gologger.Warning().Msgf("alibaba: listing failed: %v", err)
}
}
return finalResources, nil
Expand Down
Loading
Loading