mirror of
https://github.com/gravitational/teleport.git
synced 2026-10-30 18:29:21 +08:00
Migrate AWS STS client to AWS SDK v2 (#51573)
This commit is contained in:
@@ -91,8 +91,6 @@ type GCPClients interface {
|
||||
type AWSClients interface {
|
||||
// GetAWSSession returns AWS session for the specified region and any role(s).
|
||||
GetAWSSession(ctx context.Context, region string, opts ...AWSOptionsFn) (*awssession.Session, error)
|
||||
// GetAWSSTSClient returns AWS STS client for the specified region.
|
||||
GetAWSSTSClient(ctx context.Context, region string, opts ...AWSOptionsFn) (stsiface.STSAPI, error)
|
||||
}
|
||||
|
||||
// AzureClients is an interface for Azure-specific API clients
|
||||
@@ -468,15 +466,6 @@ func (c *cloudClients) GetAWSSession(ctx context.Context, region string, opts ..
|
||||
return c.getAWSSessionForRole(ctx, region, options)
|
||||
}
|
||||
|
||||
// GetAWSSTSClient returns AWS STS client for the specified region.
|
||||
func (c *cloudClients) GetAWSSTSClient(ctx context.Context, region string, opts ...AWSOptionsFn) (stsiface.STSAPI, error) {
|
||||
session, err := c.GetAWSSession(ctx, region, opts...)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return sts.New(session), nil
|
||||
}
|
||||
|
||||
// GetGCPIAMClient returns GCP IAM client.
|
||||
func (c *cloudClients) GetGCPIAMClient(ctx context.Context) (*gcpcredentials.IamCredentialsClient, error) {
|
||||
c.mtx.RLock()
|
||||
@@ -964,15 +953,6 @@ func (c *TestCloudClients) getAWSSessionForRegion(region string) (*awssession.Se
|
||||
})
|
||||
}
|
||||
|
||||
// GetAWSSTSClient returns AWS STS client for the specified region.
|
||||
func (c *TestCloudClients) GetAWSSTSClient(ctx context.Context, region string, opts ...AWSOptionsFn) (stsiface.STSAPI, error) {
|
||||
_, err := c.GetAWSSession(ctx, region, opts...)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return c.STS, nil
|
||||
}
|
||||
|
||||
// GetGCPIAMClient returns GCP IAM client.
|
||||
func (c *TestCloudClients) GetGCPIAMClient(ctx context.Context) (*gcpcredentials.IamCredentialsClient, error) {
|
||||
return gcpcredentials.NewIamCredentialsClient(ctx,
|
||||
|
||||
@@ -81,7 +81,7 @@ func (m *STSClientV1) AssumeRoleWithContext(ctx aws.Context, in *sts.AssumeRoleI
|
||||
expiry := time.Now().Add(60 * time.Minute)
|
||||
return &sts.AssumeRoleOutput{
|
||||
Credentials: &sts.Credentials{
|
||||
AccessKeyId: in.RoleArn,
|
||||
AccessKeyId: aws.String("FAKEACCESSKEYID"),
|
||||
SecretAccessKey: aws.String("secret"),
|
||||
SessionToken: aws.String("token"),
|
||||
Expiration: &expiry,
|
||||
|
||||
@@ -46,6 +46,7 @@ import (
|
||||
type STSClient struct {
|
||||
STSClientV1
|
||||
|
||||
Unauth bool
|
||||
// credentialProvider is only set when a chain of assumed roles is used.
|
||||
credentialProvider aws.CredentialsProvider
|
||||
// recordFn records the role and external ID when a role is assumed.
|
||||
@@ -55,17 +56,25 @@ type STSClient struct {
|
||||
}
|
||||
|
||||
func (m *STSClient) GetCallerIdentity(ctx context.Context, params *sts.GetCallerIdentityInput, optFns ...func(*sts.Options)) (*sts.GetCallerIdentityOutput, error) {
|
||||
if m.Unauth {
|
||||
return nil, trace.AccessDenied("unauthorized")
|
||||
}
|
||||
|
||||
return &sts.GetCallerIdentityOutput{
|
||||
Arn: aws.String(m.ARN),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *STSClient) AssumeRoleWithWebIdentity(ctx context.Context, in *sts.AssumeRoleWithWebIdentityInput, _ ...func(*sts.Options)) (*sts.AssumeRoleWithWebIdentityOutput, error) {
|
||||
if m.Unauth {
|
||||
return nil, trace.AccessDenied("unauthorized")
|
||||
}
|
||||
|
||||
m.record(aws.ToString(in.RoleArn), "")
|
||||
expiry := time.Now().Add(60 * time.Minute)
|
||||
return &sts.AssumeRoleWithWebIdentityOutput{
|
||||
Credentials: &ststypes.Credentials{
|
||||
AccessKeyId: in.RoleArn,
|
||||
AccessKeyId: aws.String("WEBIDENTITYFAKEACCESSKEYID"),
|
||||
SecretAccessKey: aws.String("secret"),
|
||||
SessionToken: aws.String("token"),
|
||||
Expiration: &expiry,
|
||||
@@ -74,6 +83,10 @@ func (m *STSClient) AssumeRoleWithWebIdentity(ctx context.Context, in *sts.Assum
|
||||
}
|
||||
|
||||
func (m *STSClient) AssumeRole(ctx context.Context, in *sts.AssumeRoleInput, _ ...func(*sts.Options)) (*sts.AssumeRoleOutput, error) {
|
||||
if m.Unauth {
|
||||
return nil, trace.AccessDenied("unauthorized")
|
||||
}
|
||||
|
||||
// Retrieve credentials if we have a credential provider, so that all
|
||||
// assume-role providers in a role chain are triggered to call AssumeRole.
|
||||
if m.credentialProvider != nil {
|
||||
@@ -87,7 +100,7 @@ func (m *STSClient) AssumeRole(ctx context.Context, in *sts.AssumeRoleInput, _ .
|
||||
expiry := time.Now().Add(60 * time.Minute)
|
||||
return &sts.AssumeRoleOutput{
|
||||
Credentials: &ststypes.Credentials{
|
||||
AccessKeyId: in.RoleArn,
|
||||
AccessKeyId: aws.String("FAKEACCESSKEYID"),
|
||||
SecretAccessKey: aws.String("secret"),
|
||||
SessionToken: aws.String("token"),
|
||||
Expiration: &expiry,
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -57,6 +58,11 @@ import (
|
||||
awsutils "github.com/gravitational/teleport/lib/utils/aws"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
utils.InitLoggerForTests()
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
type makeRequest func(url string, provider client.ConfigProvider, awsHost string) error
|
||||
|
||||
func s3Request(url string, provider client.ConfigProvider, awsHost string) error {
|
||||
|
||||
@@ -269,11 +269,13 @@ func (c *IAM) getAWSIdentity(ctx context.Context, database types.Database) (awsl
|
||||
return c.agentIdentity, nil
|
||||
}
|
||||
c.mu.RUnlock()
|
||||
sts, err := c.cfg.Clients.GetAWSSTSClient(ctx, meta.Region, cloud.WithAmbientCredentials())
|
||||
|
||||
awsCfg, err := c.cfg.AWSConfigProvider.GetConfig(ctx, meta.Region, awsconfig.WithAmbientCredentials())
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
awsIdentity, err := awslib.GetIdentityWithClient(ctx, sts)
|
||||
clt := c.cfg.awsClients.getSTSClient(awsCfg)
|
||||
awsIdentity, err := awslib.GetIdentityWithClientV2(ctx, clt)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
@@ -156,16 +156,15 @@ func TestAWSIAM(t *testing.T) {
|
||||
AWSConfigProvider: &mocks.AWSConfigProvider{
|
||||
STSClient: stsClient,
|
||||
},
|
||||
Clients: &clients.TestCloudClients{
|
||||
STS: &stsClient.STSClientV1,
|
||||
},
|
||||
HostID: "host-id",
|
||||
Clients: &clients.TestCloudClients{},
|
||||
HostID: "host-id",
|
||||
onProcessedTask: func(iamTask, error) {
|
||||
taskChan <- struct{}{}
|
||||
},
|
||||
awsClients: fakeAWSClients{
|
||||
iamClient: iamClient,
|
||||
rdsClient: clt,
|
||||
stsClient: stsClient,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
@@ -291,8 +290,10 @@ func TestAWSIAMNoPermissions(t *testing.T) {
|
||||
t.Cleanup(cancel)
|
||||
|
||||
// Create unauthorized mocks for AWS services.
|
||||
stsClient := &mocks.STSClientV1{
|
||||
ARN: "arn:aws:iam::123456789012:role/test-role",
|
||||
stsClient := &mocks.STSClient{
|
||||
STSClientV1: mocks.STSClientV1{
|
||||
ARN: "arn:aws:iam::123456789012:role/test-role",
|
||||
},
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -301,70 +302,64 @@ func TestAWSIAMNoPermissions(t *testing.T) {
|
||||
awsClients awsClientProvider
|
||||
}{
|
||||
{
|
||||
name: "RDS database",
|
||||
meta: types.AWS{Region: "localhost", AccountID: "123456789012", RDS: types.RDS{InstanceID: "postgres-rds", ResourceID: "postgres-rds-resource-id"}},
|
||||
clients: &clients.TestCloudClients{
|
||||
STS: stsClient,
|
||||
},
|
||||
name: "RDS database",
|
||||
meta: types.AWS{Region: "localhost", AccountID: "123456789012", RDS: types.RDS{InstanceID: "postgres-rds", ResourceID: "postgres-rds-resource-id"}},
|
||||
clients: &clients.TestCloudClients{},
|
||||
awsClients: fakeAWSClients{
|
||||
iamClient: &mocks.IAMMock{Unauth: true},
|
||||
rdsClient: &mocks.RDSClient{Unauth: true},
|
||||
stsClient: stsClient,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Aurora cluster",
|
||||
meta: types.AWS{Region: "localhost", AccountID: "123456789012", RDS: types.RDS{ClusterID: "postgres-aurora", ResourceID: "postgres-aurora-resource-id"}},
|
||||
clients: &clients.TestCloudClients{
|
||||
STS: stsClient,
|
||||
},
|
||||
name: "Aurora cluster",
|
||||
meta: types.AWS{Region: "localhost", AccountID: "123456789012", RDS: types.RDS{ClusterID: "postgres-aurora", ResourceID: "postgres-aurora-resource-id"}},
|
||||
clients: &clients.TestCloudClients{},
|
||||
awsClients: fakeAWSClients{
|
||||
iamClient: &mocks.IAMMock{Unauth: true},
|
||||
rdsClient: &mocks.RDSClient{Unauth: true},
|
||||
stsClient: stsClient,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "RDS database missing metadata",
|
||||
meta: types.AWS{Region: "localhost", RDS: types.RDS{ClusterID: "postgres-aurora"}},
|
||||
clients: &clients.TestCloudClients{
|
||||
STS: stsClient,
|
||||
},
|
||||
name: "RDS database missing metadata",
|
||||
meta: types.AWS{Region: "localhost", RDS: types.RDS{ClusterID: "postgres-aurora"}},
|
||||
clients: &clients.TestCloudClients{},
|
||||
awsClients: fakeAWSClients{
|
||||
iamClient: &mocks.IAMMock{Unauth: true},
|
||||
rdsClient: &mocks.RDSClient{Unauth: true},
|
||||
stsClient: stsClient,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Redshift cluster",
|
||||
meta: types.AWS{Region: "localhost", AccountID: "123456789012", Redshift: types.Redshift{ClusterID: "redshift-cluster-1"}},
|
||||
clients: &clients.TestCloudClients{
|
||||
STS: stsClient,
|
||||
},
|
||||
name: "Redshift cluster",
|
||||
meta: types.AWS{Region: "localhost", AccountID: "123456789012", Redshift: types.Redshift{ClusterID: "redshift-cluster-1"}},
|
||||
clients: &clients.TestCloudClients{},
|
||||
awsClients: fakeAWSClients{
|
||||
iamClient: &mocks.IAMMock{Unauth: true},
|
||||
stsClient: stsClient,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ElastiCache",
|
||||
meta: types.AWS{Region: "localhost", AccountID: "123456789012", ElastiCache: types.ElastiCache{ReplicationGroupID: "some-group"}},
|
||||
clients: &clients.TestCloudClients{
|
||||
STS: stsClient,
|
||||
},
|
||||
name: "ElastiCache",
|
||||
meta: types.AWS{Region: "localhost", AccountID: "123456789012", ElastiCache: types.ElastiCache{ReplicationGroupID: "some-group"}},
|
||||
clients: &clients.TestCloudClients{},
|
||||
awsClients: fakeAWSClients{
|
||||
iamClient: &mocks.IAMMock{Unauth: true},
|
||||
stsClient: stsClient,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "IAM UnmodifiableEntityException",
|
||||
meta: types.AWS{Region: "localhost", AccountID: "123456789012", Redshift: types.Redshift{ClusterID: "redshift-cluster-1"}},
|
||||
clients: &clients.TestCloudClients{
|
||||
STS: stsClient,
|
||||
},
|
||||
name: "IAM UnmodifiableEntityException",
|
||||
meta: types.AWS{Region: "localhost", AccountID: "123456789012", Redshift: types.Redshift{ClusterID: "redshift-cluster-1"}},
|
||||
clients: &clients.TestCloudClients{},
|
||||
awsClients: fakeAWSClients{
|
||||
iamClient: &mocks.IAMMock{
|
||||
Error: &iamtypes.UnmodifiableEntityException{
|
||||
Message: aws.String("Cannot perform the operation on the protected role"),
|
||||
},
|
||||
},
|
||||
stsClient: stsClient,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -377,11 +372,7 @@ func TestAWSIAMNoPermissions(t *testing.T) {
|
||||
Clients: test.clients,
|
||||
HostID: "host-id",
|
||||
AWSConfigProvider: &mocks.AWSConfigProvider{
|
||||
STSClient: &mocks.STSClient{
|
||||
STSClientV1: mocks.STSClientV1{
|
||||
ARN: "arn:aws:iam::123456789012:role/test-role",
|
||||
},
|
||||
},
|
||||
STSClient: stsClient,
|
||||
},
|
||||
awsClients: test.awsClients,
|
||||
})
|
||||
|
||||
@@ -36,6 +36,7 @@ import (
|
||||
redshifttypes "github.com/aws/aws-sdk-go-v2/service/redshift/types"
|
||||
rss "github.com/aws/aws-sdk-go-v2/service/redshiftserverless"
|
||||
rsstypes "github.com/aws/aws-sdk-go-v2/service/redshiftserverless/types"
|
||||
"github.com/aws/aws-sdk-go-v2/service/sts"
|
||||
"github.com/gravitational/trace"
|
||||
|
||||
"github.com/gravitational/teleport"
|
||||
@@ -93,6 +94,11 @@ type rssClient interface {
|
||||
GetWorkgroup(ctx context.Context, params *rss.GetWorkgroupInput, optFns ...func(*rss.Options)) (*rss.GetWorkgroupOutput, error)
|
||||
}
|
||||
|
||||
// stsClient defines a subset of the AWS STS client API.
|
||||
type stsClient interface {
|
||||
GetCallerIdentity(ctx context.Context, params *sts.GetCallerIdentityInput, optFns ...func(*sts.Options)) (*sts.GetCallerIdentityOutput, error)
|
||||
}
|
||||
|
||||
// awsClientProvider is an AWS SDK client provider.
|
||||
type awsClientProvider interface {
|
||||
getElastiCacheClient(cfg aws.Config, optFns ...func(*elasticache.Options)) elasticacheClient
|
||||
@@ -102,6 +108,7 @@ type awsClientProvider interface {
|
||||
getRDSClient(cfg aws.Config, optFns ...func(*rds.Options)) rdsClient
|
||||
getRedshiftClient(cfg aws.Config, optFns ...func(*redshift.Options)) redshiftClient
|
||||
getRedshiftServerlessClient(cfg aws.Config, optFns ...func(*rss.Options)) rssClient
|
||||
getSTSClient(cfg aws.Config, optFns ...func(*sts.Options)) stsClient
|
||||
}
|
||||
|
||||
type defaultAWSClients struct{}
|
||||
@@ -134,6 +141,10 @@ func (defaultAWSClients) getRedshiftServerlessClient(cfg aws.Config, optFns ...f
|
||||
return rss.NewFromConfig(cfg, optFns...)
|
||||
}
|
||||
|
||||
func (defaultAWSClients) getSTSClient(cfg aws.Config, optFns ...func(*sts.Options)) stsClient {
|
||||
return sts.NewFromConfig(cfg, optFns...)
|
||||
}
|
||||
|
||||
// MetadataConfig is the cloud metadata service config.
|
||||
type MetadataConfig struct {
|
||||
// Clients is an interface for retrieving cloud clients.
|
||||
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
redshifttypes "github.com/aws/aws-sdk-go-v2/service/redshift/types"
|
||||
rss "github.com/aws/aws-sdk-go-v2/service/redshiftserverless"
|
||||
rsstypes "github.com/aws/aws-sdk-go-v2/service/redshiftserverless/types"
|
||||
"github.com/aws/aws-sdk-go-v2/service/sts"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/gravitational/teleport/api/types"
|
||||
@@ -511,6 +512,7 @@ type fakeAWSClients struct {
|
||||
rdsClient rdsClient
|
||||
redshiftClient redshiftClient
|
||||
rssClient rssClient
|
||||
stsClient stsClient
|
||||
}
|
||||
|
||||
func (f fakeAWSClients) getElastiCacheClient(cfg aws.Config, optFns ...func(*elasticache.Options)) elasticacheClient {
|
||||
@@ -540,3 +542,7 @@ func (f fakeAWSClients) getRedshiftClient(aws.Config, ...func(*redshift.Options)
|
||||
func (f fakeAWSClients) getRedshiftServerlessClient(aws.Config, ...func(*rss.Options)) rssClient {
|
||||
return f.rssClient
|
||||
}
|
||||
|
||||
func (f fakeAWSClients) getSTSClient(cfg aws.Config, optFns ...func(*sts.Options)) stsClient {
|
||||
return f.stsClient
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ func NewDiscoveryResourceChecker(cfg DiscoveryResourceCheckerConfig) (DiscoveryR
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
credentialsChecker, err := newCrednentialsChecker(cfg)
|
||||
credentialsChecker, err := newCredentialsChecker(cfg)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import (
|
||||
"github.com/gravitational/teleport/api/types"
|
||||
"github.com/gravitational/teleport/lib/cloud"
|
||||
"github.com/gravitational/teleport/lib/cloud/aws"
|
||||
"github.com/gravitational/teleport/lib/cloud/awsconfig"
|
||||
"github.com/gravitational/teleport/lib/services"
|
||||
"github.com/gravitational/teleport/lib/utils"
|
||||
)
|
||||
@@ -40,13 +41,15 @@ import (
|
||||
// Note that this checker warns the user with suggestions on how to configure
|
||||
// the credentials correctly instead of returning errors.
|
||||
type credentialsChecker struct {
|
||||
cloudClients cloud.Clients
|
||||
resourceMatchers []services.ResourceMatcher
|
||||
logger *slog.Logger
|
||||
cache *utils.FnCache
|
||||
awsConfigProvider awsconfig.Provider
|
||||
awsClients awsClientProvider
|
||||
azureClients cloud.AzureClients
|
||||
resourceMatchers []services.ResourceMatcher
|
||||
logger *slog.Logger
|
||||
cache *utils.FnCache
|
||||
}
|
||||
|
||||
func newCrednentialsChecker(cfg DiscoveryResourceCheckerConfig) (*credentialsChecker, error) {
|
||||
func newCredentialsChecker(cfg DiscoveryResourceCheckerConfig) (*credentialsChecker, error) {
|
||||
cache, err := utils.NewFnCache(utils.FnCacheConfig{
|
||||
TTL: 10 * time.Minute,
|
||||
Context: cfg.Context,
|
||||
@@ -56,10 +59,12 @@ func newCrednentialsChecker(cfg DiscoveryResourceCheckerConfig) (*credentialsChe
|
||||
}
|
||||
|
||||
return &credentialsChecker{
|
||||
cloudClients: cfg.Clients,
|
||||
resourceMatchers: cfg.ResourceMatchers,
|
||||
logger: cfg.Logger,
|
||||
cache: cache,
|
||||
awsConfigProvider: cfg.AWSConfigProvider,
|
||||
awsClients: defaultAWSClients{},
|
||||
azureClients: cfg.Clients,
|
||||
resourceMatchers: cfg.ResourceMatchers,
|
||||
logger: cfg.Logger,
|
||||
cache: cache,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -111,18 +116,19 @@ func (c *credentialsChecker) getAWSIdentity(ctx context.Context, meta *types.AWS
|
||||
}
|
||||
|
||||
identity, err := utils.FnCacheGet(ctx, c.cache, types.CloudAWS, func(ctx context.Context) (aws.Identity, error) {
|
||||
client, err := c.cloudClients.GetAWSSTSClient(ctx, "", cloud.WithAmbientCredentials())
|
||||
awsCfg, err := c.awsConfigProvider.GetConfig(ctx, meta.Region, awsconfig.WithAmbientCredentials())
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return aws.GetIdentityWithClient(ctx, client)
|
||||
client := c.awsClients.getSTSClient(awsCfg)
|
||||
return aws.GetIdentityWithClientV2(ctx, client)
|
||||
})
|
||||
return identity, trace.Wrap(err)
|
||||
}
|
||||
|
||||
func (c *credentialsChecker) checkAzure(ctx context.Context, database types.Database) {
|
||||
allSubIDs, err := utils.FnCacheGet(ctx, c.cache, types.CloudAzure, func(ctx context.Context) ([]string, error) {
|
||||
client, err := c.cloudClients.GetAzureSubscriptionClient()
|
||||
client, err := c.azureClients.GetAzureSubscriptionClient()
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ import (
|
||||
rdsauth "github.com/aws/aws-sdk-go-v2/feature/rds/auth"
|
||||
"github.com/aws/aws-sdk-go-v2/service/redshift"
|
||||
rss "github.com/aws/aws-sdk-go-v2/service/redshiftserverless"
|
||||
"github.com/aws/aws-sdk-go-v2/service/sts"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
v4 "github.com/aws/aws-sdk-go/aws/signer/v4"
|
||||
"github.com/gravitational/trace"
|
||||
@@ -135,10 +136,16 @@ type rssClient interface {
|
||||
GetCredentials(context.Context, *rss.GetCredentialsInput, ...func(*rss.Options)) (*rss.GetCredentialsOutput, error)
|
||||
}
|
||||
|
||||
// stsClient defines a subset of the AWS STS client API.
|
||||
type stsClient interface {
|
||||
GetCallerIdentity(ctx context.Context, params *sts.GetCallerIdentityInput, optFns ...func(*sts.Options)) (*sts.GetCallerIdentityOutput, error)
|
||||
}
|
||||
|
||||
// awsClientProvider is an AWS SDK client provider.
|
||||
type awsClientProvider interface {
|
||||
getRedshiftClient(cfg aws.Config, optFns ...func(*redshift.Options)) redshiftClient
|
||||
getRedshiftServerlessClient(cfg aws.Config, optFns ...func(*rss.Options)) rssClient
|
||||
getSTSClient(cfg aws.Config, optFns ...func(*sts.Options)) stsClient
|
||||
}
|
||||
|
||||
type defaultAWSClients struct{}
|
||||
@@ -151,6 +158,10 @@ func (defaultAWSClients) getRedshiftServerlessClient(cfg aws.Config, optFns ...f
|
||||
return rss.NewFromConfig(cfg, optFns...)
|
||||
}
|
||||
|
||||
func (defaultAWSClients) getSTSClient(cfg aws.Config, optFns ...func(*sts.Options)) stsClient {
|
||||
return sts.NewFromConfig(cfg, optFns...)
|
||||
}
|
||||
|
||||
// AuthConfig is the database access authenticator configuration.
|
||||
type AuthConfig struct {
|
||||
// AuthClient is the cluster auth client.
|
||||
@@ -1141,12 +1152,13 @@ func (a *dbAuth) buildAWSRoleARNFromDatabaseUser(ctx context.Context, database t
|
||||
awsAccountID = assumeRoleARN.AccountID
|
||||
default:
|
||||
a.cfg.Logger.DebugContext(ctx, "Fetching AWS Account ID to build role ARN")
|
||||
stsClient, err := a.cfg.Clients.GetAWSSTSClient(ctx, dbAWS.Region, cloud.WithAmbientCredentials())
|
||||
awsCfg, err := a.cfg.AWSConfigProvider.GetConfig(ctx, dbAWS.Region, awsconfig.WithAmbientCredentials())
|
||||
if err != nil {
|
||||
return "", trace.Wrap(err)
|
||||
}
|
||||
clt := a.cfg.awsClients.getSTSClient(awsCfg)
|
||||
|
||||
identity, err := awslib.GetIdentityWithClient(ctx, stsClient)
|
||||
identity, err := awslib.GetIdentityWithClientV2(ctx, clt)
|
||||
if err != nil {
|
||||
return "", trace.Wrap(err)
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/aws-sdk-go-v2/service/redshift"
|
||||
rss "github.com/aws/aws-sdk-go-v2/service/redshiftserverless"
|
||||
"github.com/aws/aws-sdk-go-v2/service/sts"
|
||||
"github.com/gravitational/trace"
|
||||
"github.com/jonboulle/clockwork"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -591,7 +592,7 @@ func TestAuthGetAWSTokenWithAssumedRole(t *testing.T) {
|
||||
require.Equal(t, "some-user", query.Get("User"))
|
||||
require.Equal(t, "host", query.Get("X-Amz-SignedHeaders"))
|
||||
require.Equal(t, "token", query.Get("X-Amz-Security-Token"))
|
||||
require.Equal(t, "arn:aws:iam::123456789012:role/RedisRole/20010203/ca-central-1/elasticache/aws4_request",
|
||||
require.Equal(t, "FAKEACCESSKEYID/20010203/ca-central-1/elasticache/aws4_request",
|
||||
query.Get("X-Amz-Credential"))
|
||||
},
|
||||
checkSTS: func(t *testing.T, stsMock *mocks.STSClient) {
|
||||
@@ -622,6 +623,7 @@ func TestAuthGetAWSTokenWithAssumedRole(t *testing.T) {
|
||||
rssClient: &mocks.RedshiftServerlessClient{
|
||||
GetCredentialsOutput: mocks.RedshiftServerlessGetCredentialsOutput("IAM:some-user", "some-password", clock),
|
||||
},
|
||||
stsClient: fakeSTS,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
@@ -643,58 +645,55 @@ func TestGetAWSIAMCreds(t *testing.T) {
|
||||
|
||||
for name, tt := range map[string]struct {
|
||||
db types.Database
|
||||
stsMock *mocks.STSClientV1
|
||||
stsMock *mocks.STSClient
|
||||
username string
|
||||
expectedKeyId string
|
||||
expectedAssumedRoles []string
|
||||
expectedExternalIDs []string
|
||||
expectErr require.ErrorAssertionFunc
|
||||
wantErrContains string
|
||||
}{
|
||||
"username is full role ARN": {
|
||||
db: newMongoAtlasDatabase(t, types.AWS{}),
|
||||
stsMock: &mocks.STSClientV1{},
|
||||
stsMock: &mocks.STSClient{},
|
||||
username: "arn:aws:iam::123456789012:role/role-name",
|
||||
expectedKeyId: "arn:aws:iam::123456789012:role/role-name",
|
||||
expectedAssumedRoles: []string{"arn:aws:iam::123456789012:role/role-name"},
|
||||
expectedExternalIDs: []string{""},
|
||||
expectErr: require.NoError,
|
||||
},
|
||||
"username is partial role ARN": {
|
||||
db: newMongoAtlasDatabase(t, types.AWS{}),
|
||||
stsMock: &mocks.STSClientV1{
|
||||
// This is the role returned by the STS GetCallerIdentity.
|
||||
ARN: "arn:aws:iam::222222222222:role/teleport-service-role",
|
||||
stsMock: &mocks.STSClient{
|
||||
STSClientV1: mocks.STSClientV1{
|
||||
// This is the role returned by the STS GetCallerIdentity.
|
||||
ARN: "arn:aws:iam::222222222222:role/teleport-service-role",
|
||||
},
|
||||
},
|
||||
username: "role/role-name",
|
||||
expectedKeyId: "arn:aws:iam::222222222222:role/role-name",
|
||||
expectedAssumedRoles: []string{"arn:aws:iam::222222222222:role/role-name"},
|
||||
expectedExternalIDs: []string{""},
|
||||
expectErr: require.NoError,
|
||||
},
|
||||
"unable to fetch account ID": {
|
||||
db: newMongoAtlasDatabase(t, types.AWS{}),
|
||||
stsMock: &mocks.STSClientV1{
|
||||
ARN: "",
|
||||
stsMock: &mocks.STSClient{
|
||||
Unauth: true,
|
||||
},
|
||||
username: "role/role-name",
|
||||
expectErr: require.Error,
|
||||
username: "role/role-name",
|
||||
wantErrContains: "unauthorized",
|
||||
},
|
||||
"chained IAM role": {
|
||||
db: newMongoAtlasDatabase(t, types.AWS{
|
||||
ExternalID: "123123",
|
||||
AssumeRoleARN: "arn:aws:iam::222222222222:role/teleport-service-role-external",
|
||||
}),
|
||||
stsMock: &mocks.STSClientV1{
|
||||
ARN: "arn:aws:iam::111111111111:role/teleport-service-role",
|
||||
stsMock: &mocks.STSClient{
|
||||
STSClientV1: mocks.STSClientV1{
|
||||
ARN: "arn:aws:iam::111111111111:role/teleport-service-role",
|
||||
},
|
||||
},
|
||||
username: "role/role-name",
|
||||
expectedKeyId: "arn:aws:iam::222222222222:role/role-name",
|
||||
username: "role/role-name",
|
||||
expectedAssumedRoles: []string{
|
||||
"arn:aws:iam::222222222222:role/teleport-service-role-external",
|
||||
"arn:aws:iam::222222222222:role/role-name",
|
||||
},
|
||||
expectedExternalIDs: []string{"123123", ""},
|
||||
expectErr: require.NoError,
|
||||
},
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
@@ -703,15 +702,22 @@ func TestGetAWSIAMCreds(t *testing.T) {
|
||||
AuthClient: new(authClientMock),
|
||||
AccessPoint: new(accessPointMock),
|
||||
Clients: &cloud.TestCloudClients{
|
||||
STS: tt.stsMock,
|
||||
STS: &tt.stsMock.STSClientV1,
|
||||
},
|
||||
AWSConfigProvider: &mocks.AWSConfigProvider{},
|
||||
awsClients: fakeAWSClients{
|
||||
stsClient: tt.stsMock,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
keyId, _, _, err := auth.GetAWSIAMCreds(ctx, tt.db, tt.username)
|
||||
tt.expectErr(t, err)
|
||||
require.Equal(t, tt.expectedKeyId, keyId)
|
||||
if tt.wantErrContains != "" {
|
||||
require.Error(t, err)
|
||||
require.ErrorContains(t, err, tt.wantErrContains)
|
||||
return
|
||||
}
|
||||
require.Equal(t, "FAKEACCESSKEYID", keyId)
|
||||
require.ElementsMatch(t, tt.expectedAssumedRoles, tt.stsMock.GetAssumedRoleARNs())
|
||||
require.ElementsMatch(t, tt.expectedExternalIDs, tt.stsMock.GetAssumedRoleExternalIDs())
|
||||
})
|
||||
@@ -1025,6 +1031,7 @@ func (m *imdsMock) GetType() types.InstanceMetadataType {
|
||||
type fakeAWSClients struct {
|
||||
redshiftClient redshiftClient
|
||||
rssClient rssClient
|
||||
stsClient stsClient
|
||||
}
|
||||
|
||||
func (f fakeAWSClients) getRedshiftClient(aws.Config, ...func(*redshift.Options)) redshiftClient {
|
||||
@@ -1034,3 +1041,7 @@ func (f fakeAWSClients) getRedshiftClient(aws.Config, ...func(*redshift.Options)
|
||||
func (f fakeAWSClients) getRedshiftServerlessClient(cfg aws.Config, optFns ...func(*rss.Options)) rssClient {
|
||||
return f.rssClient
|
||||
}
|
||||
|
||||
func (f fakeAWSClients) getSTSClient(cfg aws.Config, optFns ...func(*sts.Options)) stsClient {
|
||||
return f.stsClient
|
||||
}
|
||||
|
||||
@@ -29,8 +29,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go-v2/service/iam"
|
||||
"github.com/aws/aws-sdk-go-v2/service/rds"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/service/sts"
|
||||
"github.com/aws/aws-sdk-go-v2/service/sts"
|
||||
"github.com/gravitational/trace"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
@@ -106,6 +105,11 @@ type iamClient interface {
|
||||
ListSAMLProviders(context.Context, *iam.ListSAMLProvidersInput, ...func(*iam.Options)) (*iam.ListSAMLProvidersOutput, error)
|
||||
}
|
||||
|
||||
// stsClient defines a subset of the AWS STS client API.
|
||||
type stsClient interface {
|
||||
GetCallerIdentity(ctx context.Context, params *sts.GetCallerIdentityInput, optFns ...func(*sts.Options)) (*sts.GetCallerIdentityOutput, error)
|
||||
}
|
||||
|
||||
// awsClientProvider provides AWS service API clients.
|
||||
type awsClientProvider interface {
|
||||
// getIAMClient provides an [iamClient].
|
||||
@@ -114,6 +118,8 @@ type awsClientProvider interface {
|
||||
getRDSClient(cfg aws.Config, optFns ...func(*rds.Options)) rdsClient
|
||||
// getS3Client provides an [s3Client].
|
||||
getS3Client(cfg aws.Config, optFns ...func(*s3.Options)) s3Client
|
||||
// getSTSClient provides an [stsClient].
|
||||
getSTSClient(cfg aws.Config, optFns ...func(*sts.Options)) stsClient
|
||||
}
|
||||
|
||||
type defaultAWSClients struct{}
|
||||
@@ -130,6 +136,10 @@ func (defaultAWSClients) getS3Client(cfg aws.Config, optFns ...func(*s3.Options)
|
||||
return s3.NewFromConfig(cfg, optFns...)
|
||||
}
|
||||
|
||||
func (defaultAWSClients) getSTSClient(cfg aws.Config, optFns ...func(*sts.Options)) stsClient {
|
||||
return sts.NewFromConfig(cfg, optFns...)
|
||||
}
|
||||
|
||||
// AssumeRole is the configuration for assuming an AWS role.
|
||||
type AssumeRole struct {
|
||||
// RoleARN is the ARN of the role to assume.
|
||||
@@ -355,36 +365,9 @@ func (a *Fetcher) poll(ctx context.Context, features Features) (*Resources, erro
|
||||
return result, trace.NewAggregate(errs...)
|
||||
}
|
||||
|
||||
// getAWSOptions returns a list of AWSAssumeRoleOptionFn to be used when
|
||||
// creating AWS clients.
|
||||
func (a *Fetcher) getAWSOptions() []cloud.AWSOptionsFn {
|
||||
opts := []cloud.AWSOptionsFn{
|
||||
cloud.WithCredentialsMaybeIntegration(a.Config.Integration),
|
||||
}
|
||||
|
||||
if a.Config.AssumeRole != nil {
|
||||
opts = append(opts, cloud.WithAssumeRole(a.Config.AssumeRole.RoleARN, a.Config.AssumeRole.ExternalID))
|
||||
}
|
||||
const maxRetries = 10
|
||||
opts = append(opts,
|
||||
cloud.WithMaxRetries(maxRetries),
|
||||
cloud.WithRetryer(
|
||||
client.DefaultRetryer{
|
||||
NumMaxRetries: maxRetries,
|
||||
MinRetryDelay: time.Second,
|
||||
MinThrottleDelay: time.Second,
|
||||
MaxRetryDelay: 300 * time.Second,
|
||||
MaxThrottleDelay: 300 * time.Second,
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
return opts
|
||||
}
|
||||
|
||||
// getAWSV2Options returns a list of options to be used when
|
||||
// getAWSOptions returns a list of options to be used when
|
||||
// creating AWS clients with the v2 sdk.
|
||||
func (a *Fetcher) getAWSV2Options() []awsconfig.OptionsFn {
|
||||
func (a *Fetcher) getAWSOptions() []awsconfig.OptionsFn {
|
||||
opts := []awsconfig.OptionsFn{
|
||||
awsconfig.WithCredentialsMaybeIntegration(a.Config.Integration),
|
||||
}
|
||||
@@ -404,7 +387,7 @@ func (a *Fetcher) getAWSV2Options() []awsconfig.OptionsFn {
|
||||
}
|
||||
|
||||
func (a *Fetcher) getAccountId(ctx context.Context) (string, error) {
|
||||
stsClient, err := a.CloudClients.GetAWSSTSClient(
|
||||
awsCfg, err := a.AWSConfigProvider.GetConfig(
|
||||
ctx,
|
||||
"", /* region is empty because groups are global */
|
||||
a.getAWSOptions()...,
|
||||
@@ -412,9 +395,10 @@ func (a *Fetcher) getAccountId(ctx context.Context) (string, error) {
|
||||
if err != nil {
|
||||
return "", trace.Wrap(err)
|
||||
}
|
||||
stsClient := a.awsClients.getSTSClient(awsCfg)
|
||||
|
||||
input := &sts.GetCallerIdentityInput{}
|
||||
req, err := stsClient.GetCallerIdentityWithContext(ctx, input)
|
||||
req, err := stsClient.GetCallerIdentity(ctx, input)
|
||||
if err != nil {
|
||||
return "", trace.Wrap(err)
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ func (a *Fetcher) fetchAWSEC2Instances(ctx context.Context) ([]*accessgraphv1alp
|
||||
return h.Region == region && h.AccountId == a.AccountID
|
||||
},
|
||||
)
|
||||
ec2Client, err := a.GetEC2Client(ctx, region, a.getAWSV2Options()...)
|
||||
ec2Client, err := a.GetEC2Client(ctx, region, a.getAWSOptions()...)
|
||||
if err != nil {
|
||||
collectHosts(prevIterationEc2, trace.Wrap(err))
|
||||
return nil
|
||||
@@ -155,7 +155,7 @@ func (a *Fetcher) fetchInstanceProfiles(ctx context.Context) ([]*accessgraphv1al
|
||||
awsCfg, err := a.AWSConfigProvider.GetConfig(
|
||||
ctx,
|
||||
"", /* region is empty because users and groups are global */
|
||||
a.getAWSV2Options()...,
|
||||
a.getAWSOptions()...,
|
||||
)
|
||||
if err != nil {
|
||||
return existing, trace.Wrap(err)
|
||||
|
||||
@@ -103,7 +103,7 @@ func (a *Fetcher) fetchAWSSEKSClusters(ctx context.Context) (fetchAWSEKSClusters
|
||||
for _, region := range a.Regions {
|
||||
region := region
|
||||
eG.Go(func() error {
|
||||
eksClient, err := a.GetEKSClient(ctx, region, a.getAWSV2Options()...)
|
||||
eksClient, err := a.GetEKSClient(ctx, region, a.getAWSOptions()...)
|
||||
if err != nil {
|
||||
collectClusters(nil, nil, nil, trace.Wrap(err))
|
||||
return nil
|
||||
|
||||
@@ -94,7 +94,7 @@ func (a *Fetcher) fetchGroups(ctx context.Context) ([]*accessgraphv1alpha.AWSGro
|
||||
awsCfg, err := a.AWSConfigProvider.GetConfig(
|
||||
ctx,
|
||||
"", /* region is empty because groups are global */
|
||||
a.getAWSV2Options()...,
|
||||
a.getAWSOptions()...,
|
||||
)
|
||||
if err != nil {
|
||||
return a.lastResult.Groups, trace.Wrap(err)
|
||||
@@ -144,7 +144,7 @@ func (a *Fetcher) fetchGroupInlinePolicies(ctx context.Context, group *accessgra
|
||||
awsCfg, err := a.AWSConfigProvider.GetConfig(
|
||||
ctx,
|
||||
"", /* region is empty because users and groups are global */
|
||||
a.getAWSV2Options()...,
|
||||
a.getAWSOptions()...,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
@@ -201,7 +201,7 @@ func (a *Fetcher) fetchGroupAttachedPolicies(ctx context.Context, group *accessg
|
||||
awsCfg, err := a.AWSConfigProvider.GetConfig(
|
||||
ctx,
|
||||
"", /* region is empty because users and groups are global */
|
||||
a.getAWSV2Options()...,
|
||||
a.getAWSOptions()...,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
|
||||
@@ -37,7 +37,7 @@ func (a *Fetcher) pollAWSSAMLProviders(ctx context.Context, result *Resources, c
|
||||
awsCfg, err := a.AWSConfigProvider.GetConfig(
|
||||
ctx,
|
||||
"", /* region is empty because saml providers are global */
|
||||
a.getAWSV2Options()...,
|
||||
a.getAWSOptions()...,
|
||||
)
|
||||
if err != nil {
|
||||
collectErr(trace.Wrap(err, "failed to get AWS IAM client"))
|
||||
@@ -138,7 +138,7 @@ func (a *Fetcher) pollAWSOIDCProviders(ctx context.Context, result *Resources, c
|
||||
awsCfg, err := a.AWSConfigProvider.GetConfig(
|
||||
ctx,
|
||||
"", /* region is empty because oidc providers are global */
|
||||
a.getAWSV2Options()...,
|
||||
a.getAWSOptions()...,
|
||||
)
|
||||
if err != nil {
|
||||
collectErr(trace.Wrap(err, "failed to get AWS IAM client"))
|
||||
|
||||
@@ -53,7 +53,7 @@ func (a *Fetcher) fetchPolicies(ctx context.Context) ([]*accessgraphv1alpha.AWSP
|
||||
awsCfg, err := a.AWSConfigProvider.GetConfig(
|
||||
ctx,
|
||||
"", /* region is empty because users and groups are global */
|
||||
a.getAWSV2Options()...,
|
||||
a.getAWSOptions()...,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
|
||||
@@ -81,7 +81,7 @@ func (a *Fetcher) fetchAWSRDSDatabases(ctx context.Context) (
|
||||
for _, region := range a.Regions {
|
||||
region := region
|
||||
eG.Go(func() error {
|
||||
awsCfg, err := a.AWSConfigProvider.GetConfig(ctx, region, a.getAWSV2Options()...)
|
||||
awsCfg, err := a.AWSConfigProvider.GetConfig(ctx, region, a.getAWSOptions()...)
|
||||
if err != nil {
|
||||
collectDBs(nil, trace.Wrap(err))
|
||||
return nil
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go-v2/service/rds"
|
||||
rdstypes "github.com/aws/aws-sdk-go-v2/service/rds/types"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
"github.com/aws/aws-sdk-go-v2/service/sts"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/testing/protocmp"
|
||||
@@ -221,6 +222,7 @@ type fakeAWSClients struct {
|
||||
iamClient iamClient
|
||||
rdsClient rdsClient
|
||||
s3Client s3Client
|
||||
stsClient stsClient
|
||||
}
|
||||
|
||||
func (f fakeAWSClients) getIAMClient(cfg aws.Config, optFns ...func(*iam.Options)) iamClient {
|
||||
@@ -234,3 +236,7 @@ func (f fakeAWSClients) getRDSClient(cfg aws.Config, optFns ...func(*rds.Options
|
||||
func (f fakeAWSClients) getS3Client(cfg aws.Config, optFns ...func(*s3.Options)) s3Client {
|
||||
return f.s3Client
|
||||
}
|
||||
|
||||
func (f fakeAWSClients) getSTSClient(cfg aws.Config, optFns ...func(*sts.Options)) stsClient {
|
||||
return f.stsClient
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ func (a *Fetcher) fetchRoles(ctx context.Context) ([]*accessgraphv1alpha.AWSRole
|
||||
awsCfg, err := a.AWSConfigProvider.GetConfig(
|
||||
ctx,
|
||||
"", /* region is empty because roles are global */
|
||||
a.getAWSV2Options()...,
|
||||
a.getAWSOptions()...,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
@@ -126,7 +126,7 @@ func (a *Fetcher) fetchRoleInlinePolicies(ctx context.Context, role *accessgraph
|
||||
awsCfg, err := a.AWSConfigProvider.GetConfig(
|
||||
ctx,
|
||||
"", /* region is empty because users and groups are global */
|
||||
a.getAWSV2Options()...,
|
||||
a.getAWSOptions()...,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
@@ -175,7 +175,7 @@ func (a *Fetcher) fetchRoleAttachedPolicies(ctx context.Context, role *accessgra
|
||||
awsCfg, err := a.AWSConfigProvider.GetConfig(
|
||||
ctx,
|
||||
"", /* region is empty because users and groups are global */
|
||||
a.getAWSV2Options()...,
|
||||
a.getAWSOptions()...,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
|
||||
@@ -218,7 +218,7 @@ func (a *Fetcher) getS3BucketDetails(ctx context.Context, bucket s3types.Bucket,
|
||||
var errs []error
|
||||
var details s3Details
|
||||
|
||||
awsCfg, err := a.AWSConfigProvider.GetConfig(ctx, bucketRegion, a.getAWSV2Options()...)
|
||||
awsCfg, err := a.AWSConfigProvider.GetConfig(ctx, bucketRegion, a.getAWSOptions()...)
|
||||
if err != nil {
|
||||
errs = append(errs,
|
||||
trace.Wrap(err, "failed to create s3 client for bucket %q", aws.ToString(bucket.Name)),
|
||||
@@ -300,7 +300,7 @@ func (a *Fetcher) listS3Buckets(ctx context.Context) ([]s3types.Bucket, func(*st
|
||||
}
|
||||
|
||||
// use any region to list buckets
|
||||
awsCfg, err := a.AWSConfigProvider.GetConfig(ctx, region, a.getAWSV2Options()...)
|
||||
awsCfg, err := a.AWSConfigProvider.GetConfig(ctx, region, a.getAWSOptions()...)
|
||||
if err != nil {
|
||||
return nil, nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ func (a *Fetcher) fetchUsers(ctx context.Context) ([]*accessgraphv1alpha.AWSUser
|
||||
awsCfg, err := a.AWSConfigProvider.GetConfig(
|
||||
ctx,
|
||||
"", /* region is empty because users are global */
|
||||
a.getAWSV2Options()...,
|
||||
a.getAWSOptions()...,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
@@ -174,7 +174,7 @@ func (a *Fetcher) fetchUserInlinePolicies(ctx context.Context, user *accessgraph
|
||||
awsCfg, err := a.AWSConfigProvider.GetConfig(
|
||||
ctx,
|
||||
"", /* region is empty because users and groups are global */
|
||||
a.getAWSV2Options()...,
|
||||
a.getAWSOptions()...,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
@@ -231,7 +231,7 @@ func (a *Fetcher) fetchUserAttachedPolicies(ctx context.Context, user *accessgra
|
||||
awsCfg, err := a.AWSConfigProvider.GetConfig(
|
||||
ctx,
|
||||
"", /* region is empty because users and groups are global */
|
||||
a.getAWSV2Options()...,
|
||||
a.getAWSOptions()...,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
@@ -280,7 +280,7 @@ func (a *Fetcher) fetchGroupsForUser(ctx context.Context, user *accessgraphv1alp
|
||||
awsCfg, err := a.AWSConfigProvider.GetConfig(
|
||||
ctx,
|
||||
"", /* region is empty because users and groups are global */
|
||||
a.getAWSV2Options()...,
|
||||
a.getAWSOptions()...,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
|
||||
Reference in New Issue
Block a user