Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Feature/aws profile auth #139

Merged
merged 4 commits into from
Aug 23, 2020
Merged
Show file tree
Hide file tree
Changes from 2 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
82 changes: 70 additions & 12 deletions collector/aws/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,87 @@ import (
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
"github.com/aws/aws-sdk-go/aws/session"
log "github.com/sirupsen/logrus"

"finala/collector/config"
)

// CreateAuthConfiguration return aws auth configuration
func CreateAuthConfiguration(accessKey, secretKey, sessionToken, role, region string) (*session.Session, *awsClient.Config) {
var credentialsAWS *credentials.Credentials
// AuthDescriptor is an interface defining the aws auth logic
type AuthDescriptor interface {
Login(region string) (*session.Session, *awsClient.Config)
}

// Auth will hold the aws auth struct
type Auth struct {
account config.AWSAccount
}

// NewAuth creates new Finala aws authenticator
func NewAuth(account config.AWSAccount) *Auth {

return &Auth{
account: account,
}
}

// Login to AWS account.
// Application hierarchy login:
// 1. checks first if static credentials defind (accessKey/ secret key and session token (optional) )
// 2. checks if profile exists in yaml file
// 3. checks if role exists in yaml file
// else login without any specific creds and give aws logic. for more details: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html
func (au *Auth) Login(region string) (*session.Session, *awsClient.Config) {

// Use separate call for AWS credentials defined in config.yaml
// Otherwise environment variables will be used
if accessKey != "" && secretKey != "" {
log.Info("Using AccessKey or SecretKey defined in config.yaml")
credentialsAWS = credentials.NewStaticCredentials(accessKey, secretKey, sessionToken)
if au.account.AccessKey != "" && au.account.SecretKey != "" {
return au.withStaticCredentials(au.account.AccessKey, au.account.SecretKey, au.account.SessionToken, region)
} else if au.account.Profile != "" {
return au.withProfile(au.account.Profile, region)
} else if au.account.Role != "" {
return au.withRole(au.account.Role, region)
}

log.WithField("region", region).Info("auth: using default AWS auth client")
config := &awsClient.Config{
Region: &region,
Credentials: credentialsAWS,
Credentials: &credentials.Credentials{},
}

sess := session.Must(session.NewSession(config))
return sess, config
}

// withStaticCredentials login with static credentials
func (au *Auth) withStaticCredentials(accessKey, secretKey, sessionToken, region string) (*session.Session, *awsClient.Config) {

if role != "" {
log.WithField("role", role).Info("assume role provided")
config.Credentials = stscreds.NewCredentials(sess, role, func(p *stscreds.AssumeRoleProvider) {})
log.WithField("region", region).Info("auth: using aws static credentials")

config := &awsClient.Config{
Region: &region,
Credentials: credentials.NewStaticCredentials(accessKey, secretKey, sessionToken),
}
sess := session.Must(session.NewSession(config))
return sess, config
}

// withProfile login with profile
func (au *Auth) withProfile(profile, region string) (*session.Session, *awsClient.Config) {

log.WithField("region", region).Info("auth: using aws profile")
config := &awsClient.Config{
Region: &region,
Credentials: credentials.NewSharedCredentials("", profile),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't you give the option to pass custom Profile file ?

}
sess := session.Must(session.NewSession(config))
return sess, config
}

// withRole login with role
func (au *Auth) withRole(role, region string) (*session.Session, *awsClient.Config) {

log.WithField("region", region).Info("auth: using aws role")
config := &awsClient.Config{
Region: &region,
}
sess := session.Must(session.NewSession(config))
config.Credentials = stscreds.NewCredentials(sess, role, func(p *stscreds.AssumeRoleProvider) {})
return sess, config
}
8 changes: 5 additions & 3 deletions collector/aws/detector.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const (

// DetectorManager describe tje detector manager
type DetectorManager struct {
awsAuth AuthDescriptor
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need it ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

collector collector.CollectorDescriber
cloudWatchClient *cloudwatch.CloudwatchManager
# *#.#Manager
Expand All @@ -43,16 +44,17 @@ type DetectorManager struct {
}

// NewDetectorManager create new instance of detector manager
func NewDetectorManager(collector collector.CollectorDescriber, account config.AWSAccount, stsManager *STSManager, global map[string]struct{}, region string) *DetectorManager {
func NewDetectorManager(awsAuth AuthDescriptor, collector collector.CollectorDescriber, account config.AWSAccount, stsManager *STSManager, global map[string]struct{}, region string) *DetectorManager {

priceSession, _ := CreateAuthConfiguration(account.AccessKey, account.SecretKey, account.SessionToken, account.Role, defaultRegionPrice)
priceSession, _ := awsAuth.Login(defaultRegionPrice)
#Manager := #.New#Manager(aws#.New(priceSession), defaultRegionPrice)

regionSession, regionConfig := CreateAuthConfiguration(account.AccessKey, account.SecretKey, account.SessionToken, account.Role, region)
regionSession, regionConfig := awsAuth.Login(region)
cloudWatchCLient := cloudwatch.NewCloudWatchManager(awsCloudwatch.New(regionSession, regionConfig))

callerIdentityOutput, _ := stsManager.client.GetCallerIdentity(&sts.GetCallerIdentityInput{})
return &DetectorManager{
awsAuth: awsAuth,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need it ? I don't see any reference for using this type.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

collector: collector,
cloudWatchClient: cloudWatchCLient,
#: #Manager,
Expand Down
16 changes: 15 additions & 1 deletion collector/aws/detector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,22 @@ import (
collectorTestutils "finala/collector/testutils"
"testing"

awsClient "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/sts"
)

type mockAuth struct {
}

func (ma *mockAuth) Login(region string) (*session.Session, *awsClient.Config) {

config := &awsClient.Config{Region: &region}

sess := session.Must(session.NewSession(config))
return sess, config
}

type MockSTS struct{}

func NewMockSTS() *STSManager {
Expand Down Expand Up @@ -38,10 +51,11 @@ func TestDetector(t *testing.T) {
SessionToken: "session",
Regions: []string{"bar"},
}
mockAuth := &mockAuth{}
mockSTS := NewMockSTS()
collector := collectorTestutils.NewMockCollector()
global := make(map[string]struct{})
detector := NewDetectorManager(collector, account, mockSTS, global, region)
detector := NewDetectorManager(mockAuth, collector, account, mockSTS, global, region)

if detector.GetRegion() != region {
t.Fatalf("unexpected collector region, got %s expected %s", detector.GetRegion(), region)
Expand Down
5 changes: 3 additions & 2 deletions collector/aws/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,12 @@ func (app *Analyze) All() {

for _, account := range app.awsAccounts {

globalsession, globalConfig := CreateAuthConfiguration(account.AccessKey, account.SecretKey, account.SessionToken, account.Role, "")
awsAuth := NewAuth(account)
globalsession, globalConfig := awsAuth.Login("")
stsManager := NewSTSManager(sts.New(globalsession, globalConfig))

for _, region := range account.Regions {
resourcesDetection := NewDetectorManager(app.cl, account, stsManager, app.global, region)
resourcesDetection := NewDetectorManager(awsAuth, app.cl, account, stsManager, app.global, region)
for resourceType, resourceDetector := range register.GetResources() {

resource, err := resourceDetector(resourcesDetection, nil)
Expand Down
1 change: 1 addition & 0 deletions collector/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type AWSAccount struct {
AccessKey string `yaml:"access_key"`
SecretKey string `yaml:"secret_key"`
Role string `yaml:"role"`
Profile string `yaml:"profile"`
SessionToken string `yaml:"session_token"`
Regions []string `yaml:"regions"`
}
Expand Down
1 change: 1 addition & 0 deletions configuration/collector.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ providers:
# access_key: <access_key>
# secret_key: <secret_key>
# role:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we want to order the types of login like the code expects them ( hierarchy)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

# profile:
regions:
- us-east-1
- us-west-2
Expand Down