Skip to content

Commit

Permalink
Don't force the use of FIPS endpoints for DynamoDB Streams and Applic…
Browse files Browse the repository at this point in the history
…ation Auto Scaling

DynamoDB Streams and Application Auto Scaling do not currently have FIPS endpoints in
non-GovCloud, leading to invalid endpoints for FIPS users running in AWS Standard.

See also: https://aws.amazon.com/compliance/fips/#FIPS_Endpoints_by_Service

Regression from #34170.

Fixes #34804.

Additionally, clean-up a few more AWS session initiations to be consistent and clear.
  • Loading branch information
reedloden authored and github-actions committed Nov 29, 2023
1 parent eb077a7 commit 1e7d338
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 58 deletions.
4 changes: 4 additions & 0 deletions integration/ec2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (

"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/sts"
"github.com/gravitational/trace"
Expand Down Expand Up @@ -141,6 +142,9 @@ func getIID(ctx context.Context, t *testing.T) imds.InstanceIdentityDocument {
func getCallerIdentity(t *testing.T) *sts.GetCallerIdentityOutput {
sess, err := session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigEnable,
Config: aws.Config{
EC2MetadataEnableFallback: aws.Bool(false),
},
})
require.NoError(t, err)
stsService := sts.New(sess)
Expand Down
6 changes: 3 additions & 3 deletions lib/auth/join_iam.go
Original file line number Diff line number Diff line change
Expand Up @@ -472,11 +472,11 @@ func newSTSClient(ctx context.Context, cfg *stsIdentityRequestConfig) (*sts.STS,
if cfg.fipsEndpointOption == endpoints.FIPSEndpointStateEnabled &&
!slices.Contains(validSTSEndpoints, strings.TrimPrefix(stsClient.Endpoint, "https://")) {
// The AWS SDK will generate invalid endpoints when attempting to
// resolve the FIPS endpoint for a region which does not have one.
// resolve the FIPS endpoint for a region that does not have one.
// In this case, try to use the FIPS endpoint in us-east-1. This should
// work for all regions in the standard partition. In GovCloud we should
// work for all regions in the standard partition. In GovCloud, we should
// not hit this because all regional endpoints support FIPS. In China or
// other partitions this will fail and FIPS mode will not be supported.
// other partitions, this will fail, and FIPS mode will not be supported.
log.Infof("AWS SDK resolved FIPS STS endpoint %s, which does not appear to be valid. "+
"Attempting to use the FIPS STS endpoint for us-east-1.",
stsClient.Endpoint)
Expand Down
37 changes: 21 additions & 16 deletions lib/backend/dynamo/dynamodbbk.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,32 +235,30 @@ func New(ctx context.Context, params backend.Params) (*Backend, error) {
clock: clockwork.NewRealClock(),
buf: buf,
}

// determine if the FIPS endpoints should be used
useFIPSEndpoint := endpoints.FIPSEndpointStateUnset
if modules.GetModules().IsBoringBinary() {
useFIPSEndpoint = endpoints.FIPSEndpointStateEnabled
}
// create an AWS session using default SDK behavior, i.e. it will interpret
// the environment and ~/.aws directory just like an AWS CLI tool would:

awsConfig := aws.Config{
EC2MetadataEnableFallback: aws.Bool(false),
}
if cfg.Region != "" {
awsConfig.Region = aws.String(cfg.Region)
}
if cfg.AccessKey != "" || cfg.SecretKey != "" {
awsConfig.Credentials = credentials.NewStaticCredentials(cfg.AccessKey, cfg.SecretKey, "")
}

b.session, err = session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigEnable,
Config: aws.Config{
EC2MetadataEnableFallback: aws.Bool(false),
UseFIPSEndpoint: useFIPSEndpoint,
},
Config: awsConfig,
})
if err != nil {
return nil, trace.Wrap(err)
}
// override the default environment (region + credentials) with the values
// from the YAML file:
if cfg.Region != "" {
b.session.Config.Region = aws.String(cfg.Region)
}
if cfg.AccessKey != "" || cfg.SecretKey != "" {
creds := credentials.NewStaticCredentials(cfg.AccessKey, cfg.SecretKey, "")
b.session.Config.Credentials = creds
}

// Increase the size of the connection pool. This substantially improves the
// performance of Teleport under load as it reduces the number of TLS
Expand All @@ -275,7 +273,14 @@ func New(ctx context.Context, params backend.Params) (*Backend, error) {
b.session.Config.HTTPClient = httpClient

// create DynamoDB service:
svc, err := dynamometrics.NewAPIMetrics(dynamometrics.Backend, dynamodb.New(b.session))
svc, err := dynamometrics.NewAPIMetrics(dynamometrics.Backend, dynamodb.New(b.session, &aws.Config{
// Setting this on the individual service instead of the session, as DynamoDB Streams
// and Application Auto Scaling do not yet have FIPS endpoints in non-GovCloud.
// See also: https://aws.amazon.com/compliance/fips/#FIPS_Endpoints_by_Service
// TODO(reed): This can be simplified once https://github.com/aws/aws-sdk-go/pull/5078
// is available (or whenever AWS adds the missing FIPS endpoints).
UseFIPSEndpoint: useFIPSEndpoint,
}))
if err != nil {
return nil, trace.Wrap(err)
}
Expand Down
39 changes: 22 additions & 17 deletions lib/events/dynamoevents/dynamoevents.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,34 +260,39 @@ func New(ctx context.Context, cfg Config) (*Log, error) {
Entry: l,
Config: cfg,
}
// create an AWS session using default SDK behavior, i.e. it will interpret
// the environment and ~/.aws directory just like an AWS CLI tool would:
b.session, err = awssession.NewSessionWithOptions(awssession.Options{
SharedConfigState: awssession.SharedConfigEnable,
})
if err != nil {
return nil, trace.Wrap(err)

awsConfig := aws.Config{
EC2MetadataEnableFallback: aws.Bool(false),
}
// override the default environment (region + credentials) with the values
// from the YAML file:

// Override the default environment's region if value set in YAML file:
if cfg.Region != "" {
b.session.Config.Region = aws.String(cfg.Region)
awsConfig.Region = aws.String(cfg.Region)
}

// Override the service endpoint using the "endpoint" query parameter from
// "audit_events_uri". This is for non-AWS DynamoDB-compatible backends.
if cfg.Endpoint != "" {
b.session.Config.Endpoint = aws.String(cfg.Endpoint)
awsConfig.Endpoint = aws.String(cfg.Endpoint)
}

// Explicitly enable or disable FIPS endpoints for DynamoDB
b.session.Config.UseFIPSEndpoint = events.FIPSProtoStateToAWSState(cfg.UseFIPSEndpoint)

// Explicitly disable IMDSv1 fallback
b.session.Config.EC2MetadataEnableFallback = aws.Bool(false)
b.session, err = awssession.NewSessionWithOptions(awssession.Options{
SharedConfigState: awssession.SharedConfigEnable,
Config: awsConfig,
})
if err != nil {
return nil, trace.Wrap(err)
}

// create DynamoDB service:
svc, err := dynamometrics.NewAPIMetrics(dynamometrics.Events, dynamodb.New(b.session))
svc, err := dynamometrics.NewAPIMetrics(dynamometrics.Events, dynamodb.New(b.session, &aws.Config{
// Setting this on the individual service instead of the session, as DynamoDB Streams
// and Application Auto Scaling do not yet have FIPS endpoints in non-GovCloud.
// See also: https://aws.amazon.com/compliance/fips/#FIPS_Endpoints_by_Service
// TODO(reed): This can be simplified once https://github.com/aws/aws-sdk-go/pull/5078
// is available (or whenever AWS adds the missing FIPS endpoints).
UseFIPSEndpoint: events.FIPSProtoStateToAWSState(cfg.UseFIPSEndpoint),
}))
if err != nil {
return nil, trace.Wrap(err)
}
Expand Down
32 changes: 15 additions & 17 deletions lib/events/s3sessions/s3handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,33 +154,31 @@ func (s *Config) CheckAndSetDefaults() error {
return trace.BadParameter("missing parameter Bucket")
}
if s.Session == nil {
// create an AWS session using default SDK behavior, i.e. it will interpret
// the environment and ~/.aws directory just like an AWS CLI tool would:
sess, err := awssession.NewSessionWithOptions(awssession.Options{
SharedConfigState: awssession.SharedConfigEnable,
})
if err != nil {
return trace.Wrap(err)
awsConfig := aws.Config{
EC2MetadataEnableFallback: aws.Bool(false),
UseFIPSEndpoint: events.FIPSProtoStateToAWSState(s.UseFIPSEndpoint),
}
// override the default environment (region + Host + credentials) with the values
// from the YAML file:
if s.Region != "" {
sess.Config.Region = aws.String(s.Region)
awsConfig.Region = aws.String(s.Region)
}
if s.Endpoint != "" {
sess.Config.Endpoint = aws.String(s.Endpoint)
sess.Config.S3ForcePathStyle = aws.Bool(true)
awsConfig.Endpoint = aws.String(s.Endpoint)
awsConfig.S3ForcePathStyle = aws.Bool(true)
}
if s.Insecure {
sess.Config.DisableSSL = aws.Bool(s.Insecure)
awsConfig.DisableSSL = aws.Bool(s.Insecure)
}
if s.Credentials != nil {
sess.Config.Credentials = s.Credentials
awsConfig.Credentials = s.Credentials
}

sess.Config.EC2MetadataEnableFallback = aws.Bool(false)

sess.Config.UseFIPSEndpoint = events.FIPSProtoStateToAWSState(s.UseFIPSEndpoint)
sess, err := awssession.NewSessionWithOptions(awssession.Options{
SharedConfigState: awssession.SharedConfigEnable,
Config: awsConfig,
})
if err != nil {
return trace.Wrap(err)
}

s.Session = sess
}
Expand Down
22 changes: 17 additions & 5 deletions lib/integrations/awsoidc/clientsv1.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
"github.com/aws/aws-sdk-go/aws/endpoints"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/sts"
"github.com/gravitational/trace"

"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/modules"
"github.com/gravitational/teleport/lib/utils/oidc"
)

Expand Down Expand Up @@ -60,8 +62,17 @@ func NewSessionV1(ctx context.Context, client IntegrationTokenGenerator, region
return nil, trace.BadParameter("invalid integration subkind, expected awsoidc, got %s", integration.GetSubKind())
}

useFIPSEndpoint := endpoints.FIPSEndpointStateUnset
if modules.GetModules().IsBoringBinary() {
useFIPSEndpoint = endpoints.FIPSEndpointStateEnabled
}

sess, err := session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigDisable,
Config: aws.Config{
EC2MetadataEnableFallback: aws.Bool(false),
UseFIPSEndpoint: useFIPSEndpoint,
},
})
if err != nil {
return nil, trace.Wrap(err)
Expand All @@ -88,13 +99,14 @@ func NewSessionV1(ctx context.Context, client IntegrationTokenGenerator, region
)
awsCredentials := credentials.NewCredentials(roleProvider)

awsConfig := aws.NewConfig().
WithRegion(region).
WithCredentials(awsCredentials)

session, err := session.NewSessionWithOptions(session.Options{
Config: *awsConfig,
SharedConfigState: session.SharedConfigDisable,
Config: aws.Config{
Region: aws.String(region),
Credentials: awsCredentials,
EC2MetadataEnableFallback: aws.Bool(false),
UseFIPSEndpoint: useFIPSEndpoint,
},
})
if err != nil {
return nil, trace.Wrap(err)
Expand Down

0 comments on commit 1e7d338

Please sign in to comment.