Skip to content

Commit

Permalink
Merge pull request #81 from hashicorp/v2-add-proxy-config
Browse files Browse the repository at this point in the history
V2: Add proxy config
  • Loading branch information
gdavison authored Sep 27, 2021
2 parents 36bccfc + b46d090 commit c05b3ca
Show file tree
Hide file tree
Showing 10 changed files with 218 additions and 135 deletions.
25 changes: 12 additions & 13 deletions aws_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@ package awsbase

import (
"context"
"crypto/tls"
"errors"
"fmt"
"log"
"net"
"net/http"
"os"
"strings"
"time"
Expand All @@ -22,7 +20,7 @@ import (
"github.com/aws/smithy-go/middleware"
"github.com/hashicorp/aws-sdk-go-base/v2/internal/constants"
"github.com/hashicorp/aws-sdk-go-base/v2/internal/endpoints"
"github.com/hashicorp/go-cleanhttp"
"github.com/hashicorp/aws-sdk-go-base/v2/internal/httpclient"
)

func GetAwsConfig(ctx context.Context, c *Config) (aws.Config, error) {
Expand All @@ -40,8 +38,12 @@ func GetAwsConfig(ctx context.Context, c *Config) (aws.Config, error) {
Retryer: retryer,
}

loadOptions := append(
commonLoadOptions(c),
loadOptions, err := commonLoadOptions(c)
if err != nil {
return aws.Config{}, err
}
loadOptions = append(
loadOptions,
config.WithCredentialsProvider(credentialsProvider),
config.WithRetryer(func() aws.Retryer {
return retryer
Expand Down Expand Up @@ -119,13 +121,10 @@ func GetAwsAccountIDAndPartition(ctx context.Context, awsConfig aws.Config, skip
return "", endpoints.PartitionForRegion(awsConfig.Region), nil
}

func commonLoadOptions(c *Config) []func(*config.LoadOptions) error {
httpClient := cleanhttp.DefaultClient()
if c.Insecure {
transport := httpClient.Transport.(*http.Transport)
transport.TLSClientConfig = &tls.Config{
InsecureSkipVerify: true,
}
func commonLoadOptions(c *Config) ([]func(*config.LoadOptions) error, error) {
httpClient, err := httpclient.DefaultHttpClient(c)
if err != nil {
return nil, err
}

apiOptions := make([]func(*middleware.Stack) error, 0)
Expand Down Expand Up @@ -171,5 +170,5 @@ func commonLoadOptions(c *Config) []func(*config.LoadOptions) error {
os.Setenv("AWS_EC2_METADATA_DISABLED", "true")
}

return loadOptions
return loadOptions, nil
}
50 changes: 11 additions & 39 deletions config.go
Original file line number Diff line number Diff line change
@@ -1,44 +1,16 @@
package awsbase

type Config struct {
AccessKey string
APNInfo *APNInfo
AssumeRole *AssumeRole
CallerDocumentationURL string
CallerName string
DebugLogging bool
IamEndpoint string
Insecure bool
MaxRetries int
Profile string
Region string
SecretKey string
SharedCredentialsFiles []string
SharedConfigFiles []string
SkipCredsValidation bool
SkipMetadataApiCheck bool
StsEndpoint string
Token string
}
import (
"github.com/hashicorp/aws-sdk-go-base/v2/internal/config"
)

type APNInfo struct {
PartnerName string
Products []APNProduct
}
// Config, APNInfo, APNProduct, and AssumeRole are aliased to an internal package to break a dependency cycle
// in internal/httpclient.

type APNProduct struct {
Name string
Version string
Comment string
}
type Config = config.Config

type AssumeRole struct {
RoleARN string
DurationSeconds int
ExternalID string
Policy string
PolicyARNs []string
SessionName string
Tags map[string]string
TransitiveTagKeys []string
}
type APNInfo = config.APNInfo

type APNProduct = config.APNProduct

type AssumeRole = config.AssumeRole
8 changes: 6 additions & 2 deletions credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@ import (
)

func getCredentialsProvider(ctx context.Context, c *Config) (aws.CredentialsProvider, error) {
loadOptions := append(
commonLoadOptions(c),
loadOptions, err := commonLoadOptions(c)
if err != nil {
return nil, err
}
loadOptions = append(
loadOptions,
config.WithSharedConfigProfile(c.Profile),
// Bypass retries when validating authentication
config.WithRetryer(func() aws.Retryer {
Expand Down
59 changes: 4 additions & 55 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,75 +2,24 @@ package awsbase

import (
"errors"
"fmt"

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

// CannotAssumeRoleError occurs when AssumeRole cannot complete.
type CannotAssumeRoleError struct {
Config *Config
Err error
}

func (e CannotAssumeRoleError) Error() string {
if e.Config == nil || e.Config.AssumeRole == nil {
return fmt.Sprintf("cannot assume role: %s", e.Err)
}

return fmt.Sprintf(`IAM Role (%s) cannot be assumed.
There are a number of possible causes of this - the most common are:
* The credentials used in order to assume the role are invalid
* The credentials do not have appropriate permission to assume the role
* The role ARN is not valid
Error: %s
`, e.Config.AssumeRole.RoleARN, e.Err)
}

func (e CannotAssumeRoleError) Unwrap() error {
return e.Err
}
type CannotAssumeRoleError = config.CannotAssumeRoleError

// IsCannotAssumeRoleError returns true if the error contains the CannotAssumeRoleError type.
func IsCannotAssumeRoleError(err error) bool {
var e CannotAssumeRoleError
return errors.As(err, &e)
}

func (c *Config) NewCannotAssumeRoleError(err error) CannotAssumeRoleError {
return CannotAssumeRoleError{Config: c, Err: err}
}

// NoValidCredentialSourcesError occurs when all credential lookup methods have been exhausted without results.
type NoValidCredentialSourcesError struct {
Config *Config
Err error
}

func (e NoValidCredentialSourcesError) Error() string {
if e.Config == nil {
return fmt.Sprintf("no valid credential sources found: %s", e.Err)
}

return fmt.Sprintf(`no valid credential sources for %[1]s found.
Please see %[2]s
for more information about providing credentials.
Error: %[3]s
`, e.Config.CallerName, e.Config.CallerDocumentationURL, e.Err)
}

func (e NoValidCredentialSourcesError) Unwrap() error {
return e.Err
}
type NoValidCredentialSourcesError = config.NoValidCredentialSourcesError

// IsNoValidCredentialSourcesError returns true if the error contains the NoValidCredentialSourcesError type.
func IsNoValidCredentialSourcesError(err error) bool {
var e NoValidCredentialSourcesError
return errors.As(err, &e)
}

func (c *Config) NewNoValidCredentialSourcesError(err error) NoValidCredentialSourcesError {
return NoValidCredentialSourcesError{Config: c, Err: err}
}
29 changes: 29 additions & 0 deletions internal/config/apn_info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package config

import (
smithyhttp "github.com/aws/smithy-go/transport/http"
)

// Builds the user-agent string for APN
func (apn APNInfo) BuildUserAgentString() string {
builder := smithyhttp.NewUserAgentBuilder()
builder.AddKeyValue("APN", "1.0")
builder.AddKeyValue(apn.PartnerName, "1.0")
for _, p := range apn.Products {
p.buildUserAgentPart(builder)
}
return builder.Build()
}

func (p APNProduct) buildUserAgentPart(b *smithyhttp.UserAgentBuilder) {
if p.Name != "" {
if p.Version != "" {
b.AddKeyValue(p.Name, p.Version)
} else {
b.AddKey(p.Name)
}
}
if p.Comment != "" {
b.AddKey("(" + p.Comment + ")")
}
}
45 changes: 45 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package config

type Config struct {
AccessKey string
APNInfo *APNInfo
AssumeRole *AssumeRole
CallerDocumentationURL string
CallerName string
DebugLogging bool
HTTPProxy string
IamEndpoint string
Insecure bool
MaxRetries int
Profile string
Region string
SecretKey string
SharedCredentialsFiles []string
SharedConfigFiles []string
SkipCredsValidation bool
SkipMetadataApiCheck bool
StsEndpoint string
Token string
}

type APNInfo struct {
PartnerName string
Products []APNProduct
}

type APNProduct struct {
Name string
Version string
Comment string
}

type AssumeRole struct {
RoleARN string
DurationSeconds int
ExternalID string
Policy string
PolicyARNs []string
SessionName string
Tags map[string]string
TransitiveTagKeys []string
}
63 changes: 63 additions & 0 deletions internal/config/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package config

import (
"fmt"
)

// CannotAssumeRoleError occurs when AssumeRole cannot complete.
type CannotAssumeRoleError struct {
Config *Config
Err error
}

func (e CannotAssumeRoleError) Error() string {
if e.Config == nil || e.Config.AssumeRole == nil {
return fmt.Sprintf("cannot assume role: %s", e.Err)
}

return fmt.Sprintf(`IAM Role (%s) cannot be assumed.
There are a number of possible causes of this - the most common are:
* The credentials used in order to assume the role are invalid
* The credentials do not have appropriate permission to assume the role
* The role ARN is not valid
Error: %s
`, e.Config.AssumeRole.RoleARN, e.Err)
}

func (e CannotAssumeRoleError) Unwrap() error {
return e.Err
}

func (c *Config) NewCannotAssumeRoleError(err error) CannotAssumeRoleError {
return CannotAssumeRoleError{Config: c, Err: err}
}

// NoValidCredentialSourcesError occurs when all credential lookup methods have been exhausted without results.
type NoValidCredentialSourcesError struct {
Config *Config
Err error
}

func (e NoValidCredentialSourcesError) Error() string {
if e.Config == nil {
return fmt.Sprintf("no valid credential sources found: %s", e.Err)
}

return fmt.Sprintf(`no valid credential sources for %[1]s found.
Please see %[2]s
for more information about providing credentials.
Error: %[3]s
`, e.Config.CallerName, e.Config.CallerDocumentationURL, e.Err)
}

func (e NoValidCredentialSourcesError) Unwrap() error {
return e.Err
}

func (c *Config) NewNoValidCredentialSourcesError(err error) NoValidCredentialSourcesError {
return NoValidCredentialSourcesError{Config: c, Err: err}
}
38 changes: 38 additions & 0 deletions internal/httpclient/http_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package httpclient

import (
"crypto/tls"
"fmt"
"net/http"
"net/url"

"github.com/hashicorp/aws-sdk-go-base/v2/internal/config"
"github.com/hashicorp/go-cleanhttp"
)

func DefaultHttpClient(c *config.Config) (*http.Client, error) {
httpClient := cleanhttp.DefaultClient()
transport := httpClient.Transport.(*http.Transport)

tlsConfig := transport.TLSClientConfig
if tlsConfig == nil {
tlsConfig = &tls.Config{}
transport.TLSClientConfig = tlsConfig
}
tlsConfig.MinVersion = tls.VersionTLS12

if c.Insecure {
tlsConfig.InsecureSkipVerify = true
}

if c.HTTPProxy != "" {
proxyUrl, err := url.Parse(c.HTTPProxy)
if err != nil {
return nil, fmt.Errorf("error parsing HTTP proxy URL: %w", err)
}

transport.Proxy = http.ProxyURL(proxyUrl)
}

return httpClient, nil
}
Loading

0 comments on commit c05b3ca

Please sign in to comment.