* CloudWatch: Restrict auth provider and assume role usage according to Grafana configuration (#31805)
* restrict usage of providers and assume role according to grafana config
* update docs
* Update docs/sources/datasources/cloudwatch.md
Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com>
* Update pkg/tsdb/cloudwatch/cloudwatch.go
Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com>
* Update pkg/tsdb/cloudwatch/session_test.go
Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com>
* pr feedback
* fix failing test
Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com>
(cherry picked from commit 2d660ee502)
* Update docs/sources/datasources/cloudwatch.md
Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com>
Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com>
189 lines
5.5 KiB
Go
189 lines
5.5 KiB
Go
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)
|
|
})
|
|
}
|