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

add aws assume role arn support #624

Open
wants to merge 2 commits into
base: dev
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
2 changes: 1 addition & 1 deletion .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
strategy:
matrix:
go-version: [1.22.x]
os: [ubuntu-latest, windows-latest, macOS-12]
os: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- name: Set up Go
uses: actions/setup-go@v4
Expand Down
6 changes: 6 additions & 0 deletions PROVIDERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ Amazon Web Services can be integrated by using the following configuration block
aws_secret_key: $AWS_SECRET_KEY
# aws_session_token session token for temporary security credentials retrieved via STS (optional)
aws_session_token: $AWS_SESSION_TOKEN
# assume_role_arn is the arn of the role to assume (optional)
assume_role_arn: $AWS_ASSUME_ROLE_ARN
# external_id is the external id for the role to assume (required if assume_role_arn is provided)
external_id: $AWS_EXTERNAL_ID
# assume_role_session_name is the name of the session for the role to assume (required if assume_role_arn is provided)
assume_role_session_name: $AWS_ASSUME_ROLE_SESSION_NAME
# assume_role_name is the name of the role to assume (optional)
assume_role_name: $AWS_ASSUME_ROLE_NAME
# account_ids is the aws account ids which has similar assumed role name (optional)
Expand Down
116 changes: 85 additions & 31 deletions pkg/providers/aws/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/aws/aws-sdk-go/service/lightsail"
"github.com/aws/aws-sdk-go/service/route53"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/sts"
"github.com/pkg/errors"
"github.com/projectdiscovery/cloudlist/pkg/schema"
sliceutil "github.com/projectdiscovery/utils/slice"
Expand All @@ -27,16 +28,20 @@ import (
var Services = []string{"ec2", "instance", "route53", "s3", "ecs", "eks", "lambda", "apigateway", "alb", "elb", "lightsail", "cloudfront"}

type ProviderOptions struct {
Id string
AccessKey string
SecretKey string
Token string
AssumeRoleName string
AccountIds []string
Services schema.ServiceMap
Id string
AccessKey string
SecretKey string
Token string
AssumeRoleArn string
AssumeRoleSessionName string
ExternalId string
AssumeRoleName string
AccountIds []string
Services schema.ServiceMap
}

func (p *ProviderOptions) ParseOptionBlock(block schema.OptionBlock) error {
p.Id, _ = block.GetMetadata("id")
accessKey, ok := block.GetMetadata(apiAccessKey)
if !ok {
return &schema.ErrNoSuchKey{Name: apiAccessKey}
Expand All @@ -46,7 +51,23 @@ func (p *ProviderOptions) ParseOptionBlock(block schema.OptionBlock) error {
return &schema.ErrNoSuchKey{Name: apiSecretKey}
}
p.Token, _ = block.GetMetadata(sessionToken)
p.Id, _ = block.GetMetadata("id")
p.AccessKey = accessKey
p.SecretKey = accessToken

if assumeRoleArn, ok := block.GetMetadata(assumeRoleArn); ok {
p.AssumeRoleArn = assumeRoleArn
}
if assumeRoleSessionName, ok := block.GetMetadata(assumeRoleSessionName); ok {
p.AssumeRoleSessionName = assumeRoleSessionName
}

if externalId, ok := block.GetMetadata(externalId); ok {
p.ExternalId = externalId
}

if assumeRoleName, ok := block.GetMetadata(assumeRoleName); ok {
p.AssumeRoleName = assumeRoleName
}

supportedServicesMap := make(map[string]struct{})
for _, s := range Services {
Expand All @@ -66,15 +87,8 @@ func (p *ProviderOptions) ParseOptionBlock(block schema.OptionBlock) error {
services[s] = struct{}{}
}
}

p.AccessKey = accessKey
p.SecretKey = accessToken
p.Services = services

if assumeRoleName, ok := block.GetMetadata(assumeRoleName); ok {
p.AssumeRoleName = assumeRoleName
}

if accountIds, ok := block.GetMetadata(accountIds); ok {
p.AccountIds = sliceutil.Dedupe(strings.Split(accountIds, ","))
}
Expand Down Expand Up @@ -111,13 +125,50 @@ func New(block schema.OptionBlock) (*Provider, error) {
config.WithRegion("us-east-1")
config.WithCredentials(credentials.NewStaticCredentials(options.AccessKey, options.SecretKey, options.Token))

session, err := session.NewSession(config)
if err != nil {
return nil, errors.Wrap(err, "could not extablish a session")
var sess *session.Session
var err error

if options.AssumeRoleArn != "" {
stsSession, err := session.NewSession(config)
if err != nil {
return nil, errors.Wrap(err, "could not establish session with AWS config")
}

stsClient := sts.New(stsSession)
roleInput := &sts.AssumeRoleInput{
RoleArn: aws.String(options.AssumeRoleArn),
RoleSessionName: aws.String(options.AssumeRoleSessionName),
ExternalId: aws.String(options.ExternalId),
}

assumeRoleOutput, err := stsClient.AssumeRole(roleInput)
if err != nil {
return nil, errors.Wrap(err, "failed to assume role")
}

assumedCredentials := assumeRoleOutput.Credentials

sess, err = session.NewSession(&aws.Config{
Credentials: credentials.NewStaticCredentials(
*assumedCredentials.AccessKeyId,
*assumedCredentials.SecretAccessKey,
*assumedCredentials.SessionToken,
),
Region: config.Region,
})
if err != nil {
return nil, errors.Wrap(err, "could not assume role")
}
} else {
sess, err = session.NewSession(config)
if err != nil {
return nil, errors.Wrap(err, "could not establish a session")
}
}
provider.session = session

rc := ec2.New(session)
provider.session = sess

rc := ec2.New(sess)
regions, err := rc.DescribeRegions(&ec2.DescribeRegionsInput{})
if err != nil {
return nil, errors.Wrap(err, "could not get list of regions")
Expand All @@ -126,37 +177,37 @@ func New(block schema.OptionBlock) (*Provider, error) {

services := provider.options.Services
if services.Has("ec2") || services.Has("instance") {
provider.ec2Client = ec2.New(session)
provider.ec2Client = ec2.New(sess)
}
if services.Has("route53") {
provider.route53Client = route53.New(session)
provider.route53Client = route53.New(sess)
}
if services.Has("s3") {
provider.s3Client = s3.New(session)
provider.s3Client = s3.New(sess)
}
if services.Has("ecs") {
provider.ecsClient = ecs.New(session)
provider.ecsClient = ecs.New(sess)
}
if services.Has("eks") {
provider.eksClient = eks.New(session)
provider.eksClient = eks.New(sess)
}
if services.Has("lambda") {
provider.lambdaClient = lambda.New(session)
provider.lambdaClient = lambda.New(sess)
}
if services.Has("apigateway") {
provider.apiGateway = apigateway.New(session)
provider.apiGateway = apigateway.New(sess)
}
if services.Has("alb") {
provider.albClient = elbv2.New(session)
provider.albClient = elbv2.New(sess)
}
if services.Has("elb") {
provider.elbClient = elb.New(session)
provider.elbClient = elb.New(sess)
}
if services.Has("lightsail") {
provider.lightsailClient = lightsail.New(session)
provider.lightsailClient = lightsail.New(sess)
}
if services.Has("cloudfront") {
provider.cloudFrontClient = cloudfront.New(session)
provider.cloudFrontClient = cloudfront.New(sess)
}
return provider, nil
}
Expand All @@ -166,6 +217,9 @@ const apiAccessKey = "aws_access_key"
const apiSecretKey = "aws_secret_key"
const sessionToken = "aws_session_token"
const assumeRoleName = "assume_role_name"
const assumeRoleArn = "assume_role_arn"
const externalId = "external_id"
const assumeRoleSessionName = "assume_role_session_name"
const accountIds = "account_ids"

// Name returns the name of the provider
Expand Down
Loading