aws / aws-sdk-go-v2

AWS SDK for the Go programming language.
https://aws.github.io/aws-sdk-go-v2/docs/
Apache License 2.0
2.5k stars 602 forks source link

Global `UseFIPSEndpoint` setting and Assuming IAM Role from shared config file #2686

Open gdavison opened 2 weeks ago

gdavison commented 2 weeks ago

Acknowledgements

Describe the bug

When

resolving credentials fails with the error

Retrieving credentials: failed to refresh cached credentials, operation error STS: AssumeRole, https response error StatusCode: 0, RequestID: , request send failed, Post "https://sts-fips.ca-central-1.amazonaws.com/": dial tcp: lookup sts-fips.ca-central-1.amazonaws.com: no such host

When overriding the endpoint, as suggested in the AWS CLI documentation, it fails with the error

Retrieving credentials: failed to refresh cached credentials, operation error STS: AssumeRole, failed to resolve service endpoint, endpoint rule error, Invalid Configuration: FIPS and custom endpoint are not supported

Expected Behavior

Based on previous discussion (https://github.com/aws/aws-sdk-go-v2/issues/2336#issuecomment-1781797308), the first failure is expected.

When providing a custom endpoint, the UseFIPSEndpoint (and UseDualStackEndpoint) flags should be cleared so that the endpoint can be used.

Current Behavior

Because config.LoadDefaultConfig creates its own STS client internally, there is no way to clear the UseFIPSEndpoint setting when also using a custom endpoint.

Using a global aws.EndpointResolverWithOptions does work to set the endpoint without the Invalid Configuration: FIPS and custom endpoint are not supported error, but aws.EndpointResolverWithOptions is now deprecated. It also doesn't directly support setting endpoints via environment variables or the shared configuration file.

Note that the AWS CLI also fails in this situation:

AWS_PROFILE="<profile-that-assumes-role>" AWS_REGION=ca-central-1 AWS_USE_FIPS_ENDPOINT=true aws s3api list-buckets --endpoint-url="https://s3.ca-central-1.amazonaws.com/"

fails with

Could not connect to the endpoint URL: "https://sts-fips.ca-central-1.amazonaws.com/"

Reproduction Steps

package main

import (
    "context"
    "fmt"
    "os"

    "github.com/aws/aws-sdk-go-v2/config"
)

func main() {
    ctx := context.Background()

    // ca-central-1 does not support FIPS for STS
    os.Setenv("AWS_REGION", "ca-central-1")
    os.Setenv("AWS_USE_FIPS_ENDPOINT", "true")

    os.Setenv("AWS_ENDPOINT_URL_STS", "https://sts.ca-central-1.amazonaws.com/")

    os.Setenv("AWS_PROFILE", "assume-role")

    cfg, err := config.LoadDefaultConfig(ctx)
    if err != nil {
        fmt.Printf("Loading configuration: %s\n", err)
        os.Exit(1)
    }

    _, err = cfg.Credentials.Retrieve(ctx)
    if err != nil {
        fmt.Printf("Retrieving credentials: %s\n", err)
        os.Exit(1)
    }

    fmt.Println("Success.")
}

The config file

[source]
aws_access_key_id     = ****
aws_secret_access_key = ****

[assume-role]
source_profile = source
role_arn       = arn:aws:iam::123456789012:role/OrganizationAccountAccessRole

Possible Solution

No response

Additional Information/Context

No response

AWS Go SDK V2 Module Versions Used

require github.com/aws/aws-sdk-go-v2/config v1.27.19

require ( github.com/aws/aws-sdk-go-v2 v1.28.0 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.19 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.6 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.10 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.10 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.12 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.20.12 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.6 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.28.13 // indirect github.com/aws/smithy-go v1.20.2 // indirect )

Compiler and Version used

go version go1.22.1 darwin/arm64

Operating System and version

macOS 13.6.7

RanVaknin commented 1 week ago

Hi @gdavison ,

Thanks for reaching out. You can pass in WithAssumeRoleCredentialOptions to your config, create an new sts client internally and assign it a new config options that disable fips. Something like this:

package main

import (
    "context"
    "fmt"
    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/credentials/stscreds"
    "github.com/aws/aws-sdk-go-v2/service/sts"
    "os"
)

func main() {
    ctx := context.Background()
    os.Setenv("AWS_USE_FIPS_ENDPOINT", "true")
    os.Setenv("AWS_ENDPOINT_URL_STS", "https://sts.ca-central-1.amazonaws.com/")
    os.Setenv("AWS_REGION", "ca-central-1")
    os.Setenv("AWS_PROFILE", "assume-role")

    cfg, err := config.LoadDefaultConfig(ctx,
        config.WithRegion("ca-central-1"),
        config.WithAssumeRoleCredentialOptions(func(o *stscreds.AssumeRoleOptions) {
            secondCfg, err := config.LoadDefaultConfig(
                context.TODO(),
                config.WithRegion("ca-central-1"),
                config.WithClientLogMode(aws.LogRequestWithBody),
                config.WithUseFIPSEndpoint(aws.FIPSEndpointStateDisabled),
            )
            if err != nil {
                panic(err)
            }
            o.Client = sts.NewFromConfig(secondCfg)
        }),
    )
    if err != nil {
        panic(err)
    }

    _, err = cfg.Credentials.Retrieve(ctx)
    if err != nil {
        panic(err)
    }

    fmt.Println("Success.")
}

let me know if this helps.

Thanks, Ran~

github-actions[bot] commented 2 days ago

This issue has not received a response in 1 week. If you want to keep this issue open, please just leave a comment below and auto-close will be canceled.

tmccombs commented 2 days ago

Please keep open

RanVaknin commented 1 day ago

Hi @tmccombs ,

Can you please elaborate on why this needs to be kept open? Did the workaround I provided not work for you?

Thanks, Ran~

gdavison commented 8 hours ago

Hi @RanVaknin. I haven't had a chance to check this out.

I assume that @tmccombs has asked to keep this open because this issue relates to an issue that he submitted in https://github.com/hashicorp/terraform-provider-aws

tmccombs commented 7 hours ago

Ugh, I wrote a response, and it appears to have been lost somehow.

Anyway, yes, an application could technically work around this, but doing so is rather complex. Consider an application where credentials could come from multiple sources, such as terraform. For this workaround, the application would need to look at the environment variables, and configuration files that the SDK usually looks at, to figure out if it should disable UseFips because an endpoint is specified. And in your example the region is a constant. What if the region comes from the credential source.

Also, in my opinion it would be better for this to be implemented once in the SDK, rather than every application that uses the SDK having to solve it separately, possibly in inconsistent ways.