diff --git a/.golangci.yml b/.golangci.yml index 79929e35e17b0..c0632f4c790e9 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -59,16 +59,21 @@ issues: path-except: ^e/ text: "non-constant format string in call to github.com/gravitational/trace." # lib/utils/aws/ subpackages are allowed to use AWS SDK constructors. + - path: lib/utils/aws/iamutils/iam.go + linters: [forbidigo] + text: 'iam.NewFromConfig' + - path: lib/utils/aws/iamutils/iam_v1.go + linters: [forbidigo] + text: 'iam.New' - path: lib/utils/aws/stsutils/sts.go linters: [forbidigo] text: 'sts.NewFromConfig' - path: lib/utils/aws/stsutils/sts_v1.go linters: [forbidigo] text: 'sts.New' - # TODO(codingllama): Remove once e/ is updated. - - path: e/lib/cloud/aws/aws.go + - path: lib/utils/aws/stsutils/stscreds_v1.go linters: [forbidigo] - text: 'sts.NewFromConfig' + text: 'stscreds.NewCredentials' exclude-use-default: true max-same-issues: 0 max-issues-per-linter: 0 @@ -281,10 +286,17 @@ linters-settings: forbid: - p: '^rsa\.GenerateKey$' msg: 'generating RSA keys is slow, use lib/cryptosuites to generate an appropriate key type' + # AWS SDK wrapped constructors. + - p: '^iam\.NewFromConfig$' + msg: 'Use iamutils.NewFromConfig' + - p: '^iam\.New$' + msg: 'Use iamutils.NewV1' - p: '^sts\.NewFromConfig$' msg: 'Use stsutils.NewFromConfig' - p: '^sts\.New$' msg: 'Use stsutils.NewV1' + - p: '^stscreds\.NewCredentials$' + msg: 'Use stsutils.NewCredentials' run: go: '1.23' diff --git a/lib/cloud/clients.go b/lib/cloud/clients.go index f8351d6309fa7..a89094a008f98 100644 --- a/lib/cloud/clients.go +++ b/lib/cloud/clients.go @@ -44,7 +44,6 @@ import ( "github.com/aws/aws-sdk-go/service/eks/eksiface" "github.com/aws/aws-sdk-go/service/elasticache" "github.com/aws/aws-sdk-go/service/elasticache/elasticacheiface" - "github.com/aws/aws-sdk-go/service/iam" "github.com/aws/aws-sdk-go/service/iam/iamiface" "github.com/aws/aws-sdk-go/service/kms" "github.com/aws/aws-sdk-go/service/kms/kmsiface" @@ -81,6 +80,7 @@ import ( gcpimds "github.com/gravitational/teleport/lib/cloud/imds/gcp" "github.com/gravitational/teleport/lib/modules" "github.com/gravitational/teleport/lib/utils" + "github.com/gravitational/teleport/lib/utils/aws/iamutils" "github.com/gravitational/teleport/lib/utils/aws/stsutils" ) @@ -589,7 +589,7 @@ func (c *cloudClients) GetAWSIAMClient(ctx context.Context, region string, opts if err != nil { return nil, trace.Wrap(err) } - return iam.New(session), nil + return iamutils.NewV1(session), nil } // GetAWSS3Client returns AWS S3 client. diff --git a/lib/configurators/aws/aws.go b/lib/configurators/aws/aws.go index 45063d9bc05bf..e8676a4925533 100644 --- a/lib/configurators/aws/aws.go +++ b/lib/configurators/aws/aws.go @@ -49,6 +49,7 @@ import ( "github.com/gravitational/teleport/lib/srv/db/secrets" "github.com/gravitational/teleport/lib/utils" awsutils "github.com/gravitational/teleport/lib/utils/aws" + "github.com/gravitational/teleport/lib/utils/aws/iamutils" "github.com/gravitational/teleport/lib/utils/aws/stsutils" ) @@ -392,7 +393,7 @@ func (c *ConfiguratorConfig) CheckAndSetDefaults() error { c.stsClient = stsutils.NewFromConfig(*c.awsCfg) } if c.iamClient == nil { - c.iamClient = iam.NewFromConfig(*c.awsCfg) + c.iamClient = iamutils.NewFromConfig(*c.awsCfg) } if c.Identity == nil { c.Identity, err = awslib.GetIdentityWithClientV2(context.Background(), c.stsClient) @@ -423,7 +424,7 @@ func (c *ConfiguratorConfig) CheckAndSetDefaults() error { if c.Policies == nil { partition := c.Identity.GetPartition() accountID := c.Identity.GetAccountID() - iamClient := iam.NewFromConfig(*c.awsCfg) + iamClient := iamutils.NewFromConfig(*c.awsCfg) c.Policies = awslib.NewPolicies(partition, accountID, iamClient) } } diff --git a/lib/integrations/awsoidc/accessgraph_sync.go b/lib/integrations/awsoidc/accessgraph_sync.go index 30232598b5e6f..ba272e0eeae07 100644 --- a/lib/integrations/awsoidc/accessgraph_sync.go +++ b/lib/integrations/awsoidc/accessgraph_sync.go @@ -29,6 +29,7 @@ import ( awslib "github.com/gravitational/teleport/lib/cloud/aws" "github.com/gravitational/teleport/lib/cloud/provisioning" "github.com/gravitational/teleport/lib/cloud/provisioning/awsactions" + "github.com/gravitational/teleport/lib/utils/aws/iamutils" "github.com/gravitational/teleport/lib/utils/aws/stsutils" ) @@ -91,7 +92,7 @@ func NewAccessGraphIAMConfigureClient(ctx context.Context) (AccessGraphIAMConfig return &defaultTAGIAMConfigureClient{ CallerIdentityGetter: stsutils.NewFromConfig(cfg), - Client: iam.NewFromConfig(cfg), + Client: iamutils.NewFromConfig(cfg), }, nil } diff --git a/lib/integrations/awsoidc/aws_app_access_iam_config.go b/lib/integrations/awsoidc/aws_app_access_iam_config.go index 46fae5ad677d3..22b4139305ec9 100644 --- a/lib/integrations/awsoidc/aws_app_access_iam_config.go +++ b/lib/integrations/awsoidc/aws_app_access_iam_config.go @@ -31,6 +31,7 @@ import ( "github.com/gravitational/teleport/lib/cloud/provisioning" "github.com/gravitational/teleport/lib/cloud/provisioning/awsactions" "github.com/gravitational/teleport/lib/modules" + "github.com/gravitational/teleport/lib/utils/aws/iamutils" "github.com/gravitational/teleport/lib/utils/aws/stsutils" ) @@ -108,7 +109,7 @@ func NewAWSAppAccessConfigureClient(ctx context.Context) (AWSAppAccessConfigureC } return &defaultAWSAppAccessConfigureClient{ - Client: iam.NewFromConfig(cfg), + Client: iamutils.NewFromConfig(cfg), CallerIdentityGetter: stsutils.NewFromConfig(cfg), }, nil } diff --git a/lib/integrations/awsoidc/deployservice_iam_config.go b/lib/integrations/awsoidc/deployservice_iam_config.go index d7b5b764c1962..67a16685217de 100644 --- a/lib/integrations/awsoidc/deployservice_iam_config.go +++ b/lib/integrations/awsoidc/deployservice_iam_config.go @@ -33,6 +33,7 @@ import ( "github.com/gravitational/teleport/lib/cloud/provisioning/awsactions" "github.com/gravitational/teleport/lib/integrations/awsoidc/tags" awslibutils "github.com/gravitational/teleport/lib/utils/aws" + "github.com/gravitational/teleport/lib/utils/aws/iamutils" "github.com/gravitational/teleport/lib/utils/aws/stsutils" ) @@ -146,7 +147,7 @@ func NewDeployServiceIAMConfigureClient(ctx context.Context, region string) (Dep } return &defaultDeployServiceIAMConfigureClient{ - Client: iam.NewFromConfig(cfg), + Client: iamutils.NewFromConfig(cfg), CallerIdentityGetter: stsutils.NewFromConfig(cfg), }, nil } diff --git a/lib/integrations/awsoidc/ec2_ssm_iam_config.go b/lib/integrations/awsoidc/ec2_ssm_iam_config.go index c2116a5cda714..4188749de612a 100644 --- a/lib/integrations/awsoidc/ec2_ssm_iam_config.go +++ b/lib/integrations/awsoidc/ec2_ssm_iam_config.go @@ -32,6 +32,7 @@ import ( "github.com/gravitational/teleport/lib/cloud/provisioning" "github.com/gravitational/teleport/lib/cloud/provisioning/awsactions" "github.com/gravitational/teleport/lib/integrations/awsoidc/tags" + "github.com/gravitational/teleport/lib/utils/aws/iamutils" "github.com/gravitational/teleport/lib/utils/aws/stsutils" ) @@ -143,7 +144,7 @@ func NewEC2SSMConfigureClient(ctx context.Context, region string) (EC2SSMConfigu } return &defaultEC2SSMConfigureClient{ - Client: iam.NewFromConfig(cfg), + Client: iamutils.NewFromConfig(cfg), ssmClient: ssm.NewFromConfig(cfg), CallerIdentityGetter: stsutils.NewFromConfig(cfg), }, nil diff --git a/lib/integrations/awsoidc/eice_iam_config.go b/lib/integrations/awsoidc/eice_iam_config.go index 8158b45042e11..99d18e8a60928 100644 --- a/lib/integrations/awsoidc/eice_iam_config.go +++ b/lib/integrations/awsoidc/eice_iam_config.go @@ -29,6 +29,7 @@ import ( awslib "github.com/gravitational/teleport/lib/cloud/aws" "github.com/gravitational/teleport/lib/cloud/provisioning" "github.com/gravitational/teleport/lib/cloud/provisioning/awsactions" + "github.com/gravitational/teleport/lib/utils/aws/iamutils" "github.com/gravitational/teleport/lib/utils/aws/stsutils" ) @@ -101,7 +102,7 @@ func NewEICEIAMConfigureClient(ctx context.Context, region string) (EICEIAMConfi return &defaultEICEIAMConfigureClient{ CallerIdentityGetter: stsutils.NewFromConfig(cfg), - Client: iam.NewFromConfig(cfg), + Client: iamutils.NewFromConfig(cfg), }, nil } diff --git a/lib/integrations/awsoidc/eks_iam_config.go b/lib/integrations/awsoidc/eks_iam_config.go index c4b13a5ed1dda..231a854b0734c 100644 --- a/lib/integrations/awsoidc/eks_iam_config.go +++ b/lib/integrations/awsoidc/eks_iam_config.go @@ -29,6 +29,7 @@ import ( awslib "github.com/gravitational/teleport/lib/cloud/aws" "github.com/gravitational/teleport/lib/cloud/provisioning" "github.com/gravitational/teleport/lib/cloud/provisioning/awsactions" + "github.com/gravitational/teleport/lib/utils/aws/iamutils" "github.com/gravitational/teleport/lib/utils/aws/stsutils" ) @@ -100,7 +101,7 @@ func NewEKSIAMConfigureClient(ctx context.Context, region string) (EKSIAMConfigu } return &defaultEKSEIAMConfigureClient{ - Client: iam.NewFromConfig(cfg), + Client: iamutils.NewFromConfig(cfg), CallerIdentityGetter: stsutils.NewFromConfig(cfg), }, nil } diff --git a/lib/integrations/awsoidc/idp_iam_config.go b/lib/integrations/awsoidc/idp_iam_config.go index 9b2a00e9f7da0..02a298d7466aa 100644 --- a/lib/integrations/awsoidc/idp_iam_config.go +++ b/lib/integrations/awsoidc/idp_iam_config.go @@ -35,6 +35,7 @@ import ( "github.com/gravitational/teleport/lib/cloud/provisioning/awsactions" "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/integrations/awsoidc/tags" + "github.com/gravitational/teleport/lib/utils/aws/iamutils" "github.com/gravitational/teleport/lib/utils/aws/stsutils" ) @@ -194,7 +195,7 @@ func NewIdPIAMConfigureClient(ctx context.Context) (IdPIAMConfigureClient, error return &defaultIdPIAMConfigureClient{ httpClient: httpClient, awsConfig: cfg, - Client: iam.NewFromConfig(cfg), + Client: iamutils.NewFromConfig(cfg), CallerIdentityGetter: stsutils.NewFromConfig(cfg), }, nil } diff --git a/lib/integrations/awsoidc/listdatabases_iam_config.go b/lib/integrations/awsoidc/listdatabases_iam_config.go index bec7e1a00de73..a2d5bd2edaa7f 100644 --- a/lib/integrations/awsoidc/listdatabases_iam_config.go +++ b/lib/integrations/awsoidc/listdatabases_iam_config.go @@ -29,6 +29,7 @@ import ( awslib "github.com/gravitational/teleport/lib/cloud/aws" "github.com/gravitational/teleport/lib/cloud/provisioning" "github.com/gravitational/teleport/lib/cloud/provisioning/awsactions" + "github.com/gravitational/teleport/lib/utils/aws/iamutils" "github.com/gravitational/teleport/lib/utils/aws/stsutils" ) @@ -92,7 +93,7 @@ func NewListDatabasesIAMConfigureClient(ctx context.Context, region string) (Lis } return &defaultListDatabasesIAMConfigureClient{ - Client: iam.NewFromConfig(cfg), + Client: iamutils.NewFromConfig(cfg), CallerIdentityGetter: stsutils.NewFromConfig(cfg), }, nil } diff --git a/lib/srv/app/cloud.go b/lib/srv/app/cloud.go index 0196cdff2faa0..a7726f49e972a 100644 --- a/lib/srv/app/cloud.go +++ b/lib/srv/app/cloud.go @@ -39,6 +39,7 @@ import ( "github.com/gravitational/teleport/api/constants" "github.com/gravitational/teleport/lib/tlsca" awsutils "github.com/gravitational/teleport/lib/utils/aws" + "github.com/gravitational/teleport/lib/utils/aws/stsutils" ) // Cloud provides cloud provider access related methods such as generating @@ -208,7 +209,7 @@ func (c *cloud) getAWSSigninToken(ctx context.Context, req *AWSSigninRequest, en creds.ExternalID = aws.String(req.ExternalID) } }) - stsCredentials, err := stscreds.NewCredentials(session, req.Identity.RouteToApp.AWSRoleARN, options...).Get() + stsCredentials, err := stsutils.NewCredentialsV1(session, req.Identity.RouteToApp.AWSRoleARN, options...).Get() if err != nil { return "", trace.Wrap(err) } diff --git a/lib/utils/aws/fips_disabled.go b/lib/utils/aws/awsfips/fips_disabled.go similarity index 89% rename from lib/utils/aws/fips_disabled.go rename to lib/utils/aws/awsfips/fips_disabled.go index 6773a61413770..a041facc8c64e 100644 --- a/lib/utils/aws/fips_disabled.go +++ b/lib/utils/aws/awsfips/fips_disabled.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -package aws +package awsfips import ( "os" @@ -27,8 +27,8 @@ import ( // Either "yes" or a "truthy" value (as defined by [strconv.ParseBool]) are // considered true. // -// Prefer using specific functions, such as those in the -// lib/utils/aws/stsutils or lib/utils/aws/dynamodbutils packages. +// Prefer using specific functions, such as those in lib/utils/aws/* +// subpackages. func IsFIPSDisabledByEnv() bool { const envVar = "TELEPORT_UNSTABLE_DISABLE_AWS_FIPS" diff --git a/lib/utils/aws/credentials.go b/lib/utils/aws/credentials.go index 257d6606d42a9..83889135aa547 100644 --- a/lib/utils/aws/credentials.go +++ b/lib/utils/aws/credentials.go @@ -37,6 +37,7 @@ import ( "github.com/gravitational/teleport/lib/modules" "github.com/gravitational/teleport/lib/utils" + "github.com/gravitational/teleport/lib/utils/aws/stsutils" ) // GetCredentialsRequest is the request for obtaining STS credentials. @@ -72,7 +73,7 @@ func NewCredentialsGetter() CredentialsGetter { // Get obtains STS credentials. func (g *credentialsGetter) Get(_ context.Context, request GetCredentialsRequest) (*credentials.Credentials, error) { logrus.Debugf("Creating STS session %q for %q.", request.SessionName, request.RoleARN) - return stscreds.NewCredentials(request.Provider, request.RoleARN, + return stsutils.NewCredentialsV1(request.Provider, request.RoleARN, func(cred *stscreds.AssumeRoleProvider) { cred.RoleSessionName = MaybeHashRoleSessionName(request.SessionName) cred.Expiry.SetExpiration(request.Expiry, 0) diff --git a/lib/utils/aws/dynamodbutils/dynamo.go b/lib/utils/aws/dynamodbutils/dynamo.go index 822ee28c3ce7d..7713e5936dcde 100644 --- a/lib/utils/aws/dynamodbutils/dynamo.go +++ b/lib/utils/aws/dynamodbutils/dynamo.go @@ -18,13 +18,13 @@ package dynamodbutils import ( "github.com/gravitational/teleport/lib/modules" - awsutils "github.com/gravitational/teleport/lib/utils/aws" + "github.com/gravitational/teleport/lib/utils/aws/awsfips" ) // IsFIPSEnabled returns true if FIPS should be enabled for DynamoDB. // FIPS is enabled is the binary is boring ([modules.Modules.IsBoringBinary]) // and if FIPS is not disabled by the environment -// ([awsutils.IsFIPSDisabledByEnv]). +// ([awsfips.IsFIPSDisabledByEnv]). func IsFIPSEnabled() bool { - return !awsutils.IsFIPSDisabledByEnv() && modules.GetModules().IsBoringBinary() + return !awsfips.IsFIPSDisabledByEnv() && modules.GetModules().IsBoringBinary() } diff --git a/lib/utils/aws/iamutils/iam.go b/lib/utils/aws/iamutils/iam.go new file mode 100644 index 0000000000000..a4784d1cc467b --- /dev/null +++ b/lib/utils/aws/iamutils/iam.go @@ -0,0 +1,38 @@ +// Teleport +// Copyright (C) 2025 Gravitational, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package iamutils + +import ( + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iam" + + "github.com/gravitational/teleport/lib/utils/aws/awsfips" +) + +// NewFromConfig wraps [iam.NewFromConfig] and applies FIPS settings +// according to environment variables. +// +// See [awsfips.IsFIPSDisabledByEnv]. +func NewFromConfig(cfg aws.Config, optFns ...func(*iam.Options)) *iam.Client { + if awsfips.IsFIPSDisabledByEnv() { + // append so it overrides any preceding settings. + optFns = append(optFns, func(opts *iam.Options) { + opts.EndpointOptions.UseFIPSEndpoint = aws.FIPSEndpointStateDisabled + }) + } + return iam.NewFromConfig(cfg, optFns...) +} diff --git a/lib/utils/aws/iamutils/iam_test.go b/lib/utils/aws/iamutils/iam_test.go new file mode 100644 index 0000000000000..73306674fd0be --- /dev/null +++ b/lib/utils/aws/iamutils/iam_test.go @@ -0,0 +1,64 @@ +// Teleport +// Copyright (C) 2025 Gravitational, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package iamutils_test + +import ( + "testing" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iam" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/gravitational/teleport/lib/utils/aws/iamutils" +) + +func TestNewFromConfig(t *testing.T) { + // Don't t.Parallel(), uses t.Setenv(). + + cfg := aws.Config{} + opts := func(opts *iam.Options) { + opts.EndpointOptions.UseFIPSEndpoint = aws.FIPSEndpointStateEnabled + } + + tests := []struct { + name string + envVarValue string // value for the _DISABLE_FIPS environment variable + want aws.FIPSEndpointState + }{ + { + name: "fips", + want: aws.FIPSEndpointStateEnabled, + }, + { + name: "fips disabled by env", + envVarValue: "yes", + want: aws.FIPSEndpointStateDisabled, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Setenv("TELEPORT_UNSTABLE_DISABLE_AWS_FIPS", test.envVarValue) + + iamClient := iamutils.NewFromConfig(cfg, opts) + require.NotNil(t, iamClient, "*iam.Client") + + got := iamClient.Options().EndpointOptions.UseFIPSEndpoint + assert.Equal(t, test.want, got, "opts.EndpointOptions.UseFIPSEndpoint mismatch") + }) + } +} diff --git a/lib/utils/aws/iamutils/iam_v1.go b/lib/utils/aws/iamutils/iam_v1.go new file mode 100644 index 0000000000000..2cc63aec5f03d --- /dev/null +++ b/lib/utils/aws/iamutils/iam_v1.go @@ -0,0 +1,37 @@ +// Teleport +// Copyright (C) 2025 Gravitational, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package iamutils + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/client" + "github.com/aws/aws-sdk-go/service/iam" + + "github.com/gravitational/teleport/lib/utils/aws/awsfips" +) + +// NewV1 wraps [iam.New] and applies FIPS settings according to environment +// variables. +// +// See [awsfips.IsFIPSDisabledByEnv]. +func NewV1(p client.ConfigProvider, cfgs ...*aws.Config) *iam.IAM { + if awsfips.IsFIPSDisabledByEnv() { + // append so it overrides any preceding settings. + cfgs = append(cfgs, aws.NewConfig().WithUseFIPSEndpoint(false)) + } + return iam.New(p, cfgs...) +} diff --git a/lib/utils/aws/iamutils/iam_v1_test.go b/lib/utils/aws/iamutils/iam_v1_test.go new file mode 100644 index 0000000000000..ddffa2467187e --- /dev/null +++ b/lib/utils/aws/iamutils/iam_v1_test.go @@ -0,0 +1,76 @@ +// Teleport +// Copyright (C) 2025 Gravitational, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package iamutils_test + +import ( + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/client" + "github.com/aws/aws-sdk-go/aws/endpoints" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/gravitational/teleport/lib/utils/aws/iamutils" +) + +func TestNewV1(t *testing.T) { + // Don't t.Parallel(), uses t.Setenv(). + + configProvider := &mockConfigProvider{ + Config: client.Config{ + Config: aws.NewConfig().WithUseFIPSEndpoint(true), + }, + } + + tests := []struct { + name string + envVarValue string // value for the _DISABLE_FIPS environment variable + want endpoints.FIPSEndpointState + }{ + { + name: "fips", + want: endpoints.FIPSEndpointStateEnabled, + }, + { + name: "fips disabled by env", + envVarValue: "yes", + want: endpoints.FIPSEndpointStateDisabled, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Setenv("TELEPORT_UNSTABLE_DISABLE_AWS_FIPS", test.envVarValue) + + iamClient := iamutils.NewV1(configProvider) + require.NotNil(t, iamClient, "*iam.IAM") + + got := iamClient.Config.UseFIPSEndpoint + assert.Equal(t, test.want, got, "iamClient.Config.UseFIPSEndpoint mismatch") + }) + } +} + +type mockConfigProvider struct { + Config client.Config +} + +func (m *mockConfigProvider) ClientConfig(_ string, cfgs ...*aws.Config) client.Config { + cc := m.Config + cc.Config = cc.Config.Copy(cfgs...) + return cc +} diff --git a/lib/utils/aws/stsutils/sts.go b/lib/utils/aws/stsutils/sts.go index 70f3d63196dce..4020a4f50ebfe 100644 --- a/lib/utils/aws/stsutils/sts.go +++ b/lib/utils/aws/stsutils/sts.go @@ -20,15 +20,15 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/sts" - awsutils "github.com/gravitational/teleport/lib/utils/aws" + "github.com/gravitational/teleport/lib/utils/aws/awsfips" ) // NewFromConfig wraps [sts.NewFromConfig] and applies FIPS settings // according to environment variables. // -// See [awsutils.IsFIPSDisabledByEnv]. +// See [awsfips.IsFIPSDisabledByEnv]. func NewFromConfig(cfg aws.Config, optFns ...func(*sts.Options)) *sts.Client { - if awsutils.IsFIPSDisabledByEnv() { + if awsfips.IsFIPSDisabledByEnv() { // append so it overrides any preceding settings. optFns = append(optFns, func(opts *sts.Options) { opts.EndpointOptions.UseFIPSEndpoint = aws.FIPSEndpointStateDisabled diff --git a/lib/utils/aws/stsutils/sts_v1.go b/lib/utils/aws/stsutils/sts_v1.go index 3d17e272de847..b60d3715c8c31 100644 --- a/lib/utils/aws/stsutils/sts_v1.go +++ b/lib/utils/aws/stsutils/sts_v1.go @@ -21,15 +21,15 @@ import ( "github.com/aws/aws-sdk-go/aws/client" "github.com/aws/aws-sdk-go/service/sts" - awsutils "github.com/gravitational/teleport/lib/utils/aws" + "github.com/gravitational/teleport/lib/utils/aws/awsfips" ) // NewV1 wraps [sts.New] and applies FIPS settings according to environment // variables. // -// See [awsutils.IsFIPSDisabledByEnv]. +// See [awsfips.IsFIPSDisabledByEnv]. func NewV1(p client.ConfigProvider, cfgs ...*aws.Config) *sts.STS { - if awsutils.IsFIPSDisabledByEnv() { + if awsfips.IsFIPSDisabledByEnv() { // append so it overrides any preceding settings. cfgs = append(cfgs, aws.NewConfig().WithUseFIPSEndpoint(false)) } diff --git a/lib/utils/aws/stsutils/stscreds_v1.go b/lib/utils/aws/stsutils/stscreds_v1.go new file mode 100644 index 0000000000000..b8f2049aad884 --- /dev/null +++ b/lib/utils/aws/stsutils/stscreds_v1.go @@ -0,0 +1,51 @@ +// Teleport +// Copyright (C) 2025 Gravitational, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package stsutils + +import ( + "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/stscreds" + + "github.com/gravitational/teleport/lib/utils/aws/awsfips" +) + +// NewCredentialsV1 wraps [stscreds.NewCredentials] and applies FIPS settings +// according to environment variables. +// +// See [awsfips.IsFIPSDisabledByEnv]. +func NewCredentialsV1( + c client.ConfigProvider, + roleARN string, + options ...func(*stscreds.AssumeRoleProvider), +) *credentials.Credentials { + if awsfips.IsFIPSDisabledByEnv() { + c = fipsDisabledProvider{provider: c} + } + return stscreds.NewCredentials(c, roleARN, options...) +} + +type fipsDisabledProvider struct { + provider client.ConfigProvider +} + +func (p fipsDisabledProvider) ClientConfig(serviceName string, cfgs ...*aws.Config) client.Config { + cfgs = append(cfgs, aws.NewConfig().WithUseFIPSEndpoint(false)) + cfg := p.provider.ClientConfig(serviceName, cfgs...) + return cfg +} diff --git a/tool/teleport/common/integration_configure.go b/tool/teleport/common/integration_configure.go index 79e9275f17c91..6ebf3d65343e5 100644 --- a/tool/teleport/common/integration_configure.go +++ b/tool/teleport/common/integration_configure.go @@ -26,7 +26,6 @@ import ( awsConfig "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/athena" "github.com/aws/aws-sdk-go-v2/service/glue" - "github.com/aws/aws-sdk-go-v2/service/iam" "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/gravitational/trace" @@ -40,6 +39,7 @@ import ( "github.com/gravitational/teleport/lib/integrations/samlidp" "github.com/gravitational/teleport/lib/integrations/samlidp/samlidpconfig" "github.com/gravitational/teleport/lib/utils" + "github.com/gravitational/teleport/lib/utils/aws/iamutils" "github.com/gravitational/teleport/lib/utils/aws/stsutils" ) @@ -218,7 +218,7 @@ func onIntegrationConfExternalAuditCmd(ctx context.Context, params easconfig.Ext } clt := &awsoidc.DefaultConfigureExternalAuditStorageClient{ - Iam: iam.NewFromConfig(cfg), + Iam: iamutils.NewFromConfig(cfg), Sts: stsutils.NewFromConfig(cfg), } return trace.Wrap(awsoidc.ConfigureExternalAuditStorage(ctx, clt, params))