Skip to content

Commit

Permalink
Merge pull request #341 from hashicorp/logging
Browse files Browse the repository at this point in the history
Adds custom logging using `tflog` and removes sensitive fields from HTTP requests and responses
  • Loading branch information
gdavison authored Jan 27, 2023
2 parents 84c1f47 + ea19859 commit 950aa16
Show file tree
Hide file tree
Showing 35 changed files with 2,552 additions and 980 deletions.
36 changes: 4 additions & 32 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,9 @@ jobs:
steps:
- uses: actions/checkout@v3

- id: go-version
uses: juliangruber/read-file-action@v1
with:
path: ./.go-version

- uses: actions/setup-go@v3
with:
# TODO: Replace with go-version-from-file when it is supported
# https://github.com/actions/setup-go/pull/62
go-version: ${{ steps.go-version.outputs.content }}
go-version-file: ./go.mod

- name: go mod
run: |
Expand All @@ -31,16 +24,9 @@ jobs:
steps:
- uses: actions/checkout@v3

- id: go-version
uses: juliangruber/read-file-action@v1
with:
path: ./.go-version

- uses: actions/setup-go@v3
with:
# TODO: Replace with go-version-from-file when it is supported
# https://github.com/actions/setup-go/pull/62
go-version: ${{ steps.go-version.outputs.content }}
go-version-file: ./go.mod

- run: |
go test ./...
Expand All @@ -51,16 +37,9 @@ jobs:
steps:
- uses: actions/checkout@v3

- id: go-version
uses: juliangruber/read-file-action@v1
with:
path: ./.go-version

- uses: actions/setup-go@v3
with:
# TODO: Replace with go-version-from-file when it is supported
# https://github.com/actions/setup-go/pull/62
go-version: ${{ steps.go-version.outputs.content }}
go-version-file: ./go.mod

- run: cd tools && go install github.com/golangci/golangci-lint/cmd/golangci-lint

Expand All @@ -73,16 +52,9 @@ jobs:
steps:
- uses: actions/checkout@v3

- id: go-version
uses: juliangruber/read-file-action@v1
with:
path: ./.go-version

- uses: actions/setup-go@v3
with:
# TODO: Replace with go-version-from-file when it is supported
# https://github.com/actions/setup-go/pull/62
go-version: ${{ steps.go-version.outputs.content }}
go-version-file: ./go.mod

- run: cd tools && go install github.com/pavius/impi/cmd/impi

Expand Down
1 change: 1 addition & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@ linters-settings:
mnd:
ignored-functions:
- strings.SplitN
- strings.SplitAfterN
13 changes: 12 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
<!-- markdownlint-disable single-title -->
# v2.0.0 (Unreleased)

BREAKING CHANGES

* Adds `context.Context` return value to `GetAwsConfig` with configured logger. Adds `context.Context` parameter to `awsbasev1.GetSession`. ([#341](https://github.com/hashicorp/aws-sdk-go-base/pull/341))

BUG FIXES

* Scrubs sensitive values from HTTP request and response logs. ([#341](https://github.com/hashicorp/aws-sdk-go-base/pull/341))

ENHANCEMENTS

* Uses structured logging. ([#341](https://github.com/hashicorp/aws-sdk-go-base/pull/341))

# v2.0.0-beta.21 (2023-01-13)

ENHANCEMENTS

* Adds support for a congfigurable HTTP client. ([#340](https://github.com/hashicorp/aws-sdk-go-base/pull/340))


# v2.0.0-beta.20 (2022-11-22)

ENHANCEMENTS
Expand Down
79 changes: 55 additions & 24 deletions aws_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,47 @@ import (
"github.com/hashicorp/aws-sdk-go-base/v2/internal/awsconfig"
"github.com/hashicorp/aws-sdk-go-base/v2/internal/constants"
"github.com/hashicorp/aws-sdk-go-base/v2/internal/endpoints"
"github.com/hashicorp/aws-sdk-go-base/v2/logging"
"github.com/hashicorp/terraform-plugin-log/tflog"
)

func GetAwsConfig(ctx context.Context, c *Config) (aws.Config, error) {
const loggerName string = "aws-base"

func configCommonLogging(ctx context.Context) context.Context {
// Catch as last resort, but prefer the custom masking in the request-response logging
return tflog.MaskAllFieldValuesRegexes(ctx, logging.UniqueIDRegex)
}

func GetAwsConfig(ctx context.Context, c *Config) (context.Context, aws.Config, error) {
ctx = configCommonLogging(ctx)

baseCtx, logger := logging.New(ctx, loggerName)
baseCtx = logging.RegisterLogger(baseCtx, logger)

if metadataUrl := os.Getenv("AWS_METADATA_URL"); metadataUrl != "" {
log.Println(`[WARN] The environment variable "AWS_METADATA_URL" is deprecated. Use "AWS_EC2_METADATA_SERVICE_ENDPOINT" instead.`)
logger.Warn(baseCtx, `The environment variable "AWS_METADATA_URL" is deprecated. Use "AWS_EC2_METADATA_SERVICE_ENDPOINT" instead.`)
if ec2MetadataServiceEndpoint := os.Getenv("AWS_EC2_METADATA_SERVICE_ENDPOINT"); ec2MetadataServiceEndpoint != "" {
if ec2MetadataServiceEndpoint != metadataUrl {
log.Printf(`[WARN] The environment variable "AWS_EC2_METADATA_SERVICE_ENDPOINT" is already set to %q. Ignoring "AWS_METADATA_URL".`, ec2MetadataServiceEndpoint)
logger.Warn(baseCtx, fmt.Sprintf(`[WARN] The environment variable "AWS_EC2_METADATA_SERVICE_ENDPOINT" is already set to %q. Ignoring "AWS_METADATA_URL".`, ec2MetadataServiceEndpoint))
}
} else {
log.Printf(`[WARN] Setting "AWS_EC2_METADATA_SERVICE_ENDPOINT" to %q.`, metadataUrl)
logger.Warn(baseCtx, fmt.Sprintf(`[WARN] Setting "AWS_EC2_METADATA_SERVICE_ENDPOINT" to %q.`, metadataUrl))
os.Setenv("AWS_EC2_METADATA_SERVICE_ENDPOINT", metadataUrl)
}
}

credentialsProvider, initialSource, err := getCredentialsProvider(ctx, c)
credentialsProvider, initialSource, err := getCredentialsProvider(baseCtx, c)
if err != nil {
return aws.Config{}, err
return ctx, aws.Config{}, err
}
creds, _ := credentialsProvider.Retrieve(ctx)
log.Printf("[INFO] Retrieved credentials from %q", creds.Source)
creds, _ := credentialsProvider.Retrieve(baseCtx)
logger.Info(baseCtx, "Retrieved credentials", map[string]any{
"tf_aws.credentials_source": creds.Source,
})

loadOptions, err := commonLoadOptions(c)
loadOptions, err := commonLoadOptions(baseCtx, c)
if err != nil {
return aws.Config{}, err
return ctx, aws.Config{}, err
}
loadOptions = append(
loadOptions,
Expand All @@ -56,20 +72,20 @@ func GetAwsConfig(ctx context.Context, c *Config) (aws.Config, error) {
config.WithEC2IMDSRegion(),
)
}
awsConfig, err := config.LoadDefaultConfig(ctx, loadOptions...)
awsConfig, err := config.LoadDefaultConfig(baseCtx, loadOptions...)
if err != nil {
return awsConfig, fmt.Errorf("loading configuration: %w", err)
return ctx, awsConfig, fmt.Errorf("loading configuration: %w", err)
}

resolveRetryer(ctx, &awsConfig)
resolveRetryer(baseCtx, &awsConfig)

if !c.SkipCredsValidation {
if _, _, err := getAccountIDAndPartitionFromSTSGetCallerIdentity(ctx, stsClient(awsConfig, c)); err != nil {
return awsConfig, fmt.Errorf("error validating provider credentials: %w", err)
if _, _, err := getAccountIDAndPartitionFromSTSGetCallerIdentity(baseCtx, stsClient(baseCtx, awsConfig, c)); err != nil {
return ctx, awsConfig, fmt.Errorf("error validating provider credentials: %w", err)
}
}

return awsConfig, nil
return ctx, awsConfig, nil
}

// Adapted from the per-service-client `resolveRetryer()` functions in the AWS SDK for Go v2
Expand Down Expand Up @@ -103,7 +119,8 @@ func (r *networkErrorShortcutter) RetryDelay(attempt int, err error) (time.Durat
if errors.As(err, &netOpErr) {
// It's disappointing that we have to do string matching here, rather than being able to using `errors.Is()` or even strings exported by the Go `net` package
if strings.Contains(netOpErr.Error(), "no such host") || strings.Contains(netOpErr.Error(), "connection refused") {
log.Printf("[WARN] Disabling retries after next request due to networking issue: %s", err)
// TODO: figure out how to get correct logger here
log.Printf("[WARN] Disabling retries after next request due to networking error: %s", err)
return 0, &retry.MaxAttemptsError{
Attempt: attempt,
Err: err,
Expand All @@ -116,11 +133,14 @@ func (r *networkErrorShortcutter) RetryDelay(attempt int, err error) (time.Durat
}

func GetAwsAccountIDAndPartition(ctx context.Context, awsConfig aws.Config, c *Config) (string, string, error) {
ctx, logger := logging.New(ctx, loggerName)
ctx = logging.RegisterLogger(ctx, logger)

if !c.SkipCredsValidation {
stsClient := stsClient(awsConfig, c)
stsClient := stsClient(ctx, awsConfig, c)
accountID, partition, err := getAccountIDAndPartitionFromSTSGetCallerIdentity(ctx, stsClient)
if err != nil {
return "", "", fmt.Errorf("error validating provider credentials: %w", err)
return "", "", fmt.Errorf("validating provider credentials: %w", err)
}

return accountID, partition, nil
Expand All @@ -132,8 +152,8 @@ func GetAwsAccountIDAndPartition(ctx context.Context, awsConfig aws.Config, c *C
credentialsProviderName = credentialsValue.Source
}

iamClient := iamClient(awsConfig, c)
stsClient := stsClient(awsConfig, c)
iamClient := iamClient(ctx, awsConfig, c)
stsClient := stsClient(ctx, awsConfig, c)
accountID, partition, err := getAccountIDAndPartition(ctx, iamClient, stsClient, credentialsProviderName)

if err == nil {
Expand All @@ -149,7 +169,9 @@ func GetAwsAccountIDAndPartition(ctx context.Context, awsConfig aws.Config, c *C
return "", endpoints.PartitionForRegion(awsConfig.Region), nil
}

func commonLoadOptions(c *Config) ([]func(*config.LoadOptions) error, error) {
func commonLoadOptions(ctx context.Context, c *Config) ([]func(*config.LoadOptions) error, error) {
logger := logging.RetrieveLogger(ctx)

var err error
var httpClient config.HTTPClient

Expand Down Expand Up @@ -180,10 +202,19 @@ func commonLoadOptions(c *Config) ([]func(*config.LoadOptions) error, error) {
})

if v := os.Getenv(constants.AppendUserAgentEnvVar); v != "" {
log.Printf("[DEBUG] Using additional User-Agent Info: %s", v)
logger.Debug(ctx, "Adding User-Agent info", map[string]any{
"source": fmt.Sprintf("envvar(%q)", constants.AppendUserAgentEnvVar),
"value": v,
})
apiOptions = append(apiOptions, awsmiddleware.AddUserAgentKey(v))
}

if !c.SuppressDebugLog {
apiOptions = append(apiOptions, func(stack *middleware.Stack) error {
return stack.Deserialize.Add(&requestResponseLogger{}, middleware.After)
})
}

loadOptions := []func(*config.LoadOptions) error{
config.WithRegion(c.Region),
config.WithHTTPClient(httpClient),
Expand All @@ -201,7 +232,7 @@ func commonLoadOptions(c *Config) ([]func(*config.LoadOptions) error, error) {
if !c.SuppressDebugLog {
loadOptions = append(
loadOptions,
config.WithClientLogMode(aws.LogRequestWithBody|aws.LogResponseWithBody|aws.LogRetries),
config.WithClientLogMode(aws.LogDeprecatedUsage|aws.LogRetries),
config.WithLogger(debugLogger{}),
)
}
Expand Down
Loading

0 comments on commit 950aa16

Please sign in to comment.