Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds full proxy configuration #775

Merged
merged 16 commits into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions .semgrep/imports.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ rules:
paths:
exclude:
- awsv1shim
- tfawserr
- awsmocks
patterns:
- pattern: |
import ("$X")
- focus-metavariable: $X
- metavariable-regex:
metavariable: "$X"
regex: '^"github.com/aws/aws-sdk-go/.+"$'
regex: 'github.com/aws/aws-sdk-go/.+'
severity: ERROR

- id: no-sdkv2-imports-in-awsv1shim
Expand All @@ -24,15 +24,17 @@ rules:
paths:
include:
- awsv1shim
- tfawserr
patterns:
- pattern: |
import ("$X")
- focus-metavariable: $X
- metavariable-regex:
metavariable: "$X"
regex: '^"github.com/aws/aws-sdk-go-v2/.+"$'
regex: 'github.com/aws/aws-sdk-go-v2/.+'
- pattern-not: |
import ("github.com/aws/aws-sdk-go-v2/aws/transport/http")
- pattern-not: |
import ("github.com/aws/aws-sdk-go-v2/config")
- pattern-not: |
import ("github.com/aws/aws-sdk-go-v2/aws/retry")
severity: ERROR
Empty file added .semgrepignore
Empty file.
5 changes: 5 additions & 0 deletions aws_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ func GetAwsConfig(ctx context.Context, c *Config) (context.Context, aws.Config,
}
}

c.ValidateProxySettings(&diags)
if diags.HasError() {
return ctx, aws.Config{}, diags
}

logger.Debug(baseCtx, "Resolving credentials provider")
credentialsProvider, initialSource, d := getCredentialsProvider(baseCtx, c)
if d.HasError() {
Expand Down
2 changes: 1 addition & 1 deletion aws_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1239,7 +1239,7 @@ func testUserAgentProducts(t *testing.T, testCase test.UserAgentTestCase) {
}
}

var errCancelOperation = fmt.Errorf("Test: Cancelling request")
var errCancelOperation = errors.New("Test: Cancelling request")

// cancelRequestMiddleware creates a Smithy middleware that intercepts the request before sending and cancels it
func cancelRequestMiddleware(t *testing.T, id string, f func(t *testing.T, request *smithyhttp.Request)) middleware.FinalizeMiddleware {
Expand Down
7 changes: 7 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,10 @@ func EC2MetadataEndpointMode_Values() []string {
EC2MetadataEndpointModeIPv6,
}
}

// type ProxyMode int

gdavison marked this conversation as resolved.
Show resolved Hide resolved
const (
HTTPProxyModeLegacy = config.HTTPProxyModeLegacy
HTTPProxyModeSeparate = config.HTTPProxyModeSeparate
)
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ require (
go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws v0.45.0
go.opentelemetry.io/otel v1.19.0
golang.org/x/exp v0.0.0-20230905200255-921286631fa9
golang.org/x/net v0.17.0
golang.org/x/text v0.14.0
)

Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1
go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand Down
16 changes: 16 additions & 0 deletions http_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package awsbase

import (
"net/http"
"testing"

"github.com/hashicorp/aws-sdk-go-base/v2/internal/config"
Expand Down Expand Up @@ -33,3 +34,18 @@ func TestHTTPClientConfiguration_insecureHTTPS(t *testing.T) {

test.HTTPClientConfigurationTest_insecureHTTPS(t, transport)
}

func TestHTTPClientConfiguration_proxy(t *testing.T) {
test.HTTPClientConfigurationTest_proxy(t, transport)
}

func transport(t *testing.T, config *config.Config) *http.Transport {
t.Helper()

client, err := defaultHttpClient(config)
if err != nil {
t.Fatalf("creating client: %s", err)
}

return client.GetTransport()
}
103 changes: 96 additions & 7 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,17 @@ import (
"github.com/aws/aws-sdk-go-v2/aws"
awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http"
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
"github.com/hashicorp/aws-sdk-go-base/v2/diag"
"github.com/hashicorp/aws-sdk-go-base/v2/internal/expand"
"github.com/hashicorp/aws-sdk-go-base/v2/logging"
"golang.org/x/net/http/httpproxy"
)

type ProxyMode int

const (
HTTPProxyModeLegacy ProxyMode = iota
HTTPProxyModeSeparate
)

type Config struct {
Expand All @@ -33,12 +42,15 @@ type Config struct {
EC2MetadataServiceEndpointMode string
ForbiddenAccountIds []string
HTTPClient *http.Client
HTTPProxy string
HTTPProxy *string
HTTPSProxy *string
IamEndpoint string
Insecure bool
Logger logging.Logger
MaxRetries int
NoProxy string
Profile string
HTTPProxyMode ProxyMode
Region string
RetryMode aws.RetryMode
SecretKey string
Expand Down Expand Up @@ -88,11 +100,18 @@ func (c Config) CustomCABundleReader() (*bytes.Reader, error) {
// The returned options function is called on both AWS SDKv1 and v2 default HTTP clients.
func (c Config) HTTPTransportOptions() (func(*http.Transport), error) {
var err error
var proxyUrl *url.URL
if c.HTTPProxy != "" {
proxyUrl, err = url.Parse(c.HTTPProxy)
var httpProxyUrl *url.URL
if c.HTTPProxy != nil {
httpProxyUrl, err = url.Parse(aws.ToString(c.HTTPProxy))
if err != nil {
return nil, fmt.Errorf("error parsing HTTP proxy URL: %w", err)
return nil, fmt.Errorf("parsing HTTP proxy URL: %w", err)
}
}
var httpsProxyUrl *url.URL
if c.HTTPSProxy != nil {
httpsProxyUrl, err = url.Parse(aws.ToString(c.HTTPSProxy))
if err != nil {
return nil, fmt.Errorf("parsing HTTPS proxy URL: %w", err)
}
}

Expand All @@ -111,14 +130,84 @@ func (c Config) HTTPTransportOptions() (func(*http.Transport), error) {
tr.TLSClientConfig.InsecureSkipVerify = true
}

if proxyUrl != nil {
tr.Proxy = http.ProxyURL(proxyUrl)
proxyConfig := httpproxy.FromEnvironment()
if httpProxyUrl != nil {
proxyConfig.HTTPProxy = httpProxyUrl.String()
if c.HTTPProxyMode == HTTPProxyModeLegacy && proxyConfig.HTTPSProxy == "" {
proxyConfig.HTTPSProxy = httpProxyUrl.String()
}
}
if httpsProxyUrl != nil {
proxyConfig.HTTPSProxy = httpsProxyUrl.String()
}
if c.NoProxy != "" {
proxyConfig.NoProxy = c.NoProxy
}
tr.Proxy = func(req *http.Request) (*url.URL, error) {
return proxyConfig.ProxyFunc()(req.URL)
}
}

return opts, nil
}

func (c Config) ValidateProxySettings(diags *diag.Diagnostics) {
if c.HTTPProxy != nil {
if _, err := url.Parse(aws.ToString(c.HTTPProxy)); err != nil {
*diags = diags.AddError(
"Invalid HTTP Proxy",
fmt.Sprintf("Unable to parse URL: %s", err),
)
}
}

if c.HTTPSProxy != nil {
if _, err := url.Parse(aws.ToString(c.HTTPSProxy)); err != nil {
*diags = diags.AddError(
"Invalid HTTPS Proxy",
fmt.Sprintf("Unable to parse URL: %s", err),
)
}
}

if c.HTTPProxy != nil && *c.HTTPProxy != "" && c.HTTPSProxy == nil && os.Getenv("HTTPS_PROXY") == "" && os.Getenv("https_proxy") == "" {
if c.HTTPProxyMode == HTTPProxyModeLegacy {
*diags = diags.Append(
missingHttpsProxyLegacyWarningDiag(aws.ToString(c.HTTPProxy)),
)
} else {
*diags = diags.Append(
missingHttpsProxyWarningDiag(),
)
}
}
}

const (
missingHttpsProxyWarningSummary = "Missing HTTPS Proxy"
missingHttpsProxyDetailProblem = "An HTTP proxy was set but no HTTPS proxy was."
missingHttpsProxyDetailResolution = "To specify no proxy for HTTPS, set the HTTPS to an empty string."
)

func missingHttpsProxyLegacyWarningDiag(s string) diag.Diagnostic {
return diag.NewWarningDiagnostic(
missingHttpsProxyWarningSummary,
fmt.Sprintf(
missingHttpsProxyDetailProblem+" Using HTTP proxy %q for HTTPS requests. This behavior may change in future versions.\n\n"+
missingHttpsProxyDetailResolution,
s,
),
)
}

func missingHttpsProxyWarningDiag() diag.Diagnostic {
return diag.NewWarningDiagnostic(
missingHttpsProxyWarningSummary,
missingHttpsProxyDetailProblem+"\n\n"+
missingHttpsProxyDetailResolution,
)
}

func (c Config) ResolveSharedConfigFiles() ([]string, error) {
v, err := expand.FilePaths(c.SharedConfigFiles)
if err != nil {
Expand Down
Loading