mirror of https://github.com/grafana/grafana
Cloudwatch: use shared library for aws auth (#29550)
* use sdk for handling auth * fix broken test * lint fixes Co-authored-by: Erik Sundell <erik.sundell87@gmail.com>pull/31281/head
parent
8404d54277
commit
9dd1d5f553
@ -1,44 +0,0 @@ |
|||||||
package cloudwatch |
|
||||||
|
|
||||||
import ( |
|
||||||
"sync" |
|
||||||
"time" |
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws" |
|
||||||
"github.com/aws/aws-sdk-go/aws/credentials" |
|
||||||
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds" |
|
||||||
"github.com/aws/aws-sdk-go/aws/credentials/stscreds" |
|
||||||
"github.com/aws/aws-sdk-go/aws/ec2metadata" |
|
||||||
"github.com/aws/aws-sdk-go/aws/session" |
|
||||||
) |
|
||||||
|
|
||||||
type envelope struct { |
|
||||||
session *session.Session |
|
||||||
expiration time.Time |
|
||||||
} |
|
||||||
|
|
||||||
var sessCache = map[string]envelope{} |
|
||||||
var sessCacheLock sync.RWMutex |
|
||||||
|
|
||||||
// Session factory.
|
|
||||||
// Stubbable by tests.
|
|
||||||
//nolint:gocritic
|
|
||||||
var newSession = func(cfgs ...*aws.Config) (*session.Session, error) { |
|
||||||
return session.NewSession(cfgs...) |
|
||||||
} |
|
||||||
|
|
||||||
// STS credentials factory.
|
|
||||||
// Stubbable by tests.
|
|
||||||
//nolint:gocritic
|
|
||||||
var newSTSCredentials = stscreds.NewCredentials |
|
||||||
|
|
||||||
// EC2Metadata service factory.
|
|
||||||
// Stubbable by tests.
|
|
||||||
//nolint:gocritic
|
|
||||||
var newEC2Metadata = ec2metadata.New |
|
||||||
|
|
||||||
// EC2 role credentials factory.
|
|
||||||
// Stubbable by tests.
|
|
||||||
var newEC2RoleCredentials = func(sess *session.Session) *credentials.Credentials { |
|
||||||
return credentials.NewCredentials(&ec2rolecreds.EC2RoleProvider{Client: ec2metadata.New(sess), ExpiryWindow: stscreds.DefaultDuration}) |
|
||||||
} |
|
||||||
@ -1,188 +0,0 @@ |
|||||||
package cloudwatch |
|
||||||
|
|
||||||
import ( |
|
||||||
"reflect" |
|
||||||
"testing" |
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws" |
|
||||||
"github.com/aws/aws-sdk-go/aws/client" |
|
||||||
"github.com/aws/aws-sdk-go/aws/credentials" |
|
||||||
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds" |
|
||||||
"github.com/aws/aws-sdk-go/aws/credentials/stscreds" |
|
||||||
"github.com/aws/aws-sdk-go/aws/ec2metadata" |
|
||||||
"github.com/aws/aws-sdk-go/aws/session" |
|
||||||
"github.com/google/go-cmp/cmp" |
|
||||||
"github.com/google/go-cmp/cmp/cmpopts" |
|
||||||
"github.com/grafana/grafana/pkg/setting" |
|
||||||
"github.com/stretchr/testify/assert" |
|
||||||
"github.com/stretchr/testify/require" |
|
||||||
) |
|
||||||
|
|
||||||
// Test cloudWatchExecutor.newSession with assumption of IAM role.
|
|
||||||
func TestNewSession_AssumeRole(t *testing.T) { |
|
||||||
origNewSession := newSession |
|
||||||
origNewSTSCredentials := newSTSCredentials |
|
||||||
origNewEC2Metadata := newEC2Metadata |
|
||||||
t.Cleanup(func() { |
|
||||||
newSession = origNewSession |
|
||||||
newSTSCredentials = origNewSTSCredentials |
|
||||||
newEC2Metadata = origNewEC2Metadata |
|
||||||
}) |
|
||||||
newSession = func(cfgs ...*aws.Config) (*session.Session, error) { |
|
||||||
cfg := aws.Config{} |
|
||||||
cfg.MergeIn(cfgs...) |
|
||||||
return &session.Session{ |
|
||||||
Config: &cfg, |
|
||||||
}, nil |
|
||||||
} |
|
||||||
newSTSCredentials = func(c client.ConfigProvider, roleARN string, |
|
||||||
options ...func(*stscreds.AssumeRoleProvider)) *credentials.Credentials { |
|
||||||
p := &stscreds.AssumeRoleProvider{ |
|
||||||
RoleARN: roleARN, |
|
||||||
} |
|
||||||
for _, o := range options { |
|
||||||
o(p) |
|
||||||
} |
|
||||||
|
|
||||||
return credentials.NewCredentials(p) |
|
||||||
} |
|
||||||
newEC2Metadata = func(p client.ConfigProvider, cfgs ...*aws.Config) *ec2metadata.EC2Metadata { |
|
||||||
return nil |
|
||||||
} |
|
||||||
|
|
||||||
duration := stscreds.DefaultDuration |
|
||||||
|
|
||||||
t.Run("Without external ID", func(t *testing.T) { |
|
||||||
t.Cleanup(func() { |
|
||||||
sessCache = map[string]envelope{} |
|
||||||
}) |
|
||||||
|
|
||||||
const roleARN = "test" |
|
||||||
|
|
||||||
e := newExecutor(nil, newTestConfig()) |
|
||||||
e.DataSource = fakeDataSource(fakeDataSourceCfg{ |
|
||||||
assumeRoleARN: roleARN, |
|
||||||
}) |
|
||||||
|
|
||||||
sess, err := e.newSession(defaultRegion) |
|
||||||
require.NoError(t, err) |
|
||||||
require.NotNil(t, sess) |
|
||||||
|
|
||||||
expCreds := credentials.NewCredentials(&stscreds.AssumeRoleProvider{ |
|
||||||
RoleARN: roleARN, |
|
||||||
Duration: duration, |
|
||||||
}) |
|
||||||
diff := cmp.Diff(expCreds, sess.Config.Credentials, cmp.Exporter(func(_ reflect.Type) bool { |
|
||||||
return true |
|
||||||
}), cmpopts.IgnoreFields(stscreds.AssumeRoleProvider{}, "Expiry")) |
|
||||||
assert.Empty(t, diff) |
|
||||||
}) |
|
||||||
|
|
||||||
t.Run("With external ID", func(t *testing.T) { |
|
||||||
t.Cleanup(func() { |
|
||||||
sessCache = map[string]envelope{} |
|
||||||
}) |
|
||||||
|
|
||||||
const roleARN = "test" |
|
||||||
const externalID = "external" |
|
||||||
|
|
||||||
e := newExecutor(nil, newTestConfig()) |
|
||||||
e.DataSource = fakeDataSource(fakeDataSourceCfg{ |
|
||||||
assumeRoleARN: roleARN, |
|
||||||
externalID: externalID, |
|
||||||
}) |
|
||||||
|
|
||||||
sess, err := e.newSession(defaultRegion) |
|
||||||
require.NoError(t, err) |
|
||||||
require.NotNil(t, sess) |
|
||||||
|
|
||||||
expCreds := credentials.NewCredentials(&stscreds.AssumeRoleProvider{ |
|
||||||
RoleARN: roleARN, |
|
||||||
ExternalID: aws.String(externalID), |
|
||||||
Duration: duration, |
|
||||||
}) |
|
||||||
diff := cmp.Diff(expCreds, sess.Config.Credentials, cmp.Exporter(func(_ reflect.Type) bool { |
|
||||||
return true |
|
||||||
}), cmpopts.IgnoreFields(stscreds.AssumeRoleProvider{}, "Expiry")) |
|
||||||
assert.Empty(t, diff) |
|
||||||
}) |
|
||||||
|
|
||||||
t.Run("Assume role not enabled", func(t *testing.T) { |
|
||||||
t.Cleanup(func() { |
|
||||||
sessCache = map[string]envelope{} |
|
||||||
}) |
|
||||||
|
|
||||||
const roleARN = "test" |
|
||||||
|
|
||||||
e := newExecutor(nil, &setting.Cfg{AWSAllowedAuthProviders: []string{"default"}, AWSAssumeRoleEnabled: false}) |
|
||||||
e.DataSource = fakeDataSource(fakeDataSourceCfg{ |
|
||||||
assumeRoleARN: roleARN, |
|
||||||
}) |
|
||||||
|
|
||||||
sess, err := e.newSession(defaultRegion) |
|
||||||
require.Error(t, err) |
|
||||||
require.Nil(t, sess) |
|
||||||
|
|
||||||
expectedError := "attempting to use assume role (ARN) which is disabled in grafana.ini" |
|
||||||
assert.Equal(t, expectedError, err.Error()) |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
func TestNewSession_AllowedAuthProviders(t *testing.T) { |
|
||||||
t.Run("Not allowed auth type is used", func(t *testing.T) { |
|
||||||
e := newExecutor(nil, &setting.Cfg{AWSAllowedAuthProviders: []string{"keys"}}) |
|
||||||
e.DataSource = fakeDataSource() |
|
||||||
e.DataSource.JsonData.Set("authType", "default") |
|
||||||
|
|
||||||
sess, err := e.newSession(defaultRegion) |
|
||||||
require.Error(t, err) |
|
||||||
require.Nil(t, sess) |
|
||||||
|
|
||||||
assert.Equal(t, `attempting to use an auth type that is not allowed: "default"`, err.Error()) |
|
||||||
}) |
|
||||||
|
|
||||||
t.Run("Allowed auth type is used", func(t *testing.T) { |
|
||||||
e := newExecutor(nil, &setting.Cfg{AWSAllowedAuthProviders: []string{"keys"}}) |
|
||||||
e.DataSource = fakeDataSource() |
|
||||||
e.DataSource.JsonData.Set("authType", "keys") |
|
||||||
|
|
||||||
sess, err := e.newSession(defaultRegion) |
|
||||||
require.NoError(t, err) |
|
||||||
require.NotNil(t, sess) |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
func TestNewSession_EC2IAMRole(t *testing.T) { |
|
||||||
newSession = func(cfgs ...*aws.Config) (*session.Session, error) { |
|
||||||
cfg := aws.Config{} |
|
||||||
cfg.MergeIn(cfgs...) |
|
||||||
return &session.Session{ |
|
||||||
Config: &cfg, |
|
||||||
}, nil |
|
||||||
} |
|
||||||
newEC2Metadata = func(p client.ConfigProvider, cfgs ...*aws.Config) *ec2metadata.EC2Metadata { |
|
||||||
return nil |
|
||||||
} |
|
||||||
newEC2RoleCredentials = func(sess *session.Session) *credentials.Credentials { |
|
||||||
return credentials.NewCredentials(&ec2rolecreds.EC2RoleProvider{Client: newEC2Metadata(nil), ExpiryWindow: stscreds.DefaultDuration}) |
|
||||||
} |
|
||||||
|
|
||||||
t.Run("Credentials are created", func(t *testing.T) { |
|
||||||
e := newExecutor(nil, &setting.Cfg{AWSAllowedAuthProviders: []string{"ec2_iam_role"}, AWSAssumeRoleEnabled: true}) |
|
||||||
e.DataSource = fakeDataSource() |
|
||||||
e.DataSource.JsonData.Set("authType", "ec2_iam_role") |
|
||||||
|
|
||||||
sess, err := e.newSession(defaultRegion) |
|
||||||
require.NoError(t, err) |
|
||||||
require.NotNil(t, sess) |
|
||||||
|
|
||||||
expCreds := credentials.NewCredentials(&ec2rolecreds.EC2RoleProvider{ |
|
||||||
Client: newEC2Metadata(nil), ExpiryWindow: stscreds.DefaultDuration, |
|
||||||
}) |
|
||||||
|
|
||||||
diff := cmp.Diff(expCreds, sess.Config.Credentials, cmp.Exporter(func(_ reflect.Type) bool { |
|
||||||
return true |
|
||||||
}), cmpopts.IgnoreFields(stscreds.AssumeRoleProvider{}, "Expiry")) |
|
||||||
assert.Empty(t, diff) |
|
||||||
}) |
|
||||||
} |
|
||||||
Loading…
Reference in new issue